[PATCH 5/9] Experimental S3C2410A cpufreq driver (nand)

Cesar Eduardo Barros cesarb at cesarb.net
Wed Feb 13 02:24:33 CET 2008


This is the cpufreq notifier for the S3C2410 NAND driver.

Signed-off-by: Cesar Eduardo Barros <cesarb at cesarb.net>
---
 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





More information about the openmoko-kernel mailing list