diff options
author | Bastian Hecht <hechtb@googlemail.com> | 2012-03-18 10:13:20 -0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2012-03-26 19:53:34 -0400 |
commit | cfe781946dac7f5ff42e23cd7054c75e7201fbdc (patch) | |
tree | 75d102cf44ab8d2fe190a67594fee88790005b88 /drivers/mtd | |
parent | 42d7fbe223ab878b23de9e3b0166f8cd665a2aa5 (diff) |
mtd: sh_flctl: Add power management with QoS request
Adds power management code with fine granularity. Every flash control
command is enclosed by runtime_put()/get()s. To make sure that no
overhead is generated by too frequent power state switches, a quality of
service request is issued.
Signed-off-by: Bastian Hecht <hechtb@gmail.com>
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/nand/sh_flctl.c | 51 |
1 files changed, 42 insertions, 9 deletions
diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index d0f1f3c13e76..2ee9a1b50a22 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/delay.h> | 26 | #include <linux/delay.h> |
27 | #include <linux/io.h> | 27 | #include <linux/io.h> |
28 | #include <linux/platform_device.h> | 28 | #include <linux/platform_device.h> |
29 | #include <linux/pm_runtime.h> | ||
29 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
30 | 31 | ||
31 | #include <linux/mtd/mtd.h> | 32 | #include <linux/mtd/mtd.h> |
@@ -515,6 +516,8 @@ static void flctl_cmdfunc(struct mtd_info *mtd, unsigned int command, | |||
515 | struct sh_flctl *flctl = mtd_to_flctl(mtd); | 516 | struct sh_flctl *flctl = mtd_to_flctl(mtd); |
516 | uint32_t read_cmd = 0; | 517 | uint32_t read_cmd = 0; |
517 | 518 | ||
519 | pm_runtime_get_sync(&flctl->pdev->dev); | ||
520 | |||
518 | flctl->read_bytes = 0; | 521 | flctl->read_bytes = 0; |
519 | if (command != NAND_CMD_PAGEPROG) | 522 | if (command != NAND_CMD_PAGEPROG) |
520 | flctl->index = 0; | 523 | flctl->index = 0; |
@@ -670,7 +673,7 @@ static void flctl_cmdfunc(struct mtd_info *mtd, unsigned int command, | |||
670 | default: | 673 | default: |
671 | break; | 674 | break; |
672 | } | 675 | } |
673 | return; | 676 | goto runtime_exit; |
674 | 677 | ||
675 | read_normal_exit: | 678 | read_normal_exit: |
676 | writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */ | 679 | writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */ |
@@ -678,23 +681,47 @@ read_normal_exit: | |||
678 | start_translation(flctl); | 681 | start_translation(flctl); |
679 | read_fiforeg(flctl, flctl->read_bytes, 0); | 682 | read_fiforeg(flctl, flctl->read_bytes, 0); |
680 | wait_completion(flctl); | 683 | wait_completion(flctl); |
684 | runtime_exit: | ||
685 | pm_runtime_put_sync(&flctl->pdev->dev); | ||
681 | return; | 686 | return; |
682 | } | 687 | } |
683 | 688 | ||
684 | static void flctl_select_chip(struct mtd_info *mtd, int chipnr) | 689 | static void flctl_select_chip(struct mtd_info *mtd, int chipnr) |
685 | { | 690 | { |
686 | struct sh_flctl *flctl = mtd_to_flctl(mtd); | 691 | struct sh_flctl *flctl = mtd_to_flctl(mtd); |
692 | int ret; | ||
687 | 693 | ||
688 | switch (chipnr) { | 694 | switch (chipnr) { |
689 | case -1: | 695 | case -1: |
690 | flctl->flcmncr_base &= ~CE0_ENABLE; | 696 | flctl->flcmncr_base &= ~CE0_ENABLE; |
697 | |||
698 | pm_runtime_get_sync(&flctl->pdev->dev); | ||
691 | writel(flctl->flcmncr_base, FLCMNCR(flctl)); | 699 | writel(flctl->flcmncr_base, FLCMNCR(flctl)); |
700 | |||
701 | if (flctl->qos_request) { | ||
702 | dev_pm_qos_remove_request(&flctl->pm_qos); | ||
703 | flctl->qos_request = 0; | ||
704 | } | ||
705 | |||
706 | pm_runtime_put_sync(&flctl->pdev->dev); | ||
692 | break; | 707 | break; |
693 | case 0: | 708 | case 0: |
694 | flctl->flcmncr_base |= CE0_ENABLE; | 709 | flctl->flcmncr_base |= CE0_ENABLE; |
695 | writel(flctl->flcmncr_base, FLCMNCR(flctl)); | 710 | |
696 | if (flctl->holden) | 711 | if (!flctl->qos_request) { |
712 | ret = dev_pm_qos_add_request(&flctl->pdev->dev, | ||
713 | &flctl->pm_qos, 100); | ||
714 | if (ret < 0) | ||
715 | dev_err(&flctl->pdev->dev, | ||
716 | "PM QoS request failed: %d\n", ret); | ||
717 | flctl->qos_request = 1; | ||
718 | } | ||
719 | |||
720 | if (flctl->holden) { | ||
721 | pm_runtime_get_sync(&flctl->pdev->dev); | ||
697 | writel(HOLDEN, FLHOLDCR(flctl)); | 722 | writel(HOLDEN, FLHOLDCR(flctl)); |
723 | pm_runtime_put_sync(&flctl->pdev->dev); | ||
724 | } | ||
698 | break; | 725 | break; |
699 | default: | 726 | default: |
700 | BUG(); | 727 | BUG(); |
@@ -835,13 +862,13 @@ static int __devinit flctl_probe(struct platform_device *pdev) | |||
835 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 862 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
836 | if (!res) { | 863 | if (!res) { |
837 | dev_err(&pdev->dev, "failed to get I/O memory\n"); | 864 | dev_err(&pdev->dev, "failed to get I/O memory\n"); |
838 | goto err; | 865 | goto err_iomap; |
839 | } | 866 | } |
840 | 867 | ||
841 | flctl->reg = ioremap(res->start, resource_size(res)); | 868 | flctl->reg = ioremap(res->start, resource_size(res)); |
842 | if (flctl->reg == NULL) { | 869 | if (flctl->reg == NULL) { |
843 | dev_err(&pdev->dev, "failed to remap I/O memory\n"); | 870 | dev_err(&pdev->dev, "failed to remap I/O memory\n"); |
844 | goto err; | 871 | goto err_iomap; |
845 | } | 872 | } |
846 | 873 | ||
847 | platform_set_drvdata(pdev, flctl); | 874 | platform_set_drvdata(pdev, flctl); |
@@ -871,23 +898,28 @@ static int __devinit flctl_probe(struct platform_device *pdev) | |||
871 | nand->read_word = flctl_read_word; | 898 | nand->read_word = flctl_read_word; |
872 | } | 899 | } |
873 | 900 | ||
901 | pm_runtime_enable(&pdev->dev); | ||
902 | pm_runtime_resume(&pdev->dev); | ||
903 | |||
874 | ret = nand_scan_ident(flctl_mtd, 1, NULL); | 904 | ret = nand_scan_ident(flctl_mtd, 1, NULL); |
875 | if (ret) | 905 | if (ret) |
876 | goto err; | 906 | goto err_chip; |
877 | 907 | ||
878 | ret = flctl_chip_init_tail(flctl_mtd); | 908 | ret = flctl_chip_init_tail(flctl_mtd); |
879 | if (ret) | 909 | if (ret) |
880 | goto err; | 910 | goto err_chip; |
881 | 911 | ||
882 | ret = nand_scan_tail(flctl_mtd); | 912 | ret = nand_scan_tail(flctl_mtd); |
883 | if (ret) | 913 | if (ret) |
884 | goto err; | 914 | goto err_chip; |
885 | 915 | ||
886 | mtd_device_register(flctl_mtd, pdata->parts, pdata->nr_parts); | 916 | mtd_device_register(flctl_mtd, pdata->parts, pdata->nr_parts); |
887 | 917 | ||
888 | return 0; | 918 | return 0; |
889 | 919 | ||
890 | err: | 920 | err_chip: |
921 | pm_runtime_disable(&pdev->dev); | ||
922 | err_iomap: | ||
891 | kfree(flctl); | 923 | kfree(flctl); |
892 | return ret; | 924 | return ret; |
893 | } | 925 | } |
@@ -897,6 +929,7 @@ static int __devexit flctl_remove(struct platform_device *pdev) | |||
897 | struct sh_flctl *flctl = platform_get_drvdata(pdev); | 929 | struct sh_flctl *flctl = platform_get_drvdata(pdev); |
898 | 930 | ||
899 | nand_release(&flctl->mtd); | 931 | nand_release(&flctl->mtd); |
932 | pm_runtime_disable(&pdev->dev); | ||
900 | kfree(flctl); | 933 | kfree(flctl); |
901 | 934 | ||
902 | return 0; | 935 | return 0; |