Commit d1fef3c5 authored by Ben Dooks's avatar Ben Dooks Committed by David Woodhouse

[MTD NAND] s3c24x0 board: Fix clock handling, ensure proper initialisation.

Signed-off-by: default avatarBen Dooks <ben-linux@fluff.org>
Signed-off-by: default avatarDavid Woodhouse <dwmw2@infradead.org>
parent 1046d880
...@@ -135,6 +135,16 @@ config MTD_NAND_NDFC ...@@ -135,6 +135,16 @@ config MTD_NAND_NDFC
help help
NDFC Nand Flash Controllers are integrated in EP44x SoCs NDFC Nand Flash Controllers are integrated in EP44x SoCs
config MTD_NAND_S3C2410_CLKSTOP
bool "S3C2410 NAND IDLE clock stop"
depends on MTD_NAND_S3C2410
default n
help
Stop the clock to the NAND controller when there is no chip
selected to save power. This will mean there is a small delay
when the is NAND chip selected or released, but will save
approximately 5mA of power when there is nothing happening.
config MTD_NAND_DISKONCHIP config MTD_NAND_DISKONCHIP
tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation) (EXPERIMENTAL)" tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation) (EXPERIMENTAL)"
depends on MTD_NAND && EXPERIMENTAL depends on MTD_NAND && EXPERIMENTAL
......
...@@ -18,8 +18,9 @@ ...@@ -18,8 +18,9 @@
* 20-Jun-2005 BJD Updated s3c2440 support, fixed timing bug * 20-Jun-2005 BJD Updated s3c2440 support, fixed timing bug
* 08-Jul-2005 BJD Fix OOPS when no platform data supplied * 08-Jul-2005 BJD Fix OOPS when no platform data supplied
* 20-Oct-2005 BJD Fix timing calculation bug * 20-Oct-2005 BJD Fix timing calculation bug
* 14-Jan-2006 BJD Allow clock to be stopped when idle
* *
* $Id: s3c2410.c,v 1.20 2005/11/07 11:14:31 gleixner Exp $ * $Id: s3c2410.c,v 1.23 2006/04/01 18:06:29 bjd Exp $
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
...@@ -36,9 +37,6 @@ ...@@ -36,9 +37,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include <config/mtd/nand/s3c2410/hwecc.h>
#include <config/mtd/nand/s3c2410/debug.h>
#ifdef CONFIG_MTD_NAND_S3C2410_DEBUG #ifdef CONFIG_MTD_NAND_S3C2410_DEBUG
#define DEBUG #define DEBUG
#endif #endif
...@@ -73,6 +71,13 @@ static int hardware_ecc = 1; ...@@ -73,6 +71,13 @@ static int hardware_ecc = 1;
static int hardware_ecc = 0; static int hardware_ecc = 0;
#endif #endif
#ifdef CONFIG_MTD_NAND_S3C2410_CLKSTOP
static int clock_stop = 1;
#else
static const int clock_stop = 0;
#endif
/* new oob placement block for use with hardware ecc generation /* new oob placement block for use with hardware ecc generation
*/ */
...@@ -134,6 +139,11 @@ static struct s3c2410_platform_nand *to_nand_plat(struct platform_device *dev) ...@@ -134,6 +139,11 @@ 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)
{
return clock_stop;
}
/* timing calculations */ /* timing calculations */
#define NS_IN_KHZ 1000000 #define NS_IN_KHZ 1000000
...@@ -201,6 +211,11 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, struct platform_d ...@@ -201,6 +211,11 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, struct platform_d
cfg = S3C2440_NFCONF_TACLS(tacls - 1); cfg = S3C2440_NFCONF_TACLS(tacls - 1);
cfg |= S3C2440_NFCONF_TWRPH0(twrph0 - 1); cfg |= S3C2440_NFCONF_TWRPH0(twrph0 - 1);
cfg |= S3C2440_NFCONF_TWRPH1(twrph1 - 1); cfg |= S3C2440_NFCONF_TWRPH1(twrph1 - 1);
/* enable the controller and de-assert nFCE */
writel(S3C2440_NFCONT_ENABLE | S3C2440_NFCONT_ENABLE,
info->regs + S3C2440_NFCONT);
} }
pr_debug(PFX "NF_CONF is 0x%lx\n", cfg); pr_debug(PFX "NF_CONF is 0x%lx\n", cfg);
...@@ -226,6 +241,9 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip) ...@@ -226,6 +241,9 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
bit = (info->is_s3c2440) ? S3C2440_NFCONT_nFCE : S3C2410_NFCONF_nFCE; bit = (info->is_s3c2440) ? S3C2440_NFCONT_nFCE : S3C2410_NFCONF_nFCE;
reg = info->regs + ((info->is_s3c2440) ? S3C2440_NFCONT : S3C2410_NFCONF); reg = info->regs + ((info->is_s3c2440) ? S3C2440_NFCONT : S3C2410_NFCONF);
if (chip != -1 && allow_clk_stop(info))
clk_enable(info->clk);
cur = readl(reg); cur = readl(reg);
if (chip == -1) { if (chip == -1) {
...@@ -245,6 +263,9 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip) ...@@ -245,6 +263,9 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
} }
writel(cur, reg); writel(cur, reg);
if (chip == -1 && allow_clk_stop(info))
clk_disable(info->clk);
} }
/* command and control functions /* command and control functions
...@@ -417,6 +438,7 @@ static int s3c2410_nand_remove(struct platform_device *pdev) ...@@ -417,6 +438,7 @@ static int s3c2410_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))
clk_disable(info->clk); clk_disable(info->clk);
clk_put(info->clk); clk_put(info->clk);
} }
...@@ -627,6 +649,11 @@ static int s3c24xx_nand_probe(struct platform_device *pdev, int is_s3c2440) ...@@ -627,6 +649,11 @@ static int s3c24xx_nand_probe(struct platform_device *pdev, int is_s3c2440)
sets++; sets++;
} }
if (allow_clk_stop(info)) {
dev_info(&pdev->dev, "clock idle support enabled\n");
clk_disable(info->clk);
}
pr_debug("initialised ok\n"); pr_debug("initialised ok\n");
return 0; return 0;
...@@ -638,6 +665,41 @@ static int s3c24xx_nand_probe(struct platform_device *pdev, int is_s3c2440) ...@@ -638,6 +665,41 @@ static int s3c24xx_nand_probe(struct platform_device *pdev, int is_s3c2440)
return err; return err;
} }
/* PM Support */
#ifdef CONFIG_PM
static int s3c24xx_nand_suspend(struct platform_device *dev, pm_message_t pm)
{
struct s3c2410_nand_info *info = platform_get_drvdata(dev);
if (info) {
if (!allow_clk_stop(info))
clk_disable(info->clk);
}
return 0;
}
static int s3c24xx_nand_resume(struct platform_device *dev)
{
struct s3c2410_nand_info *info = platform_get_drvdata(dev);
if (info) {
clk_enable(info->clk);
s3c2410_nand_inithw(info, dev);
if (allow_clk_stop(info))
clk_disable(info->clk);
}
return 0;
}
#else
#define s3c24xx_nand_suspend NULL
#define s3c24xx_nand_resume NULL
#endif
/* driver device registration */ /* driver device registration */
static int s3c2410_nand_probe(struct platform_device *dev) static int s3c2410_nand_probe(struct platform_device *dev)
...@@ -653,6 +715,8 @@ static int s3c2440_nand_probe(struct platform_device *dev) ...@@ -653,6 +715,8 @@ static int s3c2440_nand_probe(struct platform_device *dev)
static struct platform_driver s3c2410_nand_driver = { static struct platform_driver s3c2410_nand_driver = {
.probe = s3c2410_nand_probe, .probe = s3c2410_nand_probe,
.remove = s3c2410_nand_remove, .remove = s3c2410_nand_remove,
.suspend = s3c24xx_nand_suspend,
.resume = s3c24xx_nand_resume,
.driver = { .driver = {
.name = "s3c2410-nand", .name = "s3c2410-nand",
.owner = THIS_MODULE, .owner = THIS_MODULE,
...@@ -662,6 +726,8 @@ static struct platform_driver s3c2410_nand_driver = { ...@@ -662,6 +726,8 @@ static struct platform_driver s3c2410_nand_driver = {
static struct platform_driver s3c2440_nand_driver = { static struct platform_driver s3c2440_nand_driver = {
.probe = s3c2440_nand_probe, .probe = s3c2440_nand_probe,
.remove = s3c2410_nand_remove, .remove = s3c2410_nand_remove,
.suspend = s3c24xx_nand_suspend,
.resume = s3c24xx_nand_resume,
.driver = { .driver = {
.name = "s3c2440-nand", .name = "s3c2440-nand",
.owner = THIS_MODULE, .owner = THIS_MODULE,
......
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