0001
0002
0003
0004
0005
0006
0007
0008 #define pr_fmt(fmt) "cpufreq: " fmt
0009
0010 #include <linux/kernel.h>
0011 #include <linux/types.h>
0012 #include <linux/init.h>
0013 #include <linux/cpufreq.h>
0014 #include <linux/clk.h>
0015 #include <linux/err.h>
0016 #include <linux/regulator/consumer.h>
0017 #include <linux/module.h>
0018
0019 static struct regulator *vddarm;
0020 static unsigned long regulator_latency;
0021
0022 struct s3c64xx_dvfs {
0023 unsigned int vddarm_min;
0024 unsigned int vddarm_max;
0025 };
0026
0027 static struct s3c64xx_dvfs s3c64xx_dvfs_table[] = {
0028 [0] = { 1000000, 1150000 },
0029 [1] = { 1050000, 1150000 },
0030 [2] = { 1100000, 1150000 },
0031 [3] = { 1200000, 1350000 },
0032 [4] = { 1300000, 1350000 },
0033 };
0034
0035 static struct cpufreq_frequency_table s3c64xx_freq_table[] = {
0036 { 0, 0, 66000 },
0037 { 0, 0, 100000 },
0038 { 0, 0, 133000 },
0039 { 0, 1, 200000 },
0040 { 0, 1, 222000 },
0041 { 0, 1, 266000 },
0042 { 0, 2, 333000 },
0043 { 0, 2, 400000 },
0044 { 0, 2, 532000 },
0045 { 0, 2, 533000 },
0046 { 0, 3, 667000 },
0047 { 0, 4, 800000 },
0048 { 0, 0, CPUFREQ_TABLE_END },
0049 };
0050
0051 static int s3c64xx_cpufreq_set_target(struct cpufreq_policy *policy,
0052 unsigned int index)
0053 {
0054 struct s3c64xx_dvfs *dvfs;
0055 unsigned int old_freq, new_freq;
0056 int ret;
0057
0058 old_freq = clk_get_rate(policy->clk) / 1000;
0059 new_freq = s3c64xx_freq_table[index].frequency;
0060 dvfs = &s3c64xx_dvfs_table[s3c64xx_freq_table[index].driver_data];
0061
0062 #ifdef CONFIG_REGULATOR
0063 if (vddarm && new_freq > old_freq) {
0064 ret = regulator_set_voltage(vddarm,
0065 dvfs->vddarm_min,
0066 dvfs->vddarm_max);
0067 if (ret != 0) {
0068 pr_err("Failed to set VDDARM for %dkHz: %d\n",
0069 new_freq, ret);
0070 return ret;
0071 }
0072 }
0073 #endif
0074
0075 ret = clk_set_rate(policy->clk, new_freq * 1000);
0076 if (ret < 0) {
0077 pr_err("Failed to set rate %dkHz: %d\n",
0078 new_freq, ret);
0079 return ret;
0080 }
0081
0082 #ifdef CONFIG_REGULATOR
0083 if (vddarm && new_freq < old_freq) {
0084 ret = regulator_set_voltage(vddarm,
0085 dvfs->vddarm_min,
0086 dvfs->vddarm_max);
0087 if (ret != 0) {
0088 pr_err("Failed to set VDDARM for %dkHz: %d\n",
0089 new_freq, ret);
0090 if (clk_set_rate(policy->clk, old_freq * 1000) < 0)
0091 pr_err("Failed to restore original clock rate\n");
0092
0093 return ret;
0094 }
0095 }
0096 #endif
0097
0098 pr_debug("Set actual frequency %lukHz\n",
0099 clk_get_rate(policy->clk) / 1000);
0100
0101 return 0;
0102 }
0103
0104 #ifdef CONFIG_REGULATOR
0105 static void s3c64xx_cpufreq_config_regulator(void)
0106 {
0107 int count, v, i, found;
0108 struct cpufreq_frequency_table *freq;
0109 struct s3c64xx_dvfs *dvfs;
0110
0111 count = regulator_count_voltages(vddarm);
0112 if (count < 0) {
0113 pr_err("Unable to check supported voltages\n");
0114 }
0115
0116 if (!count)
0117 goto out;
0118
0119 cpufreq_for_each_valid_entry(freq, s3c64xx_freq_table) {
0120 dvfs = &s3c64xx_dvfs_table[freq->driver_data];
0121 found = 0;
0122
0123 for (i = 0; i < count; i++) {
0124 v = regulator_list_voltage(vddarm, i);
0125 if (v >= dvfs->vddarm_min && v <= dvfs->vddarm_max)
0126 found = 1;
0127 }
0128
0129 if (!found) {
0130 pr_debug("%dkHz unsupported by regulator\n",
0131 freq->frequency);
0132 freq->frequency = CPUFREQ_ENTRY_INVALID;
0133 }
0134 }
0135
0136 out:
0137
0138
0139 regulator_latency = 1 * 1000 * 1000;
0140 }
0141 #endif
0142
0143 static int s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy)
0144 {
0145 struct cpufreq_frequency_table *freq;
0146
0147 if (policy->cpu != 0)
0148 return -EINVAL;
0149
0150 policy->clk = clk_get(NULL, "armclk");
0151 if (IS_ERR(policy->clk)) {
0152 pr_err("Unable to obtain ARMCLK: %ld\n",
0153 PTR_ERR(policy->clk));
0154 return PTR_ERR(policy->clk);
0155 }
0156
0157 #ifdef CONFIG_REGULATOR
0158 vddarm = regulator_get(NULL, "vddarm");
0159 if (IS_ERR(vddarm)) {
0160 pr_err("Failed to obtain VDDARM: %ld\n", PTR_ERR(vddarm));
0161 pr_err("Only frequency scaling available\n");
0162 vddarm = NULL;
0163 } else {
0164 s3c64xx_cpufreq_config_regulator();
0165 }
0166 #endif
0167
0168 cpufreq_for_each_entry(freq, s3c64xx_freq_table) {
0169 unsigned long r;
0170
0171
0172 r = clk_round_rate(policy->clk, freq->frequency * 1000);
0173 r /= 1000;
0174 if (r != freq->frequency) {
0175 pr_debug("%dkHz unsupported by clock\n",
0176 freq->frequency);
0177 freq->frequency = CPUFREQ_ENTRY_INVALID;
0178 }
0179
0180
0181
0182 if (!vddarm && freq->frequency > clk_get_rate(policy->clk) / 1000)
0183 freq->frequency = CPUFREQ_ENTRY_INVALID;
0184 }
0185
0186
0187
0188
0189
0190 cpufreq_generic_init(policy, s3c64xx_freq_table,
0191 (500 * 1000) + regulator_latency);
0192 return 0;
0193 }
0194
0195 static struct cpufreq_driver s3c64xx_cpufreq_driver = {
0196 .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK,
0197 .verify = cpufreq_generic_frequency_table_verify,
0198 .target_index = s3c64xx_cpufreq_set_target,
0199 .get = cpufreq_generic_get,
0200 .init = s3c64xx_cpufreq_driver_init,
0201 .name = "s3c",
0202 };
0203
0204 static int __init s3c64xx_cpufreq_init(void)
0205 {
0206 return cpufreq_register_driver(&s3c64xx_cpufreq_driver);
0207 }
0208 module_init(s3c64xx_cpufreq_init);