Commit ac497c16 authored by Jiri Pinkava's avatar Jiri Pinkava Committed by David Woodhouse

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: default avatarJiri Pinkava <jiri.pinkava@vscht.cz>
Signed-off-by: default avatarArtem Bityutskiy <Artem.Bityutskiy@nokia.com>
Signed-off-by: default avatarDavid Woodhouse <David.Woodhouse@intel.com>
parent c9ddab25
...@@ -55,7 +55,7 @@ static int hardware_ecc = 0; ...@@ -55,7 +55,7 @@ static int hardware_ecc = 0;
#endif #endif
#ifdef CONFIG_MTD_NAND_S3C2410_CLKSTOP #ifdef CONFIG_MTD_NAND_S3C2410_CLKSTOP
static int clock_stop = 1; static const int clock_stop = 1;
#else #else
static const int clock_stop = 0; static const int clock_stop = 0;
#endif #endif
...@@ -96,6 +96,12 @@ enum s3c_cpu_type { ...@@ -96,6 +96,12 @@ enum s3c_cpu_type {
TYPE_S3C2440, TYPE_S3C2440,
}; };
enum s3c_nand_clk_state {
CLOCK_DISABLE = 0,
CLOCK_ENABLE,
CLOCK_SUSPEND,
};
/* overview of the s3c2410 nand state */ /* overview of the s3c2410 nand state */
/** /**
...@@ -111,6 +117,7 @@ enum s3c_cpu_type { ...@@ -111,6 +117,7 @@ enum s3c_cpu_type {
* @mtd_count: The number of MTDs created from this controller. * @mtd_count: The number of MTDs created from this controller.
* @save_sel: The contents of @sel_reg to be saved over suspend. * @save_sel: The contents of @sel_reg to be saved over suspend.
* @clk_rate: The clock rate from @clk. * @clk_rate: The clock rate from @clk.
* @clk_state: The current clock state.
* @cpu_type: The exact type of this controller. * @cpu_type: The exact type of this controller.
*/ */
struct s3c2410_nand_info { struct s3c2410_nand_info {
...@@ -129,6 +136,7 @@ struct s3c2410_nand_info { ...@@ -129,6 +136,7 @@ struct s3c2410_nand_info {
int mtd_count; int mtd_count;
unsigned long save_sel; unsigned long save_sel;
unsigned long clk_rate; unsigned long clk_rate;
enum s3c_nand_clk_state clk_state;
enum s3c_cpu_type cpu_type; enum s3c_cpu_type cpu_type;
...@@ -159,11 +167,33 @@ static struct s3c2410_platform_nand *to_nand_plat(struct platform_device *dev) ...@@ -159,11 +167,33 @@ static struct s3c2410_platform_nand *to_nand_plat(struct platform_device *dev)
return dev->dev.platform_data; return dev->dev.platform_data;
} }
static inline int allow_clk_stop(struct s3c2410_nand_info *info) static inline int allow_clk_suspend(struct s3c2410_nand_info *info)
{ {
return clock_stop; return clock_stop;
} }
/**
* s3c2410_nand_clk_set_state - Enable, disable or suspend NAND clock.
* @info: The controller instance.
* @new_state: State to which clock should be set.
*/
static void s3c2410_nand_clk_set_state(struct s3c2410_nand_info *info,
enum s3c_nand_clk_state new_state)
{
if (!allow_clk_suspend(info) && new_state == CLOCK_SUSPEND)
return;
if (info->clk_state == CLOCK_ENABLE) {
if (new_state != CLOCK_ENABLE)
clk_disable(info->clk);
} else {
if (new_state == CLOCK_ENABLE)
clk_enable(info->clk);
}
info->clk_state = new_state;
}
/* timing calculations */ /* timing calculations */
#define NS_IN_KHZ 1000000 #define NS_IN_KHZ 1000000
...@@ -333,8 +363,8 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip) ...@@ -333,8 +363,8 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
nmtd = this->priv; nmtd = this->priv;
info = nmtd->info; info = nmtd->info;
if (chip != -1 && allow_clk_stop(info)) if (chip != -1)
clk_enable(info->clk); s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);
cur = readl(info->sel_reg); cur = readl(info->sel_reg);
...@@ -356,8 +386,8 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip) ...@@ -356,8 +386,8 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
writel(cur, info->sel_reg); writel(cur, info->sel_reg);
if (chip == -1 && allow_clk_stop(info)) if (chip == -1)
clk_disable(info->clk); s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND);
} }
/* s3c2410_nand_hwcontrol /* s3c2410_nand_hwcontrol
...@@ -694,8 +724,7 @@ static int s3c24xx_nand_remove(struct platform_device *pdev) ...@@ -694,8 +724,7 @@ static int s3c24xx_nand_remove(struct platform_device *pdev)
/* free the common resources */ /* free the common resources */
if (info->clk != NULL && !IS_ERR(info->clk)) { if (info->clk != NULL && !IS_ERR(info->clk)) {
if (!allow_clk_stop(info)) s3c2410_nand_clk_set_state(info, CLOCK_DISABLE);
clk_disable(info->clk);
clk_put(info->clk); clk_put(info->clk);
} }
...@@ -947,7 +976,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev) ...@@ -947,7 +976,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
goto exit_error; goto exit_error;
} }
clk_enable(info->clk); s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);
/* allocate and map the resource */ /* allocate and map the resource */
...@@ -1026,9 +1055,9 @@ static int s3c24xx_nand_probe(struct platform_device *pdev) ...@@ -1026,9 +1055,9 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
goto exit_error; goto exit_error;
} }
if (allow_clk_stop(info)) { if (allow_clk_suspend(info)) {
dev_info(&pdev->dev, "clock idle support enabled\n"); dev_info(&pdev->dev, "clock idle support enabled\n");
clk_disable(info->clk); s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND);
} }
pr_debug("initialised ok\n"); pr_debug("initialised ok\n");
...@@ -1059,8 +1088,7 @@ static int s3c24xx_nand_suspend(struct platform_device *dev, pm_message_t pm) ...@@ -1059,8 +1088,7 @@ static int s3c24xx_nand_suspend(struct platform_device *dev, pm_message_t pm)
writel(info->save_sel | info->sel_bit, info->sel_reg); writel(info->save_sel | info->sel_bit, info->sel_reg);
if (!allow_clk_stop(info)) s3c2410_nand_clk_set_state(info, CLOCK_DISABLE);
clk_disable(info->clk);
} }
return 0; return 0;
...@@ -1072,7 +1100,7 @@ static int s3c24xx_nand_resume(struct platform_device *dev) ...@@ -1072,7 +1100,7 @@ static int s3c24xx_nand_resume(struct platform_device *dev)
unsigned long sel; unsigned long sel;
if (info) { if (info) {
clk_enable(info->clk); s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);
s3c2410_nand_inithw(info); s3c2410_nand_inithw(info);
/* Restore the state of the nFCE line. */ /* Restore the state of the nFCE line. */
...@@ -1082,8 +1110,7 @@ static int s3c24xx_nand_resume(struct platform_device *dev) ...@@ -1082,8 +1110,7 @@ static int s3c24xx_nand_resume(struct platform_device *dev)
sel |= info->save_sel & info->sel_bit; sel |= info->save_sel & info->sel_bit;
writel(sel, info->sel_reg); writel(sel, info->sel_reg);
if (allow_clk_stop(info)) s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND);
clk_disable(info->clk);
} }
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment