This is the cpufreq notifier for the S3C2410 NAND driver.

Signed-off-by: Cesar Eduardo Barros <[EMAIL PROTECTED]>
---
 drivers/mtd/nand/Kconfig   |    2 +-
 drivers/mtd/nand/s3c2410.c |   82 ++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 80 insertions(+), 4 deletions(-)

diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 246d451..ec9a402 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -128,7 +128,7 @@ config MTD_NAND_PPCHAMELEONEVB
 
 config MTD_NAND_S3C2410
        tristate "NAND Flash support for S3C2410/S3C2440 SoC"
-       depends on ARCH_S3C2410
+       depends on ARCH_S3C2410 && (CPU_FREQ=n || CPU_FREQ_S3C2410)
        help
          This enables the NAND flash controller on the S3C2410 and S3C2440
          SoCs
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index f7dd4e0..1277ae5 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -52,6 +52,7 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/clk.h>
+#include <linux/cpufreq.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
@@ -63,6 +64,8 @@
 #include <asm/plat-s3c/regs-nand.h>
 #include <asm/plat-s3c/nand.h>
 
+#include <asm/arch/s3c2410-cpufreq.h>
+
 #ifdef CONFIG_MTD_NAND_S3C2410_HWECC
 static int hardware_ecc = 1;
 #else
@@ -121,6 +124,10 @@ struct s3c2410_nand_info {
        int                             mtd_count;
 
        enum s3c_cpu_type               cpu_type;
+
+#ifdef CONFIG_CPU_FREQ
+       struct notifier_block           cpufreq_nb;
+#endif
 };
 
 /* conversion functions */
@@ -178,11 +185,11 @@ static int s3c_nand_calc_rate(int wanted, unsigned long 
clk, int max)
 
 /* controller setup */
 
-static int s3c2410_nand_inithw(struct s3c2410_nand_info *info,
-                              struct platform_device *pdev)
+static int s3c2410_nand_inithw_clkrate(struct s3c2410_nand_info *info,
+                                      struct platform_device *pdev,
+                                      unsigned long clkrate)
 {
        struct s3c2410_platform_nand *plat = to_nand_plat(pdev);
-       unsigned long clkrate = clk_get_rate(info->clk);
        int tacls_max = (info->cpu_type == TYPE_S3C2412) ? 8 : 4;
        int tacls, twrph0, twrph1;
        unsigned long cfg = 0;
@@ -235,6 +242,13 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info 
*info,
        return 0;
 }
 
+static int s3c2410_nand_inithw(struct s3c2410_nand_info *info,
+                              struct platform_device *pdev)
+{
+       unsigned long clkrate = clk_get_rate(info->clk);
+       return s3c2410_nand_inithw_clkrate(info, pdev, clkrate);
+}
+
 /* select chip */
 
 static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
@@ -506,6 +520,57 @@ static void s3c2440_nand_write_buf(struct mtd_info *mtd, 
const u_char *buf, int
 
 /* device management functions */
 
+#ifdef CONFIG_CPU_FREQ
+static int s3c2410_nand_cpufreq_notifier(struct notifier_block *nb,
+               unsigned long val, void *data)
+{
+       struct s3c2410_nand_info *info =
+               container_of(nb, struct s3c2410_nand_info, cpufreq_nb);
+       /* FIXME: do this in a better way */
+       struct platform_device *pdev =
+               container_of(info->device, struct platform_device, dev);
+       struct cpufreq_freqs *freqs = data;
+       const struct s3c2410_cpufreq_freqs *target_freqs =
+               s3c2410_cpufreq_target_freqs(freqs);
+
+       /* FIXME: is the locking correct? */
+
+       switch (val) {
+       case CPUFREQ_PRECHANGE:
+               if (target_freqs)
+                       if (target_freqs->new.hclk > target_freqs->old.hclk) {
+                               spin_lock(&info->controller.lock);
+                               s3c2410_nand_inithw_clkrate(info, pdev,
+                                               target_freqs->new.hclk);
+                               spin_unlock(&info->controller.lock);
+                       }
+               break;
+       case CPUFREQ_POSTCHANGE:
+               if (target_freqs) {
+                       if (target_freqs->old.hclk > target_freqs->new.hclk) {
+                               spin_lock(&info->controller.lock);
+                               s3c2410_nand_inithw_clkrate(info, pdev,
+                                               target_freqs->new.hclk);
+                               spin_unlock(&info->controller.lock);
+                       }
+                       break;
+               }
+               /* fall through */
+       case CPUFREQ_RESUMECHANGE:
+       case CPUFREQ_SUSPENDCHANGE:
+               /* target_freqs is not valid */
+               spin_lock(&info->controller.lock);
+               s3c2410_nand_inithw(info, pdev);
+               spin_unlock(&info->controller.lock);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+#endif
+
 static int s3c2410_nand_remove(struct platform_device *pdev)
 {
        struct s3c2410_nand_info *info = to_nand_info(pdev);
@@ -515,6 +580,11 @@ static int s3c2410_nand_remove(struct platform_device 
*pdev)
        if (info == NULL)
                return 0;
 
+#ifdef CONFIG_CPU_FREQ
+       cpufreq_unregister_notifier(&info->cpufreq_nb,
+               CPUFREQ_TRANSITION_NOTIFIER);
+#endif
+
        /* first thing we need to do is release all our mtds
         * and their partitions, then go through freeing the
         * resources used
@@ -835,6 +905,12 @@ static int s3c24xx_nand_probe(struct platform_device *pdev,
                clk_disable(info->clk);
        }
 
+#ifdef CONFIG_CPU_FREQ
+       info->cpufreq_nb.notifier_call = s3c2410_nand_cpufreq_notifier;
+       cpufreq_register_notifier(&info->cpufreq_nb,
+               CPUFREQ_TRANSITION_NOTIFIER);
+#endif
+
        pr_debug("initialised ok\n");
        return 0;
 
-- 
1.5.4


Reply via email to