[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