root/drivers/cpufreq/s3c24xx-cpufreq.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. s3c_cpufreq_getconfig
  2. s3c_cpufreq_getiotimings
  3. s3c_cpufreq_getcur
  4. s3c_cpufreq_calc
  5. closer
  6. s3c_cpufreq_show
  7. s3c_cpufreq_setio
  8. s3c_cpufreq_calcio
  9. s3c_cpufreq_setrefresh
  10. s3c_cpufreq_setdivs
  11. s3c_cpufreq_calcdivs
  12. s3c_cpufreq_setfvco
  13. s3c_cpufreq_updateclk
  14. s3c_cpufreq_settarget
  15. s3c_cpufreq_target
  16. s3c_cpufreq_clk_get
  17. s3c_cpufreq_init
  18. s3c_cpufreq_initclks
  19. s3c_cpufreq_suspend
  20. s3c_cpufreq_resume
  21. s3c_cpufreq_register
  22. s3c_cpufreq_setboard
  23. s3c_cpufreq_auto_io
  24. s3c_cpufreq_freq_min
  25. calc_locktime
  26. s3c_cpufreq_update_loctkime
  27. s3c_cpufreq_build_freq
  28. s3c_cpufreq_initcall
  29. s3c_plltab_register

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (c) 2006-2008 Simtec Electronics
   4  *      http://armlinux.simtec.co.uk/
   5  *      Ben Dooks <ben@simtec.co.uk>
   6  *
   7  * S3C24XX CPU Frequency scaling
   8 */
   9 
  10 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  11 
  12 #include <linux/init.h>
  13 #include <linux/module.h>
  14 #include <linux/interrupt.h>
  15 #include <linux/ioport.h>
  16 #include <linux/cpufreq.h>
  17 #include <linux/cpu.h>
  18 #include <linux/clk.h>
  19 #include <linux/err.h>
  20 #include <linux/io.h>
  21 #include <linux/device.h>
  22 #include <linux/sysfs.h>
  23 #include <linux/slab.h>
  24 
  25 #include <asm/mach/arch.h>
  26 #include <asm/mach/map.h>
  27 
  28 #include <plat/cpu.h>
  29 #include <plat/cpu-freq-core.h>
  30 
  31 #include <mach/regs-clock.h>
  32 
  33 /* note, cpufreq support deals in kHz, no Hz */
  34 
  35 static struct cpufreq_driver s3c24xx_driver;
  36 static struct s3c_cpufreq_config cpu_cur;
  37 static struct s3c_iotimings s3c24xx_iotiming;
  38 static struct cpufreq_frequency_table *pll_reg;
  39 static unsigned int last_target = ~0;
  40 static unsigned int ftab_size;
  41 static struct cpufreq_frequency_table *ftab;
  42 
  43 static struct clk *_clk_mpll;
  44 static struct clk *_clk_xtal;
  45 static struct clk *clk_fclk;
  46 static struct clk *clk_hclk;
  47 static struct clk *clk_pclk;
  48 static struct clk *clk_arm;
  49 
  50 #ifdef CONFIG_ARM_S3C24XX_CPUFREQ_DEBUGFS
  51 struct s3c_cpufreq_config *s3c_cpufreq_getconfig(void)
  52 {
  53         return &cpu_cur;
  54 }
  55 
  56 struct s3c_iotimings *s3c_cpufreq_getiotimings(void)
  57 {
  58         return &s3c24xx_iotiming;
  59 }
  60 #endif /* CONFIG_ARM_S3C24XX_CPUFREQ_DEBUGFS */
  61 
  62 static void s3c_cpufreq_getcur(struct s3c_cpufreq_config *cfg)
  63 {
  64         unsigned long fclk, pclk, hclk, armclk;
  65 
  66         cfg->freq.fclk = fclk = clk_get_rate(clk_fclk);
  67         cfg->freq.hclk = hclk = clk_get_rate(clk_hclk);
  68         cfg->freq.pclk = pclk = clk_get_rate(clk_pclk);
  69         cfg->freq.armclk = armclk = clk_get_rate(clk_arm);
  70 
  71         cfg->pll.driver_data = __raw_readl(S3C2410_MPLLCON);
  72         cfg->pll.frequency = fclk;
  73 
  74         cfg->freq.hclk_tns = 1000000000 / (cfg->freq.hclk / 10);
  75 
  76         cfg->divs.h_divisor = fclk / hclk;
  77         cfg->divs.p_divisor = fclk / pclk;
  78 }
  79 
  80 static inline void s3c_cpufreq_calc(struct s3c_cpufreq_config *cfg)
  81 {
  82         unsigned long pll = cfg->pll.frequency;
  83 
  84         cfg->freq.fclk = pll;
  85         cfg->freq.hclk = pll / cfg->divs.h_divisor;
  86         cfg->freq.pclk = pll / cfg->divs.p_divisor;
  87 
  88         /* convert hclk into 10ths of nanoseconds for io calcs */
  89         cfg->freq.hclk_tns = 1000000000 / (cfg->freq.hclk / 10);
  90 }
  91 
  92 static inline int closer(unsigned int target, unsigned int n, unsigned int c)
  93 {
  94         int diff_cur = abs(target - c);
  95         int diff_new = abs(target - n);
  96 
  97         return (diff_new < diff_cur);
  98 }
  99 
 100 static void s3c_cpufreq_show(const char *pfx,
 101                                  struct s3c_cpufreq_config *cfg)
 102 {
 103         s3c_freq_dbg("%s: Fvco=%u, F=%lu, A=%lu, H=%lu (%u), P=%lu (%u)\n",
 104                      pfx, cfg->pll.frequency, cfg->freq.fclk, cfg->freq.armclk,
 105                      cfg->freq.hclk, cfg->divs.h_divisor,
 106                      cfg->freq.pclk, cfg->divs.p_divisor);
 107 }
 108 
 109 /* functions to wrapper the driver info calls to do the cpu specific work */
 110 
 111 static void s3c_cpufreq_setio(struct s3c_cpufreq_config *cfg)
 112 {
 113         if (cfg->info->set_iotiming)
 114                 (cfg->info->set_iotiming)(cfg, &s3c24xx_iotiming);
 115 }
 116 
 117 static int s3c_cpufreq_calcio(struct s3c_cpufreq_config *cfg)
 118 {
 119         if (cfg->info->calc_iotiming)
 120                 return (cfg->info->calc_iotiming)(cfg, &s3c24xx_iotiming);
 121 
 122         return 0;
 123 }
 124 
 125 static void s3c_cpufreq_setrefresh(struct s3c_cpufreq_config *cfg)
 126 {
 127         (cfg->info->set_refresh)(cfg);
 128 }
 129 
 130 static void s3c_cpufreq_setdivs(struct s3c_cpufreq_config *cfg)
 131 {
 132         (cfg->info->set_divs)(cfg);
 133 }
 134 
 135 static int s3c_cpufreq_calcdivs(struct s3c_cpufreq_config *cfg)
 136 {
 137         return (cfg->info->calc_divs)(cfg);
 138 }
 139 
 140 static void s3c_cpufreq_setfvco(struct s3c_cpufreq_config *cfg)
 141 {
 142         cfg->mpll = _clk_mpll;
 143         (cfg->info->set_fvco)(cfg);
 144 }
 145 
 146 static inline void s3c_cpufreq_updateclk(struct clk *clk,
 147                                          unsigned int freq)
 148 {
 149         clk_set_rate(clk, freq);
 150 }
 151 
 152 static int s3c_cpufreq_settarget(struct cpufreq_policy *policy,
 153                                  unsigned int target_freq,
 154                                  struct cpufreq_frequency_table *pll)
 155 {
 156         struct s3c_cpufreq_freqs freqs;
 157         struct s3c_cpufreq_config cpu_new;
 158         unsigned long flags;
 159 
 160         cpu_new = cpu_cur;  /* copy new from current */
 161 
 162         s3c_cpufreq_show("cur", &cpu_cur);
 163 
 164         /* TODO - check for DMA currently outstanding */
 165 
 166         cpu_new.pll = pll ? *pll : cpu_cur.pll;
 167 
 168         if (pll)
 169                 freqs.pll_changing = 1;
 170 
 171         /* update our frequencies */
 172 
 173         cpu_new.freq.armclk = target_freq;
 174         cpu_new.freq.fclk = cpu_new.pll.frequency;
 175 
 176         if (s3c_cpufreq_calcdivs(&cpu_new) < 0) {
 177                 pr_err("no divisors for %d\n", target_freq);
 178                 goto err_notpossible;
 179         }
 180 
 181         s3c_freq_dbg("%s: got divs\n", __func__);
 182 
 183         s3c_cpufreq_calc(&cpu_new);
 184 
 185         s3c_freq_dbg("%s: calculated frequencies for new\n", __func__);
 186 
 187         if (cpu_new.freq.hclk != cpu_cur.freq.hclk) {
 188                 if (s3c_cpufreq_calcio(&cpu_new) < 0) {
 189                         pr_err("%s: no IO timings\n", __func__);
 190                         goto err_notpossible;
 191                 }
 192         }
 193 
 194         s3c_cpufreq_show("new", &cpu_new);
 195 
 196         /* setup our cpufreq parameters */
 197 
 198         freqs.old = cpu_cur.freq;
 199         freqs.new = cpu_new.freq;
 200 
 201         freqs.freqs.old = cpu_cur.freq.armclk / 1000;
 202         freqs.freqs.new = cpu_new.freq.armclk / 1000;
 203 
 204         /* update f/h/p clock settings before we issue the change
 205          * notification, so that drivers do not need to do anything
 206          * special if they want to recalculate on CPUFREQ_PRECHANGE. */
 207 
 208         s3c_cpufreq_updateclk(_clk_mpll, cpu_new.pll.frequency);
 209         s3c_cpufreq_updateclk(clk_fclk, cpu_new.freq.fclk);
 210         s3c_cpufreq_updateclk(clk_hclk, cpu_new.freq.hclk);
 211         s3c_cpufreq_updateclk(clk_pclk, cpu_new.freq.pclk);
 212 
 213         /* start the frequency change */
 214         cpufreq_freq_transition_begin(policy, &freqs.freqs);
 215 
 216         /* If hclk is staying the same, then we do not need to
 217          * re-write the IO or the refresh timings whilst we are changing
 218          * speed. */
 219 
 220         local_irq_save(flags);
 221 
 222         /* is our memory clock slowing down? */
 223         if (cpu_new.freq.hclk < cpu_cur.freq.hclk) {
 224                 s3c_cpufreq_setrefresh(&cpu_new);
 225                 s3c_cpufreq_setio(&cpu_new);
 226         }
 227 
 228         if (cpu_new.freq.fclk == cpu_cur.freq.fclk) {
 229                 /* not changing PLL, just set the divisors */
 230 
 231                 s3c_cpufreq_setdivs(&cpu_new);
 232         } else {
 233                 if (cpu_new.freq.fclk < cpu_cur.freq.fclk) {
 234                         /* slow the cpu down, then set divisors */
 235 
 236                         s3c_cpufreq_setfvco(&cpu_new);
 237                         s3c_cpufreq_setdivs(&cpu_new);
 238                 } else {
 239                         /* set the divisors, then speed up */
 240 
 241                         s3c_cpufreq_setdivs(&cpu_new);
 242                         s3c_cpufreq_setfvco(&cpu_new);
 243                 }
 244         }
 245 
 246         /* did our memory clock speed up */
 247         if (cpu_new.freq.hclk > cpu_cur.freq.hclk) {
 248                 s3c_cpufreq_setrefresh(&cpu_new);
 249                 s3c_cpufreq_setio(&cpu_new);
 250         }
 251 
 252         /* update our current settings */
 253         cpu_cur = cpu_new;
 254 
 255         local_irq_restore(flags);
 256 
 257         /* notify everyone we've done this */
 258         cpufreq_freq_transition_end(policy, &freqs.freqs, 0);
 259 
 260         s3c_freq_dbg("%s: finished\n", __func__);
 261         return 0;
 262 
 263  err_notpossible:
 264         pr_err("no compatible settings for %d\n", target_freq);
 265         return -EINVAL;
 266 }
 267 
 268 /* s3c_cpufreq_target
 269  *
 270  * called by the cpufreq core to adjust the frequency that the CPU
 271  * is currently running at.
 272  */
 273 
 274 static int s3c_cpufreq_target(struct cpufreq_policy *policy,
 275                               unsigned int target_freq,
 276                               unsigned int relation)
 277 {
 278         struct cpufreq_frequency_table *pll;
 279         unsigned int index;
 280 
 281         /* avoid repeated calls which cause a needless amout of duplicated
 282          * logging output (and CPU time as the calculation process is
 283          * done) */
 284         if (target_freq == last_target)
 285                 return 0;
 286 
 287         last_target = target_freq;
 288 
 289         s3c_freq_dbg("%s: policy %p, target %u, relation %u\n",
 290                      __func__, policy, target_freq, relation);
 291 
 292         if (ftab) {
 293                 index = cpufreq_frequency_table_target(policy, target_freq,
 294                                                        relation);
 295 
 296                 s3c_freq_dbg("%s: adjust %d to entry %d (%u)\n", __func__,
 297                              target_freq, index, ftab[index].frequency);
 298                 target_freq = ftab[index].frequency;
 299         }
 300 
 301         target_freq *= 1000;  /* convert target to Hz */
 302 
 303         /* find the settings for our new frequency */
 304 
 305         if (!pll_reg || cpu_cur.lock_pll) {
 306                 /* either we've not got any PLL values, or we've locked
 307                  * to the current one. */
 308                 pll = NULL;
 309         } else {
 310                 struct cpufreq_policy tmp_policy;
 311 
 312                 /* we keep the cpu pll table in Hz, to ensure we get an
 313                  * accurate value for the PLL output. */
 314 
 315                 tmp_policy.min = policy->min * 1000;
 316                 tmp_policy.max = policy->max * 1000;
 317                 tmp_policy.cpu = policy->cpu;
 318                 tmp_policy.freq_table = pll_reg;
 319 
 320                 /* cpufreq_frequency_table_target returns the index
 321                  * of the table entry, not the value of
 322                  * the table entry's index field. */
 323 
 324                 index = cpufreq_frequency_table_target(&tmp_policy, target_freq,
 325                                                        relation);
 326                 pll = pll_reg + index;
 327 
 328                 s3c_freq_dbg("%s: target %u => %u\n",
 329                              __func__, target_freq, pll->frequency);
 330 
 331                 target_freq = pll->frequency;
 332         }
 333 
 334         return s3c_cpufreq_settarget(policy, target_freq, pll);
 335 }
 336 
 337 struct clk *s3c_cpufreq_clk_get(struct device *dev, const char *name)
 338 {
 339         struct clk *clk;
 340 
 341         clk = clk_get(dev, name);
 342         if (IS_ERR(clk))
 343                 pr_err("failed to get clock '%s'\n", name);
 344 
 345         return clk;
 346 }
 347 
 348 static int s3c_cpufreq_init(struct cpufreq_policy *policy)
 349 {
 350         policy->clk = clk_arm;
 351         policy->cpuinfo.transition_latency = cpu_cur.info->latency;
 352         policy->freq_table = ftab;
 353 
 354         return 0;
 355 }
 356 
 357 static int __init s3c_cpufreq_initclks(void)
 358 {
 359         _clk_mpll = s3c_cpufreq_clk_get(NULL, "mpll");
 360         _clk_xtal = s3c_cpufreq_clk_get(NULL, "xtal");
 361         clk_fclk = s3c_cpufreq_clk_get(NULL, "fclk");
 362         clk_hclk = s3c_cpufreq_clk_get(NULL, "hclk");
 363         clk_pclk = s3c_cpufreq_clk_get(NULL, "pclk");
 364         clk_arm = s3c_cpufreq_clk_get(NULL, "armclk");
 365 
 366         if (IS_ERR(clk_fclk) || IS_ERR(clk_hclk) || IS_ERR(clk_pclk) ||
 367             IS_ERR(_clk_mpll) || IS_ERR(clk_arm) || IS_ERR(_clk_xtal)) {
 368                 pr_err("%s: could not get clock(s)\n", __func__);
 369                 return -ENOENT;
 370         }
 371 
 372         pr_info("%s: clocks f=%lu,h=%lu,p=%lu,a=%lu\n",
 373                 __func__,
 374                 clk_get_rate(clk_fclk) / 1000,
 375                 clk_get_rate(clk_hclk) / 1000,
 376                 clk_get_rate(clk_pclk) / 1000,
 377                 clk_get_rate(clk_arm) / 1000);
 378 
 379         return 0;
 380 }
 381 
 382 #ifdef CONFIG_PM
 383 static struct cpufreq_frequency_table suspend_pll;
 384 static unsigned int suspend_freq;
 385 
 386 static int s3c_cpufreq_suspend(struct cpufreq_policy *policy)
 387 {
 388         suspend_pll.frequency = clk_get_rate(_clk_mpll);
 389         suspend_pll.driver_data = __raw_readl(S3C2410_MPLLCON);
 390         suspend_freq = clk_get_rate(clk_arm);
 391 
 392         return 0;
 393 }
 394 
 395 static int s3c_cpufreq_resume(struct cpufreq_policy *policy)
 396 {
 397         int ret;
 398 
 399         s3c_freq_dbg("%s: resuming with policy %p\n", __func__, policy);
 400 
 401         last_target = ~0;       /* invalidate last_target setting */
 402 
 403         /* whilst we will be called later on, we try and re-set the
 404          * cpu frequencies as soon as possible so that we do not end
 405          * up resuming devices and then immediately having to re-set
 406          * a number of settings once these devices have restarted.
 407          *
 408          * as a note, it is expected devices are not used until they
 409          * have been un-suspended and at that time they should have
 410          * used the updated clock settings.
 411          */
 412 
 413         ret = s3c_cpufreq_settarget(NULL, suspend_freq, &suspend_pll);
 414         if (ret) {
 415                 pr_err("%s: failed to reset pll/freq\n", __func__);
 416                 return ret;
 417         }
 418 
 419         return 0;
 420 }
 421 #else
 422 #define s3c_cpufreq_resume NULL
 423 #define s3c_cpufreq_suspend NULL
 424 #endif
 425 
 426 static struct cpufreq_driver s3c24xx_driver = {
 427         .flags          = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK,
 428         .target         = s3c_cpufreq_target,
 429         .get            = cpufreq_generic_get,
 430         .init           = s3c_cpufreq_init,
 431         .suspend        = s3c_cpufreq_suspend,
 432         .resume         = s3c_cpufreq_resume,
 433         .name           = "s3c24xx",
 434 };
 435 
 436 
 437 int s3c_cpufreq_register(struct s3c_cpufreq_info *info)
 438 {
 439         if (!info || !info->name) {
 440                 pr_err("%s: failed to pass valid information\n", __func__);
 441                 return -EINVAL;
 442         }
 443 
 444         pr_info("S3C24XX CPU Frequency driver, %s cpu support\n",
 445                 info->name);
 446 
 447         /* check our driver info has valid data */
 448 
 449         BUG_ON(info->set_refresh == NULL);
 450         BUG_ON(info->set_divs == NULL);
 451         BUG_ON(info->calc_divs == NULL);
 452 
 453         /* info->set_fvco is optional, depending on whether there
 454          * is a need to set the clock code. */
 455 
 456         cpu_cur.info = info;
 457 
 458         /* Note, driver registering should probably update locktime */
 459 
 460         return 0;
 461 }
 462 
 463 int __init s3c_cpufreq_setboard(struct s3c_cpufreq_board *board)
 464 {
 465         struct s3c_cpufreq_board *ours;
 466 
 467         if (!board) {
 468                 pr_info("%s: no board data\n", __func__);
 469                 return -EINVAL;
 470         }
 471 
 472         /* Copy the board information so that each board can make this
 473          * initdata. */
 474 
 475         ours = kzalloc(sizeof(*ours), GFP_KERNEL);
 476         if (!ours)
 477                 return -ENOMEM;
 478 
 479         *ours = *board;
 480         cpu_cur.board = ours;
 481 
 482         return 0;
 483 }
 484 
 485 static int __init s3c_cpufreq_auto_io(void)
 486 {
 487         int ret;
 488 
 489         if (!cpu_cur.info->get_iotiming) {
 490                 pr_err("%s: get_iotiming undefined\n", __func__);
 491                 return -ENOENT;
 492         }
 493 
 494         pr_info("%s: working out IO settings\n", __func__);
 495 
 496         ret = (cpu_cur.info->get_iotiming)(&cpu_cur, &s3c24xx_iotiming);
 497         if (ret)
 498                 pr_err("%s: failed to get timings\n", __func__);
 499 
 500         return ret;
 501 }
 502 
 503 /* if one or is zero, then return the other, otherwise return the min */
 504 #define do_min(_a, _b) ((_a) == 0 ? (_b) : (_b) == 0 ? (_a) : min(_a, _b))
 505 
 506 /**
 507  * s3c_cpufreq_freq_min - find the minimum settings for the given freq.
 508  * @dst: The destination structure
 509  * @a: One argument.
 510  * @b: The other argument.
 511  *
 512  * Create a minimum of each frequency entry in the 'struct s3c_freq',
 513  * unless the entry is zero when it is ignored and the non-zero argument
 514  * used.
 515  */
 516 static void s3c_cpufreq_freq_min(struct s3c_freq *dst,
 517                                  struct s3c_freq *a, struct s3c_freq *b)
 518 {
 519         dst->fclk = do_min(a->fclk, b->fclk);
 520         dst->hclk = do_min(a->hclk, b->hclk);
 521         dst->pclk = do_min(a->pclk, b->pclk);
 522         dst->armclk = do_min(a->armclk, b->armclk);
 523 }
 524 
 525 static inline u32 calc_locktime(u32 freq, u32 time_us)
 526 {
 527         u32 result;
 528 
 529         result = freq * time_us;
 530         result = DIV_ROUND_UP(result, 1000 * 1000);
 531 
 532         return result;
 533 }
 534 
 535 static void s3c_cpufreq_update_loctkime(void)
 536 {
 537         unsigned int bits = cpu_cur.info->locktime_bits;
 538         u32 rate = (u32)clk_get_rate(_clk_xtal);
 539         u32 val;
 540 
 541         if (bits == 0) {
 542                 WARN_ON(1);
 543                 return;
 544         }
 545 
 546         val = calc_locktime(rate, cpu_cur.info->locktime_u) << bits;
 547         val |= calc_locktime(rate, cpu_cur.info->locktime_m);
 548 
 549         pr_info("%s: new locktime is 0x%08x\n", __func__, val);
 550         __raw_writel(val, S3C2410_LOCKTIME);
 551 }
 552 
 553 static int s3c_cpufreq_build_freq(void)
 554 {
 555         int size, ret;
 556 
 557         kfree(ftab);
 558 
 559         size = cpu_cur.info->calc_freqtable(&cpu_cur, NULL, 0);
 560         size++;
 561 
 562         ftab = kcalloc(size, sizeof(*ftab), GFP_KERNEL);
 563         if (!ftab)
 564                 return -ENOMEM;
 565 
 566         ftab_size = size;
 567 
 568         ret = cpu_cur.info->calc_freqtable(&cpu_cur, ftab, size);
 569         s3c_cpufreq_addfreq(ftab, ret, size, CPUFREQ_TABLE_END);
 570 
 571         return 0;
 572 }
 573 
 574 static int __init s3c_cpufreq_initcall(void)
 575 {
 576         int ret = 0;
 577 
 578         if (cpu_cur.info && cpu_cur.board) {
 579                 ret = s3c_cpufreq_initclks();
 580                 if (ret)
 581                         goto out;
 582 
 583                 /* get current settings */
 584                 s3c_cpufreq_getcur(&cpu_cur);
 585                 s3c_cpufreq_show("cur", &cpu_cur);
 586 
 587                 if (cpu_cur.board->auto_io) {
 588                         ret = s3c_cpufreq_auto_io();
 589                         if (ret) {
 590                                 pr_err("%s: failed to get io timing\n",
 591                                        __func__);
 592                                 goto out;
 593                         }
 594                 }
 595 
 596                 if (cpu_cur.board->need_io && !cpu_cur.info->set_iotiming) {
 597                         pr_err("%s: no IO support registered\n", __func__);
 598                         ret = -EINVAL;
 599                         goto out;
 600                 }
 601 
 602                 if (!cpu_cur.info->need_pll)
 603                         cpu_cur.lock_pll = 1;
 604 
 605                 s3c_cpufreq_update_loctkime();
 606 
 607                 s3c_cpufreq_freq_min(&cpu_cur.max, &cpu_cur.board->max,
 608                                      &cpu_cur.info->max);
 609 
 610                 if (cpu_cur.info->calc_freqtable)
 611                         s3c_cpufreq_build_freq();
 612 
 613                 ret = cpufreq_register_driver(&s3c24xx_driver);
 614         }
 615 
 616  out:
 617         return ret;
 618 }
 619 
 620 late_initcall(s3c_cpufreq_initcall);
 621 
 622 /**
 623  * s3c_plltab_register - register CPU PLL table.
 624  * @plls: The list of PLL entries.
 625  * @plls_no: The size of the PLL entries @plls.
 626  *
 627  * Register the given set of PLLs with the system.
 628  */
 629 int s3c_plltab_register(struct cpufreq_frequency_table *plls,
 630                                unsigned int plls_no)
 631 {
 632         struct cpufreq_frequency_table *vals;
 633         unsigned int size;
 634 
 635         size = sizeof(*vals) * (plls_no + 1);
 636 
 637         vals = kzalloc(size, GFP_KERNEL);
 638         if (vals) {
 639                 memcpy(vals, plls, size);
 640                 pll_reg = vals;
 641 
 642                 /* write a terminating entry, we don't store it in the
 643                  * table that is stored in the kernel */
 644                 vals += plls_no;
 645                 vals->frequency = CPUFREQ_TABLE_END;
 646 
 647                 pr_info("%d PLL entries\n", plls_no);
 648         } else
 649                 pr_err("no memory for PLL tables\n");
 650 
 651         return vals ? 0 : -ENOMEM;
 652 }

/* [<][>][^][v][top][bottom][index][help] */