CPUFREQ: S3C24XX NAND driver frequency scaling support.

Add support for CPU frequency scalling to the S3C24XX NAND driver.

Signed-off-by: Ben Dooks <ben-linux@fluff.org>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>

authored by

Ben Dooks and committed by
David Woodhouse
30821fee ee39a0e6

+122 -21
+122 -21
drivers/mtd/nand/s3c2410.c
··· 36 36 #include <linux/err.h> 37 37 #include <linux/slab.h> 38 38 #include <linux/clk.h> 39 + #include <linux/cpufreq.h> 39 40 40 41 #include <linux/mtd/mtd.h> 41 42 #include <linux/mtd/nand.h> ··· 105 104 int sel_bit; 106 105 int mtd_count; 107 106 unsigned long save_sel; 107 + unsigned long clk_rate; 108 108 109 109 enum s3c_cpu_type cpu_type; 110 + 111 + #ifdef CONFIG_CPU_FREQ 112 + struct notifier_block freq_transition; 113 + #endif 110 114 }; 111 115 112 116 /* conversion functions */ ··· 169 163 170 164 /* controller setup */ 171 165 172 - static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, 173 - struct platform_device *pdev) 166 + static int s3c2410_nand_setrate(struct s3c2410_nand_info *info) 174 167 { 175 - struct s3c2410_platform_nand *plat = to_nand_plat(pdev); 176 - unsigned long clkrate = clk_get_rate(info->clk); 168 + struct s3c2410_platform_nand *plat = info->platform; 177 169 int tacls_max = (info->cpu_type == TYPE_S3C2412) ? 8 : 4; 178 170 int tacls, twrph0, twrph1; 179 - unsigned long cfg = 0; 171 + unsigned long clkrate = clk_get_rate(info->clk); 172 + unsigned long set, cfg, mask; 173 + unsigned long flags; 180 174 181 175 /* calculate the timing information for the controller */ 182 176 177 + info->clk_rate = clkrate; 183 178 clkrate /= 1000; /* turn clock into kHz for ease of use */ 184 179 185 180 if (plat != NULL) { ··· 202 195 dev_info(info->device, "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n", 203 196 tacls, to_ns(tacls, clkrate), twrph0, to_ns(twrph0, clkrate), twrph1, to_ns(twrph1, clkrate)); 204 197 198 + switch (info->cpu_type) { 199 + case TYPE_S3C2410: 200 + mask = (S3C2410_NFCONF_TACLS(3) | 201 + S3C2410_NFCONF_TWRPH0(7) | 202 + S3C2410_NFCONF_TWRPH1(7)); 203 + set = S3C2410_NFCONF_EN; 204 + set |= S3C2410_NFCONF_TACLS(tacls - 1); 205 + set |= S3C2410_NFCONF_TWRPH0(twrph0 - 1); 206 + set |= S3C2410_NFCONF_TWRPH1(twrph1 - 1); 207 + break; 208 + 209 + case TYPE_S3C2440: 210 + case TYPE_S3C2412: 211 + mask = (S3C2410_NFCONF_TACLS(tacls_max - 1) | 212 + S3C2410_NFCONF_TWRPH0(7) | 213 + S3C2410_NFCONF_TWRPH1(7)); 214 + 215 + set = S3C2440_NFCONF_TACLS(tacls - 1); 216 + set |= S3C2440_NFCONF_TWRPH0(twrph0 - 1); 217 + set |= S3C2440_NFCONF_TWRPH1(twrph1 - 1); 218 + break; 219 + 220 + default: 221 + /* keep compiler happy */ 222 + mask = 0; 223 + set = 0; 224 + BUG(); 225 + } 226 + 227 + dev_dbg(info->device, "NF_CONF is 0x%lx\n", cfg); 228 + 229 + local_irq_save(flags); 230 + 231 + cfg = readl(info->regs + S3C2410_NFCONF); 232 + cfg &= ~mask; 233 + cfg |= set; 234 + writel(cfg, info->regs + S3C2410_NFCONF); 235 + 236 + local_irq_restore(flags); 237 + 238 + return 0; 239 + } 240 + 241 + static int s3c2410_nand_inithw(struct s3c2410_nand_info *info) 242 + { 243 + int ret; 244 + 245 + ret = s3c2410_nand_setrate(info); 246 + if (ret < 0) 247 + return ret; 248 + 205 249 switch (info->cpu_type) { 206 250 case TYPE_S3C2410: 207 - cfg = S3C2410_NFCONF_EN; 208 - cfg |= S3C2410_NFCONF_TACLS(tacls - 1); 209 - cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1); 210 - cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1); 251 + default: 211 252 break; 212 253 213 254 case TYPE_S3C2440: 214 255 case TYPE_S3C2412: 215 - cfg = S3C2440_NFCONF_TACLS(tacls - 1); 216 - cfg |= S3C2440_NFCONF_TWRPH0(twrph0 - 1); 217 - cfg |= S3C2440_NFCONF_TWRPH1(twrph1 - 1); 218 - 219 256 /* enable the controller and de-assert nFCE */ 220 257 221 258 writel(S3C2440_NFCONT_ENABLE, info->regs + S3C2440_NFCONT); 222 259 } 223 260 224 - dev_dbg(info->device, "NF_CONF is 0x%lx\n", cfg); 225 - 226 - writel(cfg, info->regs + S3C2410_NFCONF); 227 261 return 0; 228 262 } 229 263 ··· 545 497 writesl(info->regs + S3C2440_NFDATA, buf, len / 4); 546 498 } 547 499 500 + /* cpufreq driver support */ 501 + 502 + #ifdef CONFIG_CPU_FREQ 503 + 504 + static int s3c2410_nand_cpufreq_transition(struct notifier_block *nb, 505 + unsigned long val, void *data) 506 + { 507 + struct s3c2410_nand_info *info; 508 + unsigned long newclk; 509 + 510 + info = container_of(nb, struct s3c2410_nand_info, freq_transition); 511 + newclk = clk_get_rate(info->clk); 512 + 513 + if ((val == CPUFREQ_POSTCHANGE && newclk < info->clk_rate) || 514 + (val == CPUFREQ_PRECHANGE && newclk > info->clk_rate)) { 515 + s3c2410_nand_setrate(info); 516 + } 517 + 518 + return 0; 519 + } 520 + 521 + static inline int s3c2410_nand_cpufreq_register(struct s3c2410_nand_info *info) 522 + { 523 + info->freq_transition.notifier_call = s3c2410_nand_cpufreq_transition; 524 + 525 + return cpufreq_register_notifier(&info->freq_transition, 526 + CPUFREQ_TRANSITION_NOTIFIER); 527 + } 528 + 529 + static inline void s3c2410_nand_cpufreq_deregister(struct s3c2410_nand_info *info) 530 + { 531 + cpufreq_unregister_notifier(&info->freq_transition, 532 + CPUFREQ_TRANSITION_NOTIFIER); 533 + } 534 + 535 + #else 536 + static inline int s3c2410_nand_cpufreq_register(struct s3c2410_nand_info *info) 537 + { 538 + return 0; 539 + } 540 + 541 + static inline void s3c2410_nand_cpufreq_deregister(struct s3c2410_nand_info *info) 542 + { 543 + } 544 + #endif 545 + 548 546 /* device management functions */ 549 547 550 548 static int s3c2410_nand_remove(struct platform_device *pdev) ··· 602 508 if (info == NULL) 603 509 return 0; 604 510 605 - /* first thing we need to do is release all our mtds 606 - * and their partitions, then go through freeing the 607 - * resources used 511 + s3c2410_nand_cpufreq_deregister(info); 512 + 513 + /* Release all our mtds and their partitions, then go through 514 + * freeing the resources used 608 515 */ 609 516 610 517 if (info->mtds != NULL) { ··· 864 769 865 770 /* initialise the hardware */ 866 771 867 - err = s3c2410_nand_inithw(info, pdev); 772 + err = s3c2410_nand_inithw(info); 868 773 if (err != 0) 869 774 goto exit_error; 870 775 ··· 905 810 906 811 if (sets != NULL) 907 812 sets++; 813 + } 814 + 815 + err = s3c2410_nand_cpufreq_register(info); 816 + if (err < 0) { 817 + dev_err(&pdev->dev, "failed to init cpufreq support\n"); 818 + goto exit_error; 908 819 } 909 820 910 821 if (allow_clk_stop(info)) { ··· 960 859 961 860 if (info) { 962 861 clk_enable(info->clk); 963 - s3c2410_nand_inithw(info, dev); 862 + s3c2410_nand_inithw(info); 964 863 965 864 /* Restore the state of the nFCE line. */ 966 865