diff options
Diffstat (limited to 'drivers/cpufreq/s5pv210-cpufreq.c')
-rw-r--r-- | drivers/cpufreq/s5pv210-cpufreq.c | 86 |
1 files changed, 21 insertions, 65 deletions
diff --git a/drivers/cpufreq/s5pv210-cpufreq.c b/drivers/cpufreq/s5pv210-cpufreq.c index 5c7757073793..e3973dae28a7 100644 --- a/drivers/cpufreq/s5pv210-cpufreq.c +++ b/drivers/cpufreq/s5pv210-cpufreq.c | |||
@@ -26,7 +26,6 @@ | |||
26 | static struct clk *cpu_clk; | 26 | static struct clk *cpu_clk; |
27 | static struct clk *dmc0_clk; | 27 | static struct clk *dmc0_clk; |
28 | static struct clk *dmc1_clk; | 28 | static struct clk *dmc1_clk; |
29 | static struct cpufreq_freqs freqs; | ||
30 | static DEFINE_MUTEX(set_freq_lock); | 29 | static DEFINE_MUTEX(set_freq_lock); |
31 | 30 | ||
32 | /* APLL M,P,S values for 1G/800Mhz */ | 31 | /* APLL M,P,S values for 1G/800Mhz */ |
@@ -36,16 +35,7 @@ static DEFINE_MUTEX(set_freq_lock); | |||
36 | /* Use 800MHz when entering sleep mode */ | 35 | /* Use 800MHz when entering sleep mode */ |
37 | #define SLEEP_FREQ (800 * 1000) | 36 | #define SLEEP_FREQ (800 * 1000) |
38 | 37 | ||
39 | /* | 38 | /* Tracks if cpu freqency can be updated anymore */ |
40 | * relation has an additional symantics other than the standard of cpufreq | ||
41 | * DISALBE_FURTHER_CPUFREQ: disable further access to target | ||
42 | * ENABLE_FURTUER_CPUFREQ: enable access to target | ||
43 | */ | ||
44 | enum cpufreq_access { | ||
45 | DISABLE_FURTHER_CPUFREQ = 0x10, | ||
46 | ENABLE_FURTHER_CPUFREQ = 0x20, | ||
47 | }; | ||
48 | |||
49 | static bool no_cpufreq_access; | 39 | static bool no_cpufreq_access; |
50 | 40 | ||
51 | /* | 41 | /* |
@@ -174,14 +164,6 @@ static void s5pv210_set_refresh(enum s5pv210_dmc_port ch, unsigned long freq) | |||
174 | __raw_writel(tmp1, reg); | 164 | __raw_writel(tmp1, reg); |
175 | } | 165 | } |
176 | 166 | ||
177 | static int s5pv210_verify_speed(struct cpufreq_policy *policy) | ||
178 | { | ||
179 | if (policy->cpu) | ||
180 | return -EINVAL; | ||
181 | |||
182 | return cpufreq_frequency_table_verify(policy, s5pv210_freq_table); | ||
183 | } | ||
184 | |||
185 | static unsigned int s5pv210_getspeed(unsigned int cpu) | 167 | static unsigned int s5pv210_getspeed(unsigned int cpu) |
186 | { | 168 | { |
187 | if (cpu) | 169 | if (cpu) |
@@ -190,22 +172,18 @@ static unsigned int s5pv210_getspeed(unsigned int cpu) | |||
190 | return clk_get_rate(cpu_clk) / 1000; | 172 | return clk_get_rate(cpu_clk) / 1000; |
191 | } | 173 | } |
192 | 174 | ||
193 | static int s5pv210_target(struct cpufreq_policy *policy, | 175 | static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index) |
194 | unsigned int target_freq, | ||
195 | unsigned int relation) | ||
196 | { | 176 | { |
197 | unsigned long reg; | 177 | unsigned long reg; |
198 | unsigned int index, priv_index; | 178 | unsigned int priv_index; |
199 | unsigned int pll_changing = 0; | 179 | unsigned int pll_changing = 0; |
200 | unsigned int bus_speed_changing = 0; | 180 | unsigned int bus_speed_changing = 0; |
181 | unsigned int old_freq, new_freq; | ||
201 | int arm_volt, int_volt; | 182 | int arm_volt, int_volt; |
202 | int ret = 0; | 183 | int ret = 0; |
203 | 184 | ||
204 | mutex_lock(&set_freq_lock); | 185 | mutex_lock(&set_freq_lock); |
205 | 186 | ||
206 | if (relation & ENABLE_FURTHER_CPUFREQ) | ||
207 | no_cpufreq_access = false; | ||
208 | |||
209 | if (no_cpufreq_access) { | 187 | if (no_cpufreq_access) { |
210 | #ifdef CONFIG_PM_VERBOSE | 188 | #ifdef CONFIG_PM_VERBOSE |
211 | pr_err("%s:%d denied access to %s as it is disabled" | 189 | pr_err("%s:%d denied access to %s as it is disabled" |
@@ -215,27 +193,13 @@ static int s5pv210_target(struct cpufreq_policy *policy, | |||
215 | goto exit; | 193 | goto exit; |
216 | } | 194 | } |
217 | 195 | ||
218 | if (relation & DISABLE_FURTHER_CPUFREQ) | 196 | old_freq = s5pv210_getspeed(0); |
219 | no_cpufreq_access = true; | 197 | new_freq = s5pv210_freq_table[index].frequency; |
220 | |||
221 | relation &= ~(ENABLE_FURTHER_CPUFREQ | DISABLE_FURTHER_CPUFREQ); | ||
222 | |||
223 | freqs.old = s5pv210_getspeed(0); | ||
224 | |||
225 | if (cpufreq_frequency_table_target(policy, s5pv210_freq_table, | ||
226 | target_freq, relation, &index)) { | ||
227 | ret = -EINVAL; | ||
228 | goto exit; | ||
229 | } | ||
230 | |||
231 | freqs.new = s5pv210_freq_table[index].frequency; | ||
232 | |||
233 | if (freqs.new == freqs.old) | ||
234 | goto exit; | ||
235 | 198 | ||
236 | /* Finding current running level index */ | 199 | /* Finding current running level index */ |
237 | if (cpufreq_frequency_table_target(policy, s5pv210_freq_table, | 200 | if (cpufreq_frequency_table_target(policy, s5pv210_freq_table, |
238 | freqs.old, relation, &priv_index)) { | 201 | old_freq, CPUFREQ_RELATION_H, |
202 | &priv_index)) { | ||
239 | ret = -EINVAL; | 203 | ret = -EINVAL; |
240 | goto exit; | 204 | goto exit; |
241 | } | 205 | } |
@@ -243,7 +207,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, | |||
243 | arm_volt = dvs_conf[index].arm_volt; | 207 | arm_volt = dvs_conf[index].arm_volt; |
244 | int_volt = dvs_conf[index].int_volt; | 208 | int_volt = dvs_conf[index].int_volt; |
245 | 209 | ||
246 | if (freqs.new > freqs.old) { | 210 | if (new_freq > old_freq) { |
247 | ret = regulator_set_voltage(arm_regulator, | 211 | ret = regulator_set_voltage(arm_regulator, |
248 | arm_volt, arm_volt_max); | 212 | arm_volt, arm_volt_max); |
249 | if (ret) | 213 | if (ret) |
@@ -255,8 +219,6 @@ static int s5pv210_target(struct cpufreq_policy *policy, | |||
255 | goto exit; | 219 | goto exit; |
256 | } | 220 | } |
257 | 221 | ||
258 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); | ||
259 | |||
260 | /* Check if there need to change PLL */ | 222 | /* Check if there need to change PLL */ |
261 | if ((index == L0) || (priv_index == L0)) | 223 | if ((index == L0) || (priv_index == L0)) |
262 | pll_changing = 1; | 224 | pll_changing = 1; |
@@ -467,9 +429,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, | |||
467 | } | 429 | } |
468 | } | 430 | } |
469 | 431 | ||
470 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | 432 | if (new_freq < old_freq) { |
471 | |||
472 | if (freqs.new < freqs.old) { | ||
473 | regulator_set_voltage(int_regulator, | 433 | regulator_set_voltage(int_regulator, |
474 | int_volt, int_volt_max); | 434 | int_volt, int_volt_max); |
475 | 435 | ||
@@ -551,13 +511,7 @@ static int __init s5pv210_cpu_init(struct cpufreq_policy *policy) | |||
551 | s5pv210_dram_conf[1].refresh = (__raw_readl(S5P_VA_DMC1 + 0x30) * 1000); | 511 | s5pv210_dram_conf[1].refresh = (__raw_readl(S5P_VA_DMC1 + 0x30) * 1000); |
552 | s5pv210_dram_conf[1].freq = clk_get_rate(dmc1_clk); | 512 | s5pv210_dram_conf[1].freq = clk_get_rate(dmc1_clk); |
553 | 513 | ||
554 | policy->cur = policy->min = policy->max = s5pv210_getspeed(0); | 514 | return cpufreq_generic_init(policy, s5pv210_freq_table, 40000); |
555 | |||
556 | cpufreq_frequency_table_get_attr(s5pv210_freq_table, policy->cpu); | ||
557 | |||
558 | policy->cpuinfo.transition_latency = 40000; | ||
559 | |||
560 | return cpufreq_frequency_table_cpuinfo(policy, s5pv210_freq_table); | ||
561 | 515 | ||
562 | out_dmc1: | 516 | out_dmc1: |
563 | clk_put(dmc0_clk); | 517 | clk_put(dmc0_clk); |
@@ -573,16 +527,18 @@ static int s5pv210_cpufreq_notifier_event(struct notifier_block *this, | |||
573 | 527 | ||
574 | switch (event) { | 528 | switch (event) { |
575 | case PM_SUSPEND_PREPARE: | 529 | case PM_SUSPEND_PREPARE: |
576 | ret = cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ, | 530 | ret = cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ, 0); |
577 | DISABLE_FURTHER_CPUFREQ); | ||
578 | if (ret < 0) | 531 | if (ret < 0) |
579 | return NOTIFY_BAD; | 532 | return NOTIFY_BAD; |
580 | 533 | ||
534 | /* Disable updation of cpu frequency */ | ||
535 | no_cpufreq_access = true; | ||
581 | return NOTIFY_OK; | 536 | return NOTIFY_OK; |
582 | case PM_POST_RESTORE: | 537 | case PM_POST_RESTORE: |
583 | case PM_POST_SUSPEND: | 538 | case PM_POST_SUSPEND: |
584 | cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ, | 539 | /* Enable updation of cpu frequency */ |
585 | ENABLE_FURTHER_CPUFREQ); | 540 | no_cpufreq_access = false; |
541 | cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ, 0); | ||
586 | 542 | ||
587 | return NOTIFY_OK; | 543 | return NOTIFY_OK; |
588 | } | 544 | } |
@@ -595,18 +551,18 @@ static int s5pv210_cpufreq_reboot_notifier_event(struct notifier_block *this, | |||
595 | { | 551 | { |
596 | int ret; | 552 | int ret; |
597 | 553 | ||
598 | ret = cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ, | 554 | ret = cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ, 0); |
599 | DISABLE_FURTHER_CPUFREQ); | ||
600 | if (ret < 0) | 555 | if (ret < 0) |
601 | return NOTIFY_BAD; | 556 | return NOTIFY_BAD; |
602 | 557 | ||
558 | no_cpufreq_access = true; | ||
603 | return NOTIFY_DONE; | 559 | return NOTIFY_DONE; |
604 | } | 560 | } |
605 | 561 | ||
606 | static struct cpufreq_driver s5pv210_driver = { | 562 | static struct cpufreq_driver s5pv210_driver = { |
607 | .flags = CPUFREQ_STICKY, | 563 | .flags = CPUFREQ_STICKY, |
608 | .verify = s5pv210_verify_speed, | 564 | .verify = cpufreq_generic_frequency_table_verify, |
609 | .target = s5pv210_target, | 565 | .target_index = s5pv210_target, |
610 | .get = s5pv210_getspeed, | 566 | .get = s5pv210_getspeed, |
611 | .init = s5pv210_cpu_init, | 567 | .init = s5pv210_cpu_init, |
612 | .name = "s5pv210", | 568 | .name = "s5pv210", |