diff options
author | Jiri Pinkava <jiri.pinkava@vscht.cz> | 2011-04-13 05:59:30 -0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2011-05-24 20:53:10 -0400 |
commit | ac497c1602555c908c9738fa93b1145f431d1876 (patch) | |
tree | a1ab0f42276413e23c4b8ba96fa15d903d841f36 /drivers/mtd/nand | |
parent | c9ddab25d1b62baead4b0c5de562f1fce026dcfd (diff) |
mtd: nand: fix S3C NAND clock stop
Current implementation of s3c2410_nand_select_chip call
clk_disable every time when chip = -1 (de-select). This happend
multiple times even if chip was already de-selected. This causes
disabling clock even if they are already disabled and due to
nature of clock subsytem implementation this causes nand clock
to be disabled and newer enabled again.
Signed-off-by: Jiri Pinkava <jiri.pinkava@vscht.cz>
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd/nand')
-rw-r--r-- | drivers/mtd/nand/s3c2410.c | 59 |
1 files changed, 43 insertions, 16 deletions
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 33d832dddfdd..cea775aa9482 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c | |||
@@ -55,7 +55,7 @@ static int hardware_ecc = 0; | |||
55 | #endif | 55 | #endif |
56 | 56 | ||
57 | #ifdef CONFIG_MTD_NAND_S3C2410_CLKSTOP | 57 | #ifdef CONFIG_MTD_NAND_S3C2410_CLKSTOP |
58 | static int clock_stop = 1; | 58 | static const int clock_stop = 1; |
59 | #else | 59 | #else |
60 | static const int clock_stop = 0; | 60 | static const int clock_stop = 0; |
61 | #endif | 61 | #endif |
@@ -96,6 +96,12 @@ enum s3c_cpu_type { | |||
96 | TYPE_S3C2440, | 96 | TYPE_S3C2440, |
97 | }; | 97 | }; |
98 | 98 | ||
99 | enum s3c_nand_clk_state { | ||
100 | CLOCK_DISABLE = 0, | ||
101 | CLOCK_ENABLE, | ||
102 | CLOCK_SUSPEND, | ||
103 | }; | ||
104 | |||
99 | /* overview of the s3c2410 nand state */ | 105 | /* overview of the s3c2410 nand state */ |
100 | 106 | ||
101 | /** | 107 | /** |
@@ -111,6 +117,7 @@ enum s3c_cpu_type { | |||
111 | * @mtd_count: The number of MTDs created from this controller. | 117 | * @mtd_count: The number of MTDs created from this controller. |
112 | * @save_sel: The contents of @sel_reg to be saved over suspend. | 118 | * @save_sel: The contents of @sel_reg to be saved over suspend. |
113 | * @clk_rate: The clock rate from @clk. | 119 | * @clk_rate: The clock rate from @clk. |
120 | * @clk_state: The current clock state. | ||
114 | * @cpu_type: The exact type of this controller. | 121 | * @cpu_type: The exact type of this controller. |
115 | */ | 122 | */ |
116 | struct s3c2410_nand_info { | 123 | struct s3c2410_nand_info { |
@@ -129,6 +136,7 @@ struct s3c2410_nand_info { | |||
129 | int mtd_count; | 136 | int mtd_count; |
130 | unsigned long save_sel; | 137 | unsigned long save_sel; |
131 | unsigned long clk_rate; | 138 | unsigned long clk_rate; |
139 | enum s3c_nand_clk_state clk_state; | ||
132 | 140 | ||
133 | enum s3c_cpu_type cpu_type; | 141 | enum s3c_cpu_type cpu_type; |
134 | 142 | ||
@@ -159,11 +167,33 @@ static struct s3c2410_platform_nand *to_nand_plat(struct platform_device *dev) | |||
159 | return dev->dev.platform_data; | 167 | return dev->dev.platform_data; |
160 | } | 168 | } |
161 | 169 | ||
162 | static inline int allow_clk_stop(struct s3c2410_nand_info *info) | 170 | static inline int allow_clk_suspend(struct s3c2410_nand_info *info) |
163 | { | 171 | { |
164 | return clock_stop; | 172 | return clock_stop; |
165 | } | 173 | } |
166 | 174 | ||
175 | /** | ||
176 | * s3c2410_nand_clk_set_state - Enable, disable or suspend NAND clock. | ||
177 | * @info: The controller instance. | ||
178 | * @new_state: State to which clock should be set. | ||
179 | */ | ||
180 | static void s3c2410_nand_clk_set_state(struct s3c2410_nand_info *info, | ||
181 | enum s3c_nand_clk_state new_state) | ||
182 | { | ||
183 | if (!allow_clk_suspend(info) && new_state == CLOCK_SUSPEND) | ||
184 | return; | ||
185 | |||
186 | if (info->clk_state == CLOCK_ENABLE) { | ||
187 | if (new_state != CLOCK_ENABLE) | ||
188 | clk_disable(info->clk); | ||
189 | } else { | ||
190 | if (new_state == CLOCK_ENABLE) | ||
191 | clk_enable(info->clk); | ||
192 | } | ||
193 | |||
194 | info->clk_state = new_state; | ||
195 | } | ||
196 | |||
167 | /* timing calculations */ | 197 | /* timing calculations */ |
168 | 198 | ||
169 | #define NS_IN_KHZ 1000000 | 199 | #define NS_IN_KHZ 1000000 |
@@ -333,8 +363,8 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip) | |||
333 | nmtd = this->priv; | 363 | nmtd = this->priv; |
334 | info = nmtd->info; | 364 | info = nmtd->info; |
335 | 365 | ||
336 | if (chip != -1 && allow_clk_stop(info)) | 366 | if (chip != -1) |
337 | clk_enable(info->clk); | 367 | s3c2410_nand_clk_set_state(info, CLOCK_ENABLE); |
338 | 368 | ||
339 | cur = readl(info->sel_reg); | 369 | cur = readl(info->sel_reg); |
340 | 370 | ||
@@ -356,8 +386,8 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip) | |||
356 | 386 | ||
357 | writel(cur, info->sel_reg); | 387 | writel(cur, info->sel_reg); |
358 | 388 | ||
359 | if (chip == -1 && allow_clk_stop(info)) | 389 | if (chip == -1) |
360 | clk_disable(info->clk); | 390 | s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND); |
361 | } | 391 | } |
362 | 392 | ||
363 | /* s3c2410_nand_hwcontrol | 393 | /* s3c2410_nand_hwcontrol |
@@ -694,8 +724,7 @@ static int s3c24xx_nand_remove(struct platform_device *pdev) | |||
694 | /* free the common resources */ | 724 | /* free the common resources */ |
695 | 725 | ||
696 | if (info->clk != NULL && !IS_ERR(info->clk)) { | 726 | if (info->clk != NULL && !IS_ERR(info->clk)) { |
697 | if (!allow_clk_stop(info)) | 727 | s3c2410_nand_clk_set_state(info, CLOCK_DISABLE); |
698 | clk_disable(info->clk); | ||
699 | clk_put(info->clk); | 728 | clk_put(info->clk); |
700 | } | 729 | } |
701 | 730 | ||
@@ -947,7 +976,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev) | |||
947 | goto exit_error; | 976 | goto exit_error; |
948 | } | 977 | } |
949 | 978 | ||
950 | clk_enable(info->clk); | 979 | s3c2410_nand_clk_set_state(info, CLOCK_ENABLE); |
951 | 980 | ||
952 | /* allocate and map the resource */ | 981 | /* allocate and map the resource */ |
953 | 982 | ||
@@ -1026,9 +1055,9 @@ static int s3c24xx_nand_probe(struct platform_device *pdev) | |||
1026 | goto exit_error; | 1055 | goto exit_error; |
1027 | } | 1056 | } |
1028 | 1057 | ||
1029 | if (allow_clk_stop(info)) { | 1058 | if (allow_clk_suspend(info)) { |
1030 | dev_info(&pdev->dev, "clock idle support enabled\n"); | 1059 | dev_info(&pdev->dev, "clock idle support enabled\n"); |
1031 | clk_disable(info->clk); | 1060 | s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND); |
1032 | } | 1061 | } |
1033 | 1062 | ||
1034 | pr_debug("initialised ok\n"); | 1063 | pr_debug("initialised ok\n"); |
@@ -1059,8 +1088,7 @@ static int s3c24xx_nand_suspend(struct platform_device *dev, pm_message_t pm) | |||
1059 | 1088 | ||
1060 | writel(info->save_sel | info->sel_bit, info->sel_reg); | 1089 | writel(info->save_sel | info->sel_bit, info->sel_reg); |
1061 | 1090 | ||
1062 | if (!allow_clk_stop(info)) | 1091 | s3c2410_nand_clk_set_state(info, CLOCK_DISABLE); |
1063 | clk_disable(info->clk); | ||
1064 | } | 1092 | } |
1065 | 1093 | ||
1066 | return 0; | 1094 | return 0; |
@@ -1072,7 +1100,7 @@ static int s3c24xx_nand_resume(struct platform_device *dev) | |||
1072 | unsigned long sel; | 1100 | unsigned long sel; |
1073 | 1101 | ||
1074 | if (info) { | 1102 | if (info) { |
1075 | clk_enable(info->clk); | 1103 | s3c2410_nand_clk_set_state(info, CLOCK_ENABLE); |
1076 | s3c2410_nand_inithw(info); | 1104 | s3c2410_nand_inithw(info); |
1077 | 1105 | ||
1078 | /* Restore the state of the nFCE line. */ | 1106 | /* Restore the state of the nFCE line. */ |
@@ -1082,8 +1110,7 @@ static int s3c24xx_nand_resume(struct platform_device *dev) | |||
1082 | sel |= info->save_sel & info->sel_bit; | 1110 | sel |= info->save_sel & info->sel_bit; |
1083 | writel(sel, info->sel_reg); | 1111 | writel(sel, info->sel_reg); |
1084 | 1112 | ||
1085 | if (allow_clk_stop(info)) | 1113 | s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND); |
1086 | clk_disable(info->clk); | ||
1087 | } | 1114 | } |
1088 | 1115 | ||
1089 | return 0; | 1116 | return 0; |