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

Linux-MTD Mailing List linux-mtd at lists.infradead.org
Mon Jun 19 04:59:02 EDT 2006


Commit:     d1fef3c5e16327661be6cb127d68f5be379697a5
Parent:     1046d88001e7b8819f60dece2eaf1b44bf4b4460
commit d1fef3c5e16327661be6cb127d68f5be379697a5
Author:     Ben Dooks <ben-linux at fluff.org>
AuthorDate: Mon Jun 19 09:29:38 2006 +0100
Commit:     David Woodhouse <dwmw2 at infradead.org>
CommitDate: Mon Jun 19 09:29:38 2006 +0100

    [MTD NAND] s3c24x0 board: Fix clock handling, ensure proper initialisation.
    
    Signed-off-by: Ben Dooks <ben-linux at fluff.org>
    Signed-off-by: David Woodhouse <dwmw2 at infradead.org>
---
 drivers/mtd/nand/Kconfig   |   10 ++++++
 drivers/mtd/nand/s3c2410.c |   76 +++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 81 insertions(+), 5 deletions(-)

diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 203f90a..3db77ee 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -135,6 +135,16 @@ config MTD_NAND_NDFC
 	help
 	 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
 	tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation) (EXPERIMENTAL)"
 	depends on MTD_NAND && EXPERIMENTAL
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index d6365a6..fd78fb8 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -18,8 +18,9 @@
  *	20-Jun-2005  BJD  Updated s3c2440 support, fixed timing bug
  *	08-Jul-2005  BJD  Fix OOPS when no platform data supplied
  *	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
  * it under the terms of the GNU General Public License as published by
@@ -36,9 +37,6 @@
  * 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
 #define DEBUG
 #endif
@@ -73,6 +71,13 @@ #else
 static int hardware_ecc = 0;
 #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
  */
 
@@ -134,6 +139,11 @@ static struct s3c2410_platform_nand *to_
 	return dev->dev.platform_data;
 }
 
+static inline int allow_clk_stop(struct s3c2410_nand_info *info)
+{
+	return clock_stop;
+}
+
 /* timing calculations */
 
 #define NS_IN_KHZ 1000000
@@ -201,6 +211,11 @@ static int s3c2410_nand_inithw(struct s3
 		cfg = S3C2440_NFCONF_TACLS(tacls - 1);
 		cfg |= S3C2440_NFCONF_TWRPH0(twrph0 - 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);
@@ -226,6 +241,9 @@ static void s3c2410_nand_select_chip(str
 	bit = (info->is_s3c2440) ? S3C2440_NFCONT_nFCE : S3C2410_NFCONF_nFCE;
 	reg = info->regs + ((info->is_s3c2440) ? S3C2440_NFCONT : S3C2410_NFCONF);
 
+	if (chip != -1 && allow_clk_stop(info))
+		clk_enable(info->clk);
+
 	cur = readl(reg);
 
 	if (chip == -1) {
@@ -245,6 +263,9 @@ static void s3c2410_nand_select_chip(str
 	}
 
 	writel(cur, reg);
+
+	if (chip == -1 && allow_clk_stop(info))
+		clk_disable(info->clk);
 }
 
 /* command and control functions
@@ -417,7 +438,8 @@ static int s3c2410_nand_remove(struct pl
 	/* free the common resources */
 
 	if (info->clk != NULL && !IS_ERR(info->clk)) {
-		clk_disable(info->clk);
+		if (!allow_clk_stop(info))
+			clk_disable(info->clk);
 		clk_put(info->clk);
 	}
 
@@ -627,6 +649,11 @@ static int s3c24xx_nand_probe(struct pla
 			sets++;
 	}
 
+	if (allow_clk_stop(info)) {
+		dev_info(&pdev->dev, "clock idle support enabled\n");
+		clk_disable(info->clk);
+	}
+
 	pr_debug("initialised ok\n");
 	return 0;
 
@@ -638,6 +665,41 @@ static int s3c24xx_nand_probe(struct pla
 	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 */
 
 static int s3c2410_nand_probe(struct platform_device *dev)
@@ -653,6 +715,8 @@ static int s3c2440_nand_probe(struct pla
 static struct platform_driver s3c2410_nand_driver = {
 	.probe		= s3c2410_nand_probe,
 	.remove		= s3c2410_nand_remove,
+	.suspend	= s3c24xx_nand_suspend,
+	.resume		= s3c24xx_nand_resume,
 	.driver		= {
 		.name	= "s3c2410-nand",
 		.owner	= THIS_MODULE,
@@ -662,6 +726,8 @@ static struct platform_driver s3c2410_na
 static struct platform_driver s3c2440_nand_driver = {
 	.probe		= s3c2440_nand_probe,
 	.remove		= s3c2410_nand_remove,
+	.suspend	= s3c24xx_nand_suspend,
+	.resume		= s3c24xx_nand_resume,
 	.driver		= {
 		.name	= "s3c2440-nand",
 		.owner	= THIS_MODULE,



More information about the linux-mtd-cvs mailing list