in s3c2416-cpufreq.c [343:476]
static int s3c2416_cpufreq_driver_init(struct cpufreq_policy *policy)
{
struct s3c2416_data *s3c_freq = &s3c2416_cpufreq;
struct cpufreq_frequency_table *pos;
struct clk *msysclk;
unsigned long rate;
int ret;
if (policy->cpu != 0)
return -EINVAL;
msysclk = clk_get(NULL, "msysclk");
if (IS_ERR(msysclk)) {
ret = PTR_ERR(msysclk);
pr_err("cpufreq: Unable to obtain msysclk: %d\n", ret);
return ret;
}
/*
* S3C2416 and S3C2450 share the same processor-ID and also provide no
* other means to distinguish them other than through the rate of
* msysclk. On S3C2416 msysclk runs at 800MHz and on S3C2450 at 533MHz.
*/
rate = clk_get_rate(msysclk);
if (rate == 800 * 1000 * 1000) {
pr_info("cpufreq: msysclk running at %lukHz, using S3C2416 frequency table\n",
rate / 1000);
s3c_freq->freq_table = s3c2416_freq_table;
policy->cpuinfo.max_freq = 400000;
} else if (rate / 1000 == 534000) {
pr_info("cpufreq: msysclk running at %lukHz, using S3C2450 frequency table\n",
rate / 1000);
s3c_freq->freq_table = s3c2450_freq_table;
policy->cpuinfo.max_freq = 534000;
}
/* not needed anymore */
clk_put(msysclk);
if (s3c_freq->freq_table == NULL) {
pr_err("cpufreq: No frequency information for this CPU, msysclk at %lukHz\n",
rate / 1000);
return -ENODEV;
}
s3c_freq->is_dvs = 0;
s3c_freq->armdiv = clk_get(NULL, "armdiv");
if (IS_ERR(s3c_freq->armdiv)) {
ret = PTR_ERR(s3c_freq->armdiv);
pr_err("cpufreq: Unable to obtain ARMDIV: %d\n", ret);
return ret;
}
s3c_freq->hclk = clk_get(NULL, "hclk");
if (IS_ERR(s3c_freq->hclk)) {
ret = PTR_ERR(s3c_freq->hclk);
pr_err("cpufreq: Unable to obtain HCLK: %d\n", ret);
goto err_hclk;
}
/* chech hclk rate, we only support the common 133MHz for now
* hclk could also run at 66MHz, but this not often used
*/
rate = clk_get_rate(s3c_freq->hclk);
if (rate < 133 * 1000 * 1000) {
pr_err("cpufreq: HCLK not at 133MHz\n");
ret = -EINVAL;
goto err_armclk;
}
s3c_freq->armclk = clk_get(NULL, "armclk");
if (IS_ERR(s3c_freq->armclk)) {
ret = PTR_ERR(s3c_freq->armclk);
pr_err("cpufreq: Unable to obtain ARMCLK: %d\n", ret);
goto err_armclk;
}
#ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
s3c_freq->vddarm = regulator_get(NULL, "vddarm");
if (IS_ERR(s3c_freq->vddarm)) {
ret = PTR_ERR(s3c_freq->vddarm);
pr_err("cpufreq: Failed to obtain VDDARM: %d\n", ret);
goto err_vddarm;
}
s3c2416_cpufreq_cfg_regulator(s3c_freq);
#else
s3c_freq->regulator_latency = 0;
#endif
cpufreq_for_each_entry(pos, s3c_freq->freq_table) {
/* special handling for dvs mode */
if (pos->driver_data == 0) {
if (!s3c_freq->hclk) {
pr_debug("cpufreq: %dkHz unsupported as it would need unavailable dvs mode\n",
pos->frequency);
pos->frequency = CPUFREQ_ENTRY_INVALID;
} else {
continue;
}
}
/* Check for frequencies we can generate */
rate = clk_round_rate(s3c_freq->armdiv,
pos->frequency * 1000);
rate /= 1000;
if (rate != pos->frequency) {
pr_debug("cpufreq: %dkHz unsupported by clock (clk_round_rate return %lu)\n",
pos->frequency, rate);
pos->frequency = CPUFREQ_ENTRY_INVALID;
}
}
/* Datasheet says PLL stabalisation time must be at least 300us,
* so but add some fudge. (reference in LOCKCON0 register description)
*/
cpufreq_generic_init(policy, s3c_freq->freq_table,
(500 * 1000) + s3c_freq->regulator_latency);
register_reboot_notifier(&s3c2416_cpufreq_reboot_notifier);
return 0;
#ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
err_vddarm:
clk_put(s3c_freq->armclk);
#endif
err_armclk:
clk_put(s3c_freq->hclk);
err_hclk:
clk_put(s3c_freq->armdiv);
return ret;
}