aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBastian Hecht <hechtb@googlemail.com>2012-03-18 10:13:20 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2012-03-26 19:53:34 -0400
commitcfe781946dac7f5ff42e23cd7054c75e7201fbdc (patch)
tree75d102cf44ab8d2fe190a67594fee88790005b88
parent42d7fbe223ab878b23de9e3b0166f8cd665a2aa5 (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>
-rw-r--r--drivers/mtd/nand/sh_flctl.c51
-rw-r--r--include/linux/mtd/sh_flctl.h3
2 files changed, 45 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
675read_normal_exit: 678read_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);
684runtime_exit:
685 pm_runtime_put_sync(&flctl->pdev->dev);
681 return; 686 return;
682} 687}
683 688
684static void flctl_select_chip(struct mtd_info *mtd, int chipnr) 689static 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
890err: 920err_chip:
921 pm_runtime_disable(&pdev->dev);
922err_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;
diff --git a/include/linux/mtd/sh_flctl.h b/include/linux/mtd/sh_flctl.h
index 8bcf299cb9bf..a38e1fa8af01 100644
--- a/include/linux/mtd/sh_flctl.h
+++ b/include/linux/mtd/sh_flctl.h
@@ -23,6 +23,7 @@
23#include <linux/mtd/mtd.h> 23#include <linux/mtd/mtd.h>
24#include <linux/mtd/nand.h> 24#include <linux/mtd/nand.h>
25#include <linux/mtd/partitions.h> 25#include <linux/mtd/partitions.h>
26#include <linux/pm_qos.h>
26 27
27/* FLCTL registers */ 28/* FLCTL registers */
28#define FLCMNCR(f) (f->reg + 0x0) 29#define FLCMNCR(f) (f->reg + 0x0)
@@ -131,6 +132,7 @@ struct sh_flctl {
131 struct mtd_info mtd; 132 struct mtd_info mtd;
132 struct nand_chip chip; 133 struct nand_chip chip;
133 struct platform_device *pdev; 134 struct platform_device *pdev;
135 struct dev_pm_qos_request pm_qos;
134 void __iomem *reg; 136 void __iomem *reg;
135 137
136 uint8_t done_buff[2048 + 64]; /* max size 2048 + 64 */ 138 uint8_t done_buff[2048 + 64]; /* max size 2048 + 64 */
@@ -149,6 +151,7 @@ struct sh_flctl {
149 unsigned page_size:1; /* NAND page size (0 = 512, 1 = 2048) */ 151 unsigned page_size:1; /* NAND page size (0 = 512, 1 = 2048) */
150 unsigned hwecc:1; /* Hardware ECC (0 = disabled, 1 = enabled) */ 152 unsigned hwecc:1; /* Hardware ECC (0 = disabled, 1 = enabled) */
151 unsigned holden:1; /* Hardware has FLHOLDCR and HOLDEN is set */ 153 unsigned holden:1; /* Hardware has FLHOLDCR and HOLDEN is set */
154 unsigned qos_request:1; /* QoS request to prevent deep power shutdown */
152}; 155};
153 156
154struct sh_flctl_platform_data { 157struct sh_flctl_platform_data {