Loading drivers/mtd/nand/s3c2410.c +122 −21 Original line number Diff line number Diff line Loading @@ -36,6 +36,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> Loading Loading @@ -104,8 +105,13 @@ struct s3c2410_nand_info { int sel_bit; int mtd_count; unsigned long save_sel; unsigned long clk_rate; enum s3c_cpu_type cpu_type; #ifdef CONFIG_CPU_FREQ struct notifier_block freq_transition; #endif }; /* conversion functions */ Loading Loading @@ -163,17 +169,18 @@ 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_setrate(struct s3c2410_nand_info *info) { struct s3c2410_platform_nand *plat = to_nand_plat(pdev); unsigned long clkrate = clk_get_rate(info->clk); struct s3c2410_platform_nand *plat = info->platform; int tacls_max = (info->cpu_type == TYPE_S3C2412) ? 8 : 4; int tacls, twrph0, twrph1; unsigned long cfg = 0; unsigned long clkrate = clk_get_rate(info->clk); unsigned long set, cfg, mask; unsigned long flags; /* calculate the timing information for the controller */ info->clk_rate = clkrate; clkrate /= 1000; /* turn clock into kHz for ease of use */ if (plat != NULL) { Loading @@ -197,26 +204,67 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, switch (info->cpu_type) { case TYPE_S3C2410: cfg = S3C2410_NFCONF_EN; cfg |= S3C2410_NFCONF_TACLS(tacls - 1); cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1); cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1); mask = (S3C2410_NFCONF_TACLS(3) | S3C2410_NFCONF_TWRPH0(7) | S3C2410_NFCONF_TWRPH1(7)); set = S3C2410_NFCONF_EN; set |= S3C2410_NFCONF_TACLS(tacls - 1); set |= S3C2410_NFCONF_TWRPH0(twrph0 - 1); set |= S3C2410_NFCONF_TWRPH1(twrph1 - 1); break; case TYPE_S3C2440: case TYPE_S3C2412: cfg = S3C2440_NFCONF_TACLS(tacls - 1); cfg |= S3C2440_NFCONF_TWRPH0(twrph0 - 1); cfg |= S3C2440_NFCONF_TWRPH1(twrph1 - 1); mask = (S3C2410_NFCONF_TACLS(tacls_max - 1) | S3C2410_NFCONF_TWRPH0(7) | S3C2410_NFCONF_TWRPH1(7)); /* enable the controller and de-assert nFCE */ set = S3C2440_NFCONF_TACLS(tacls - 1); set |= S3C2440_NFCONF_TWRPH0(twrph0 - 1); set |= S3C2440_NFCONF_TWRPH1(twrph1 - 1); break; writel(S3C2440_NFCONT_ENABLE, info->regs + S3C2440_NFCONT); default: /* keep compiler happy */ mask = 0; set = 0; BUG(); } dev_dbg(info->device, "NF_CONF is 0x%lx\n", cfg); local_irq_save(flags); cfg = readl(info->regs + S3C2410_NFCONF); cfg &= ~mask; cfg |= set; writel(cfg, info->regs + S3C2410_NFCONF); local_irq_restore(flags); return 0; } static int s3c2410_nand_inithw(struct s3c2410_nand_info *info) { int ret; ret = s3c2410_nand_setrate(info); if (ret < 0) return ret; switch (info->cpu_type) { case TYPE_S3C2410: default: break; case TYPE_S3C2440: case TYPE_S3C2412: /* enable the controller and de-assert nFCE */ writel(S3C2440_NFCONT_ENABLE, info->regs + S3C2440_NFCONT); } return 0; } Loading Loading @@ -497,6 +545,52 @@ static void s3c2440_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int writesl(info->regs + S3C2440_NFDATA, buf, len / 4); } /* cpufreq driver support */ #ifdef CONFIG_CPU_FREQ static int s3c2410_nand_cpufreq_transition(struct notifier_block *nb, unsigned long val, void *data) { struct s3c2410_nand_info *info; unsigned long newclk; info = container_of(nb, struct s3c2410_nand_info, freq_transition); newclk = clk_get_rate(info->clk); if ((val == CPUFREQ_POSTCHANGE && newclk < info->clk_rate) || (val == CPUFREQ_PRECHANGE && newclk > info->clk_rate)) { s3c2410_nand_setrate(info); } return 0; } static inline int s3c2410_nand_cpufreq_register(struct s3c2410_nand_info *info) { info->freq_transition.notifier_call = s3c2410_nand_cpufreq_transition; return cpufreq_register_notifier(&info->freq_transition, CPUFREQ_TRANSITION_NOTIFIER); } static inline void s3c2410_nand_cpufreq_deregister(struct s3c2410_nand_info *info) { cpufreq_unregister_notifier(&info->freq_transition, CPUFREQ_TRANSITION_NOTIFIER); } #else static inline int s3c2410_nand_cpufreq_register(struct s3c2410_nand_info *info) { return 0; } static inline void s3c2410_nand_cpufreq_deregister(struct s3c2410_nand_info *info) { } #endif /* device management functions */ static int s3c2410_nand_remove(struct platform_device *pdev) Loading @@ -508,9 +602,10 @@ static int s3c2410_nand_remove(struct platform_device *pdev) if (info == NULL) return 0; /* first thing we need to do is release all our mtds * and their partitions, then go through freeing the * resources used s3c2410_nand_cpufreq_deregister(info); /* Release all our mtds and their partitions, then go through * freeing the resources used */ if (info->mtds != NULL) { Loading Loading @@ -769,7 +864,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev, /* initialise the hardware */ err = s3c2410_nand_inithw(info, pdev); err = s3c2410_nand_inithw(info); if (err != 0) goto exit_error; Loading Loading @@ -812,6 +907,12 @@ static int s3c24xx_nand_probe(struct platform_device *pdev, sets++; } err = s3c2410_nand_cpufreq_register(info); if (err < 0) { dev_err(&pdev->dev, "failed to init cpufreq support\n"); goto exit_error; } if (allow_clk_stop(info)) { dev_info(&pdev->dev, "clock idle support enabled\n"); clk_disable(info->clk); Loading Loading @@ -859,7 +960,7 @@ static int s3c24xx_nand_resume(struct platform_device *dev) if (info) { clk_enable(info->clk); s3c2410_nand_inithw(info, dev); s3c2410_nand_inithw(info); /* Restore the state of the nFCE line. */ Loading Loading
drivers/mtd/nand/s3c2410.c +122 −21 Original line number Diff line number Diff line Loading @@ -36,6 +36,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> Loading Loading @@ -104,8 +105,13 @@ struct s3c2410_nand_info { int sel_bit; int mtd_count; unsigned long save_sel; unsigned long clk_rate; enum s3c_cpu_type cpu_type; #ifdef CONFIG_CPU_FREQ struct notifier_block freq_transition; #endif }; /* conversion functions */ Loading Loading @@ -163,17 +169,18 @@ 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_setrate(struct s3c2410_nand_info *info) { struct s3c2410_platform_nand *plat = to_nand_plat(pdev); unsigned long clkrate = clk_get_rate(info->clk); struct s3c2410_platform_nand *plat = info->platform; int tacls_max = (info->cpu_type == TYPE_S3C2412) ? 8 : 4; int tacls, twrph0, twrph1; unsigned long cfg = 0; unsigned long clkrate = clk_get_rate(info->clk); unsigned long set, cfg, mask; unsigned long flags; /* calculate the timing information for the controller */ info->clk_rate = clkrate; clkrate /= 1000; /* turn clock into kHz for ease of use */ if (plat != NULL) { Loading @@ -197,26 +204,67 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, switch (info->cpu_type) { case TYPE_S3C2410: cfg = S3C2410_NFCONF_EN; cfg |= S3C2410_NFCONF_TACLS(tacls - 1); cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1); cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1); mask = (S3C2410_NFCONF_TACLS(3) | S3C2410_NFCONF_TWRPH0(7) | S3C2410_NFCONF_TWRPH1(7)); set = S3C2410_NFCONF_EN; set |= S3C2410_NFCONF_TACLS(tacls - 1); set |= S3C2410_NFCONF_TWRPH0(twrph0 - 1); set |= S3C2410_NFCONF_TWRPH1(twrph1 - 1); break; case TYPE_S3C2440: case TYPE_S3C2412: cfg = S3C2440_NFCONF_TACLS(tacls - 1); cfg |= S3C2440_NFCONF_TWRPH0(twrph0 - 1); cfg |= S3C2440_NFCONF_TWRPH1(twrph1 - 1); mask = (S3C2410_NFCONF_TACLS(tacls_max - 1) | S3C2410_NFCONF_TWRPH0(7) | S3C2410_NFCONF_TWRPH1(7)); /* enable the controller and de-assert nFCE */ set = S3C2440_NFCONF_TACLS(tacls - 1); set |= S3C2440_NFCONF_TWRPH0(twrph0 - 1); set |= S3C2440_NFCONF_TWRPH1(twrph1 - 1); break; writel(S3C2440_NFCONT_ENABLE, info->regs + S3C2440_NFCONT); default: /* keep compiler happy */ mask = 0; set = 0; BUG(); } dev_dbg(info->device, "NF_CONF is 0x%lx\n", cfg); local_irq_save(flags); cfg = readl(info->regs + S3C2410_NFCONF); cfg &= ~mask; cfg |= set; writel(cfg, info->regs + S3C2410_NFCONF); local_irq_restore(flags); return 0; } static int s3c2410_nand_inithw(struct s3c2410_nand_info *info) { int ret; ret = s3c2410_nand_setrate(info); if (ret < 0) return ret; switch (info->cpu_type) { case TYPE_S3C2410: default: break; case TYPE_S3C2440: case TYPE_S3C2412: /* enable the controller and de-assert nFCE */ writel(S3C2440_NFCONT_ENABLE, info->regs + S3C2440_NFCONT); } return 0; } Loading Loading @@ -497,6 +545,52 @@ static void s3c2440_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int writesl(info->regs + S3C2440_NFDATA, buf, len / 4); } /* cpufreq driver support */ #ifdef CONFIG_CPU_FREQ static int s3c2410_nand_cpufreq_transition(struct notifier_block *nb, unsigned long val, void *data) { struct s3c2410_nand_info *info; unsigned long newclk; info = container_of(nb, struct s3c2410_nand_info, freq_transition); newclk = clk_get_rate(info->clk); if ((val == CPUFREQ_POSTCHANGE && newclk < info->clk_rate) || (val == CPUFREQ_PRECHANGE && newclk > info->clk_rate)) { s3c2410_nand_setrate(info); } return 0; } static inline int s3c2410_nand_cpufreq_register(struct s3c2410_nand_info *info) { info->freq_transition.notifier_call = s3c2410_nand_cpufreq_transition; return cpufreq_register_notifier(&info->freq_transition, CPUFREQ_TRANSITION_NOTIFIER); } static inline void s3c2410_nand_cpufreq_deregister(struct s3c2410_nand_info *info) { cpufreq_unregister_notifier(&info->freq_transition, CPUFREQ_TRANSITION_NOTIFIER); } #else static inline int s3c2410_nand_cpufreq_register(struct s3c2410_nand_info *info) { return 0; } static inline void s3c2410_nand_cpufreq_deregister(struct s3c2410_nand_info *info) { } #endif /* device management functions */ static int s3c2410_nand_remove(struct platform_device *pdev) Loading @@ -508,9 +602,10 @@ static int s3c2410_nand_remove(struct platform_device *pdev) if (info == NULL) return 0; /* first thing we need to do is release all our mtds * and their partitions, then go through freeing the * resources used s3c2410_nand_cpufreq_deregister(info); /* Release all our mtds and their partitions, then go through * freeing the resources used */ if (info->mtds != NULL) { Loading Loading @@ -769,7 +864,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev, /* initialise the hardware */ err = s3c2410_nand_inithw(info, pdev); err = s3c2410_nand_inithw(info); if (err != 0) goto exit_error; Loading Loading @@ -812,6 +907,12 @@ static int s3c24xx_nand_probe(struct platform_device *pdev, sets++; } err = s3c2410_nand_cpufreq_register(info); if (err < 0) { dev_err(&pdev->dev, "failed to init cpufreq support\n"); goto exit_error; } if (allow_clk_stop(info)) { dev_info(&pdev->dev, "clock idle support enabled\n"); clk_disable(info->clk); Loading Loading @@ -859,7 +960,7 @@ static int s3c24xx_nand_resume(struct platform_device *dev) if (info) { clk_enable(info->clk); s3c2410_nand_inithw(info, dev); s3c2410_nand_inithw(info); /* Restore the state of the nFCE line. */ Loading