diff options
Diffstat (limited to 'drivers/cpufreq/cpufreq-cpu0.c')
-rw-r--r-- | drivers/cpufreq/cpufreq-cpu0.c | 119 |
1 files changed, 30 insertions, 89 deletions
diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c index c522a95c0e16..d4585ce2346c 100644 --- a/drivers/cpufreq/cpufreq-cpu0.c +++ b/drivers/cpufreq/cpufreq-cpu0.c | |||
@@ -17,7 +17,7 @@ | |||
17 | #include <linux/err.h> | 17 | #include <linux/err.h> |
18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
19 | #include <linux/of.h> | 19 | #include <linux/of.h> |
20 | #include <linux/opp.h> | 20 | #include <linux/pm_opp.h> |
21 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
22 | #include <linux/regulator/consumer.h> | 22 | #include <linux/regulator/consumer.h> |
23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
@@ -30,73 +30,51 @@ static struct clk *cpu_clk; | |||
30 | static struct regulator *cpu_reg; | 30 | static struct regulator *cpu_reg; |
31 | static struct cpufreq_frequency_table *freq_table; | 31 | static struct cpufreq_frequency_table *freq_table; |
32 | 32 | ||
33 | static int cpu0_verify_speed(struct cpufreq_policy *policy) | ||
34 | { | ||
35 | return cpufreq_frequency_table_verify(policy, freq_table); | ||
36 | } | ||
37 | |||
38 | static unsigned int cpu0_get_speed(unsigned int cpu) | 33 | static unsigned int cpu0_get_speed(unsigned int cpu) |
39 | { | 34 | { |
40 | return clk_get_rate(cpu_clk) / 1000; | 35 | return clk_get_rate(cpu_clk) / 1000; |
41 | } | 36 | } |
42 | 37 | ||
43 | static int cpu0_set_target(struct cpufreq_policy *policy, | 38 | static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index) |
44 | unsigned int target_freq, unsigned int relation) | ||
45 | { | 39 | { |
46 | struct cpufreq_freqs freqs; | 40 | struct dev_pm_opp *opp; |
47 | struct opp *opp; | ||
48 | unsigned long volt = 0, volt_old = 0, tol = 0; | 41 | unsigned long volt = 0, volt_old = 0, tol = 0; |
42 | unsigned int old_freq, new_freq; | ||
49 | long freq_Hz, freq_exact; | 43 | long freq_Hz, freq_exact; |
50 | unsigned int index; | ||
51 | int ret; | 44 | int ret; |
52 | 45 | ||
53 | ret = cpufreq_frequency_table_target(policy, freq_table, target_freq, | ||
54 | relation, &index); | ||
55 | if (ret) { | ||
56 | pr_err("failed to match target freqency %d: %d\n", | ||
57 | target_freq, ret); | ||
58 | return ret; | ||
59 | } | ||
60 | |||
61 | freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000); | 46 | freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000); |
62 | if (freq_Hz < 0) | 47 | if (freq_Hz < 0) |
63 | freq_Hz = freq_table[index].frequency * 1000; | 48 | freq_Hz = freq_table[index].frequency * 1000; |
64 | freq_exact = freq_Hz; | ||
65 | freqs.new = freq_Hz / 1000; | ||
66 | freqs.old = clk_get_rate(cpu_clk) / 1000; | ||
67 | 49 | ||
68 | if (freqs.old == freqs.new) | 50 | freq_exact = freq_Hz; |
69 | return 0; | 51 | new_freq = freq_Hz / 1000; |
70 | 52 | old_freq = clk_get_rate(cpu_clk) / 1000; | |
71 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); | ||
72 | 53 | ||
73 | if (!IS_ERR(cpu_reg)) { | 54 | if (!IS_ERR(cpu_reg)) { |
74 | rcu_read_lock(); | 55 | rcu_read_lock(); |
75 | opp = opp_find_freq_ceil(cpu_dev, &freq_Hz); | 56 | opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_Hz); |
76 | if (IS_ERR(opp)) { | 57 | if (IS_ERR(opp)) { |
77 | rcu_read_unlock(); | 58 | rcu_read_unlock(); |
78 | pr_err("failed to find OPP for %ld\n", freq_Hz); | 59 | pr_err("failed to find OPP for %ld\n", freq_Hz); |
79 | freqs.new = freqs.old; | 60 | return PTR_ERR(opp); |
80 | ret = PTR_ERR(opp); | ||
81 | goto post_notify; | ||
82 | } | 61 | } |
83 | volt = opp_get_voltage(opp); | 62 | volt = dev_pm_opp_get_voltage(opp); |
84 | rcu_read_unlock(); | 63 | rcu_read_unlock(); |
85 | tol = volt * voltage_tolerance / 100; | 64 | tol = volt * voltage_tolerance / 100; |
86 | volt_old = regulator_get_voltage(cpu_reg); | 65 | volt_old = regulator_get_voltage(cpu_reg); |
87 | } | 66 | } |
88 | 67 | ||
89 | pr_debug("%u MHz, %ld mV --> %u MHz, %ld mV\n", | 68 | pr_debug("%u MHz, %ld mV --> %u MHz, %ld mV\n", |
90 | freqs.old / 1000, volt_old ? volt_old / 1000 : -1, | 69 | old_freq / 1000, volt_old ? volt_old / 1000 : -1, |
91 | freqs.new / 1000, volt ? volt / 1000 : -1); | 70 | new_freq / 1000, volt ? volt / 1000 : -1); |
92 | 71 | ||
93 | /* scaling up? scale voltage before frequency */ | 72 | /* scaling up? scale voltage before frequency */ |
94 | if (!IS_ERR(cpu_reg) && freqs.new > freqs.old) { | 73 | if (!IS_ERR(cpu_reg) && new_freq > old_freq) { |
95 | ret = regulator_set_voltage_tol(cpu_reg, volt, tol); | 74 | ret = regulator_set_voltage_tol(cpu_reg, volt, tol); |
96 | if (ret) { | 75 | if (ret) { |
97 | pr_err("failed to scale voltage up: %d\n", ret); | 76 | pr_err("failed to scale voltage up: %d\n", ret); |
98 | freqs.new = freqs.old; | 77 | return ret; |
99 | goto post_notify; | ||
100 | } | 78 | } |
101 | } | 79 | } |
102 | 80 | ||
@@ -105,72 +83,35 @@ static int cpu0_set_target(struct cpufreq_policy *policy, | |||
105 | pr_err("failed to set clock rate: %d\n", ret); | 83 | pr_err("failed to set clock rate: %d\n", ret); |
106 | if (!IS_ERR(cpu_reg)) | 84 | if (!IS_ERR(cpu_reg)) |
107 | regulator_set_voltage_tol(cpu_reg, volt_old, tol); | 85 | regulator_set_voltage_tol(cpu_reg, volt_old, tol); |
108 | freqs.new = freqs.old; | 86 | return ret; |
109 | goto post_notify; | ||
110 | } | 87 | } |
111 | 88 | ||
112 | /* scaling down? scale voltage after frequency */ | 89 | /* scaling down? scale voltage after frequency */ |
113 | if (!IS_ERR(cpu_reg) && freqs.new < freqs.old) { | 90 | if (!IS_ERR(cpu_reg) && new_freq < old_freq) { |
114 | ret = regulator_set_voltage_tol(cpu_reg, volt, tol); | 91 | ret = regulator_set_voltage_tol(cpu_reg, volt, tol); |
115 | if (ret) { | 92 | if (ret) { |
116 | pr_err("failed to scale voltage down: %d\n", ret); | 93 | pr_err("failed to scale voltage down: %d\n", ret); |
117 | clk_set_rate(cpu_clk, freqs.old * 1000); | 94 | clk_set_rate(cpu_clk, old_freq * 1000); |
118 | freqs.new = freqs.old; | ||
119 | } | 95 | } |
120 | } | 96 | } |
121 | 97 | ||
122 | post_notify: | ||
123 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | ||
124 | |||
125 | return ret; | 98 | return ret; |
126 | } | 99 | } |
127 | 100 | ||
128 | static int cpu0_cpufreq_init(struct cpufreq_policy *policy) | 101 | static int cpu0_cpufreq_init(struct cpufreq_policy *policy) |
129 | { | 102 | { |
130 | int ret; | 103 | return cpufreq_generic_init(policy, freq_table, transition_latency); |
131 | |||
132 | ret = cpufreq_frequency_table_cpuinfo(policy, freq_table); | ||
133 | if (ret) { | ||
134 | pr_err("invalid frequency table: %d\n", ret); | ||
135 | return ret; | ||
136 | } | ||
137 | |||
138 | policy->cpuinfo.transition_latency = transition_latency; | ||
139 | policy->cur = clk_get_rate(cpu_clk) / 1000; | ||
140 | |||
141 | /* | ||
142 | * The driver only supports the SMP configuartion where all processors | ||
143 | * share the clock and voltage and clock. Use cpufreq affected_cpus | ||
144 | * interface to have all CPUs scaled together. | ||
145 | */ | ||
146 | cpumask_setall(policy->cpus); | ||
147 | |||
148 | cpufreq_frequency_table_get_attr(freq_table, policy->cpu); | ||
149 | |||
150 | return 0; | ||
151 | } | 104 | } |
152 | 105 | ||
153 | static int cpu0_cpufreq_exit(struct cpufreq_policy *policy) | ||
154 | { | ||
155 | cpufreq_frequency_table_put_attr(policy->cpu); | ||
156 | |||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | static struct freq_attr *cpu0_cpufreq_attr[] = { | ||
161 | &cpufreq_freq_attr_scaling_available_freqs, | ||
162 | NULL, | ||
163 | }; | ||
164 | |||
165 | static struct cpufreq_driver cpu0_cpufreq_driver = { | 106 | static struct cpufreq_driver cpu0_cpufreq_driver = { |
166 | .flags = CPUFREQ_STICKY, | 107 | .flags = CPUFREQ_STICKY, |
167 | .verify = cpu0_verify_speed, | 108 | .verify = cpufreq_generic_frequency_table_verify, |
168 | .target = cpu0_set_target, | 109 | .target_index = cpu0_set_target, |
169 | .get = cpu0_get_speed, | 110 | .get = cpu0_get_speed, |
170 | .init = cpu0_cpufreq_init, | 111 | .init = cpu0_cpufreq_init, |
171 | .exit = cpu0_cpufreq_exit, | 112 | .exit = cpufreq_generic_exit, |
172 | .name = "generic_cpu0", | 113 | .name = "generic_cpu0", |
173 | .attr = cpu0_cpufreq_attr, | 114 | .attr = cpufreq_generic_attr, |
174 | }; | 115 | }; |
175 | 116 | ||
176 | static int cpu0_cpufreq_probe(struct platform_device *pdev) | 117 | static int cpu0_cpufreq_probe(struct platform_device *pdev) |
@@ -218,7 +159,7 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev) | |||
218 | goto out_put_node; | 159 | goto out_put_node; |
219 | } | 160 | } |
220 | 161 | ||
221 | ret = opp_init_cpufreq_table(cpu_dev, &freq_table); | 162 | ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table); |
222 | if (ret) { | 163 | if (ret) { |
223 | pr_err("failed to init cpufreq table: %d\n", ret); | 164 | pr_err("failed to init cpufreq table: %d\n", ret); |
224 | goto out_put_node; | 165 | goto out_put_node; |
@@ -230,7 +171,7 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev) | |||
230 | transition_latency = CPUFREQ_ETERNAL; | 171 | transition_latency = CPUFREQ_ETERNAL; |
231 | 172 | ||
232 | if (!IS_ERR(cpu_reg)) { | 173 | if (!IS_ERR(cpu_reg)) { |
233 | struct opp *opp; | 174 | struct dev_pm_opp *opp; |
234 | unsigned long min_uV, max_uV; | 175 | unsigned long min_uV, max_uV; |
235 | int i; | 176 | int i; |
236 | 177 | ||
@@ -242,12 +183,12 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev) | |||
242 | for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) | 183 | for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) |
243 | ; | 184 | ; |
244 | rcu_read_lock(); | 185 | rcu_read_lock(); |
245 | opp = opp_find_freq_exact(cpu_dev, | 186 | opp = dev_pm_opp_find_freq_exact(cpu_dev, |
246 | freq_table[0].frequency * 1000, true); | 187 | freq_table[0].frequency * 1000, true); |
247 | min_uV = opp_get_voltage(opp); | 188 | min_uV = dev_pm_opp_get_voltage(opp); |
248 | opp = opp_find_freq_exact(cpu_dev, | 189 | opp = dev_pm_opp_find_freq_exact(cpu_dev, |
249 | freq_table[i-1].frequency * 1000, true); | 190 | freq_table[i-1].frequency * 1000, true); |
250 | max_uV = opp_get_voltage(opp); | 191 | max_uV = dev_pm_opp_get_voltage(opp); |
251 | rcu_read_unlock(); | 192 | rcu_read_unlock(); |
252 | ret = regulator_set_voltage_time(cpu_reg, min_uV, max_uV); | 193 | ret = regulator_set_voltage_time(cpu_reg, min_uV, max_uV); |
253 | if (ret > 0) | 194 | if (ret > 0) |
@@ -264,7 +205,7 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev) | |||
264 | return 0; | 205 | return 0; |
265 | 206 | ||
266 | out_free_table: | 207 | out_free_table: |
267 | opp_free_cpufreq_table(cpu_dev, &freq_table); | 208 | dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); |
268 | out_put_node: | 209 | out_put_node: |
269 | of_node_put(np); | 210 | of_node_put(np); |
270 | return ret; | 211 | return ret; |
@@ -273,7 +214,7 @@ out_put_node: | |||
273 | static int cpu0_cpufreq_remove(struct platform_device *pdev) | 214 | static int cpu0_cpufreq_remove(struct platform_device *pdev) |
274 | { | 215 | { |
275 | cpufreq_unregister_driver(&cpu0_cpufreq_driver); | 216 | cpufreq_unregister_driver(&cpu0_cpufreq_driver); |
276 | opp_free_cpufreq_table(cpu_dev, &freq_table); | 217 | dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); |
277 | 218 | ||
278 | return 0; | 219 | return 0; |
279 | } | 220 | } |