diff options
-rw-r--r-- | drivers/mtd/nand/Kconfig | 10 | ||||
-rw-r--r-- | 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 203f90a024db..3db77eec0ed2 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig | |||
@@ -135,6 +135,16 @@ config MTD_NAND_NDFC | |||
135 | help | 135 | help |
136 | NDFC Nand Flash Controllers are integrated in EP44x SoCs | 136 | NDFC Nand Flash Controllers are integrated in EP44x SoCs |
137 | 137 | ||
138 | config MTD_NAND_S3C2410_CLKSTOP | ||
139 | bool "S3C2410 NAND IDLE clock stop" | ||
140 | depends on MTD_NAND_S3C2410 | ||
141 | default n | ||
142 | help | ||
143 | Stop the clock to the NAND controller when there is no chip | ||
144 | selected to save power. This will mean there is a small delay | ||
145 | when the is NAND chip selected or released, but will save | ||
146 | approximately 5mA of power when there is nothing happening. | ||
147 | |||
138 | config MTD_NAND_DISKONCHIP | 148 | config MTD_NAND_DISKONCHIP |
139 | tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation) (EXPERIMENTAL)" | 149 | tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation) (EXPERIMENTAL)" |
140 | depends on MTD_NAND && EXPERIMENTAL | 150 | depends on MTD_NAND && EXPERIMENTAL |
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index d6365a668874..fd78fb83549e 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c | |||
@@ -18,8 +18,9 @@ | |||
18 | * 20-Jun-2005 BJD Updated s3c2440 support, fixed timing bug | 18 | * 20-Jun-2005 BJD Updated s3c2440 support, fixed timing bug |
19 | * 08-Jul-2005 BJD Fix OOPS when no platform data supplied | 19 | * 08-Jul-2005 BJD Fix OOPS when no platform data supplied |
20 | * 20-Oct-2005 BJD Fix timing calculation bug | 20 | * 20-Oct-2005 BJD Fix timing calculation bug |
21 | * 14-Jan-2006 BJD Allow clock to be stopped when idle | ||
21 | * | 22 | * |
22 | * $Id: s3c2410.c,v 1.20 2005/11/07 11:14:31 gleixner Exp $ | 23 | * $Id: s3c2410.c,v 1.23 2006/04/01 18:06:29 bjd Exp $ |
23 | * | 24 | * |
24 | * This program is free software; you can redistribute it and/or modify | 25 | * This program is free software; you can redistribute it and/or modify |
25 | * it under the terms of the GNU General Public License as published by | 26 | * it under the terms of the GNU General Public License as published by |
@@ -36,9 +37,6 @@ | |||
36 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 37 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
37 | */ | 38 | */ |
38 | 39 | ||
39 | #include <config/mtd/nand/s3c2410/hwecc.h> | ||
40 | #include <config/mtd/nand/s3c2410/debug.h> | ||
41 | |||
42 | #ifdef CONFIG_MTD_NAND_S3C2410_DEBUG | 40 | #ifdef CONFIG_MTD_NAND_S3C2410_DEBUG |
43 | #define DEBUG | 41 | #define DEBUG |
44 | #endif | 42 | #endif |
@@ -73,6 +71,13 @@ static int hardware_ecc = 1; | |||
73 | static int hardware_ecc = 0; | 71 | static int hardware_ecc = 0; |
74 | #endif | 72 | #endif |
75 | 73 | ||
74 | #ifdef CONFIG_MTD_NAND_S3C2410_CLKSTOP | ||
75 | static int clock_stop = 1; | ||
76 | #else | ||
77 | static const int clock_stop = 0; | ||
78 | #endif | ||
79 | |||
80 | |||
76 | /* new oob placement block for use with hardware ecc generation | 81 | /* new oob placement block for use with hardware ecc generation |
77 | */ | 82 | */ |
78 | 83 | ||
@@ -134,6 +139,11 @@ static struct s3c2410_platform_nand *to_nand_plat(struct platform_device *dev) | |||
134 | return dev->dev.platform_data; | 139 | return dev->dev.platform_data; |
135 | } | 140 | } |
136 | 141 | ||
142 | static inline int allow_clk_stop(struct s3c2410_nand_info *info) | ||
143 | { | ||
144 | return clock_stop; | ||
145 | } | ||
146 | |||
137 | /* timing calculations */ | 147 | /* timing calculations */ |
138 | 148 | ||
139 | #define NS_IN_KHZ 1000000 | 149 | #define NS_IN_KHZ 1000000 |
@@ -201,6 +211,11 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, struct platform_d | |||
201 | cfg = S3C2440_NFCONF_TACLS(tacls - 1); | 211 | cfg = S3C2440_NFCONF_TACLS(tacls - 1); |
202 | cfg |= S3C2440_NFCONF_TWRPH0(twrph0 - 1); | 212 | cfg |= S3C2440_NFCONF_TWRPH0(twrph0 - 1); |
203 | cfg |= S3C2440_NFCONF_TWRPH1(twrph1 - 1); | 213 | cfg |= S3C2440_NFCONF_TWRPH1(twrph1 - 1); |
214 | |||
215 | /* enable the controller and de-assert nFCE */ | ||
216 | |||
217 | writel(S3C2440_NFCONT_ENABLE | S3C2440_NFCONT_ENABLE, | ||
218 | info->regs + S3C2440_NFCONT); | ||
204 | } | 219 | } |
205 | 220 | ||
206 | pr_debug(PFX "NF_CONF is 0x%lx\n", cfg); | 221 | 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 | bit = (info->is_s3c2440) ? S3C2440_NFCONT_nFCE : S3C2410_NFCONF_nFCE; | 241 | bit = (info->is_s3c2440) ? S3C2440_NFCONT_nFCE : S3C2410_NFCONF_nFCE; |
227 | reg = info->regs + ((info->is_s3c2440) ? S3C2440_NFCONT : S3C2410_NFCONF); | 242 | reg = info->regs + ((info->is_s3c2440) ? S3C2440_NFCONT : S3C2410_NFCONF); |
228 | 243 | ||
244 | if (chip != -1 && allow_clk_stop(info)) | ||
245 | clk_enable(info->clk); | ||
246 | |||
229 | cur = readl(reg); | 247 | cur = readl(reg); |
230 | 248 | ||
231 | if (chip == -1) { | 249 | if (chip == -1) { |
@@ -245,6 +263,9 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip) | |||
245 | } | 263 | } |
246 | 264 | ||
247 | writel(cur, reg); | 265 | writel(cur, reg); |
266 | |||
267 | if (chip == -1 && allow_clk_stop(info)) | ||
268 | clk_disable(info->clk); | ||
248 | } | 269 | } |
249 | 270 | ||
250 | /* command and control functions | 271 | /* command and control functions |
@@ -417,7 +438,8 @@ static int s3c2410_nand_remove(struct platform_device *pdev) | |||
417 | /* free the common resources */ | 438 | /* free the common resources */ |
418 | 439 | ||
419 | if (info->clk != NULL && !IS_ERR(info->clk)) { | 440 | if (info->clk != NULL && !IS_ERR(info->clk)) { |
420 | clk_disable(info->clk); | 441 | if (!allow_clk_stop(info)) |
442 | clk_disable(info->clk); | ||
421 | clk_put(info->clk); | 443 | clk_put(info->clk); |
422 | } | 444 | } |
423 | 445 | ||
@@ -627,6 +649,11 @@ static int s3c24xx_nand_probe(struct platform_device *pdev, int is_s3c2440) | |||
627 | sets++; | 649 | sets++; |
628 | } | 650 | } |
629 | 651 | ||
652 | if (allow_clk_stop(info)) { | ||
653 | dev_info(&pdev->dev, "clock idle support enabled\n"); | ||
654 | clk_disable(info->clk); | ||
655 | } | ||
656 | |||
630 | pr_debug("initialised ok\n"); | 657 | pr_debug("initialised ok\n"); |
631 | return 0; | 658 | return 0; |
632 | 659 | ||
@@ -638,6 +665,41 @@ static int s3c24xx_nand_probe(struct platform_device *pdev, int is_s3c2440) | |||
638 | return err; | 665 | return err; |
639 | } | 666 | } |
640 | 667 | ||
668 | /* PM Support */ | ||
669 | #ifdef CONFIG_PM | ||
670 | |||
671 | static int s3c24xx_nand_suspend(struct platform_device *dev, pm_message_t pm) | ||
672 | { | ||
673 | struct s3c2410_nand_info *info = platform_get_drvdata(dev); | ||
674 | |||
675 | if (info) { | ||
676 | if (!allow_clk_stop(info)) | ||
677 | clk_disable(info->clk); | ||
678 | } | ||
679 | |||
680 | return 0; | ||
681 | } | ||
682 | |||
683 | static int s3c24xx_nand_resume(struct platform_device *dev) | ||
684 | { | ||
685 | struct s3c2410_nand_info *info = platform_get_drvdata(dev); | ||
686 | |||
687 | if (info) { | ||
688 | clk_enable(info->clk); | ||
689 | s3c2410_nand_inithw(info, dev); | ||
690 | |||
691 | if (allow_clk_stop(info)) | ||
692 | clk_disable(info->clk); | ||
693 | } | ||
694 | |||
695 | return 0; | ||
696 | } | ||
697 | |||
698 | #else | ||
699 | #define s3c24xx_nand_suspend NULL | ||
700 | #define s3c24xx_nand_resume NULL | ||
701 | #endif | ||
702 | |||
641 | /* driver device registration */ | 703 | /* driver device registration */ |
642 | 704 | ||
643 | static int s3c2410_nand_probe(struct platform_device *dev) | 705 | static int s3c2410_nand_probe(struct platform_device *dev) |
@@ -653,6 +715,8 @@ static int s3c2440_nand_probe(struct platform_device *dev) | |||
653 | static struct platform_driver s3c2410_nand_driver = { | 715 | static struct platform_driver s3c2410_nand_driver = { |
654 | .probe = s3c2410_nand_probe, | 716 | .probe = s3c2410_nand_probe, |
655 | .remove = s3c2410_nand_remove, | 717 | .remove = s3c2410_nand_remove, |
718 | .suspend = s3c24xx_nand_suspend, | ||
719 | .resume = s3c24xx_nand_resume, | ||
656 | .driver = { | 720 | .driver = { |
657 | .name = "s3c2410-nand", | 721 | .name = "s3c2410-nand", |
658 | .owner = THIS_MODULE, | 722 | .owner = THIS_MODULE, |
@@ -662,6 +726,8 @@ static struct platform_driver s3c2410_nand_driver = { | |||
662 | static struct platform_driver s3c2440_nand_driver = { | 726 | static struct platform_driver s3c2440_nand_driver = { |
663 | .probe = s3c2440_nand_probe, | 727 | .probe = s3c2440_nand_probe, |
664 | .remove = s3c2410_nand_remove, | 728 | .remove = s3c2410_nand_remove, |
729 | .suspend = s3c24xx_nand_suspend, | ||
730 | .resume = s3c24xx_nand_resume, | ||
665 | .driver = { | 731 | .driver = { |
666 | .name = "s3c2440-nand", | 732 | .name = "s3c2440-nand", |
667 | .owner = THIS_MODULE, | 733 | .owner = THIS_MODULE, |