aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/nand
diff options
context:
space:
mode:
authorJiri Pinkava <jiri.pinkava@vscht.cz>2011-04-13 05:59:30 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2011-05-24 20:53:10 -0400
commitac497c1602555c908c9738fa93b1145f431d1876 (patch)
treea1ab0f42276413e23c4b8ba96fa15d903d841f36 /drivers/mtd/nand
parentc9ddab25d1b62baead4b0c5de562f1fce026dcfd (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.c59
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
58static int clock_stop = 1; 58static const int clock_stop = 1;
59#else 59#else
60static const int clock_stop = 0; 60static 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
99enum 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 */
116struct s3c2410_nand_info { 123struct 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
162static inline int allow_clk_stop(struct s3c2410_nand_info *info) 170static 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 */
180static 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;