aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/cpufreq
diff options
context:
space:
mode:
authorKevin Hilman <khilman@ti.com>2011-07-15 18:05:04 -0400
committerKevin Hilman <khilman@ti.com>2012-02-21 19:32:25 -0500
commit53dfe8a884e6f85d73379f84cffa72225cd52ad6 (patch)
tree0a4ffbe130edab06ea52aa141fa20d8c90dbe729 /drivers/cpufreq
parentb09db45c56c299438a09b85c06067d7dcd951ea4 (diff)
cpufreq: OMAP: scale voltage along with frequency
Use the regulator framework to get the voltage regulator associated with the MPU voltage domain and use it to scale voltage along with frequency. While here, CONFIG_CPU_FREQ_DEBUG doesn't exist anymore, so move debug prints to use dev_dbg(). Special thanks to Afzal Mohammed for suggestions on more robust error checking. Cc: Afzal Mohammed <afzal@ti.com> Signed-off-by: Kevin Hilman <khilman@ti.com>
Diffstat (limited to 'drivers/cpufreq')
-rw-r--r--drivers/cpufreq/omap-cpufreq.c68
1 files changed, 63 insertions, 5 deletions
diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c
index 5d04c57aae30..9f5d6368766e 100644
--- a/drivers/cpufreq/omap-cpufreq.c
+++ b/drivers/cpufreq/omap-cpufreq.c
@@ -25,6 +25,7 @@
25#include <linux/opp.h> 25#include <linux/opp.h>
26#include <linux/cpu.h> 26#include <linux/cpu.h>
27#include <linux/module.h> 27#include <linux/module.h>
28#include <linux/regulator/consumer.h>
28 29
29#include <asm/system.h> 30#include <asm/system.h>
30#include <asm/smp_plat.h> 31#include <asm/smp_plat.h>
@@ -52,6 +53,7 @@ static atomic_t freq_table_users = ATOMIC_INIT(0);
52static struct clk *mpu_clk; 53static struct clk *mpu_clk;
53static char *mpu_clk_name; 54static char *mpu_clk_name;
54static struct device *mpu_dev; 55static struct device *mpu_dev;
56static struct regulator *mpu_reg;
55 57
56static int omap_verify_speed(struct cpufreq_policy *policy) 58static int omap_verify_speed(struct cpufreq_policy *policy)
57{ 59{
@@ -76,8 +78,10 @@ static int omap_target(struct cpufreq_policy *policy,
76 unsigned int relation) 78 unsigned int relation)
77{ 79{
78 unsigned int i; 80 unsigned int i;
79 int ret = 0; 81 int r, ret = 0;
80 struct cpufreq_freqs freqs; 82 struct cpufreq_freqs freqs;
83 struct opp *opp;
84 unsigned long freq, volt = 0, volt_old = 0;
81 85
82 if (!freq_table) { 86 if (!freq_table) {
83 dev_err(mpu_dev, "%s: cpu%d: no freq table!\n", __func__, 87 dev_err(mpu_dev, "%s: cpu%d: no freq table!\n", __func__,
@@ -111,13 +115,49 @@ static int omap_target(struct cpufreq_policy *policy,
111 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); 115 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
112 } 116 }
113 117
114#ifdef CONFIG_CPU_FREQ_DEBUG 118 freq = freqs.new * 1000;
115 pr_info("cpufreq-omap: transition: %u --> %u\n", freqs.old, freqs.new); 119
116#endif 120 if (mpu_reg) {
121 opp = opp_find_freq_ceil(mpu_dev, &freq);
122 if (IS_ERR(opp)) {
123 dev_err(mpu_dev, "%s: unable to find MPU OPP for %d\n",
124 __func__, freqs.new);
125 return -EINVAL;
126 }
127 volt = opp_get_voltage(opp);
128 volt_old = regulator_get_voltage(mpu_reg);
129 }
130
131 dev_dbg(mpu_dev, "cpufreq-omap: %u MHz, %ld mV --> %u MHz, %ld mV\n",
132 freqs.old / 1000, volt_old ? volt_old / 1000 : -1,
133 freqs.new / 1000, volt ? volt / 1000 : -1);
134
135 /* scaling up? scale voltage before frequency */
136 if (mpu_reg && (freqs.new > freqs.old)) {
137 r = regulator_set_voltage(mpu_reg, volt, volt);
138 if (r < 0) {
139 dev_warn(mpu_dev, "%s: unable to scale voltage up.\n",
140 __func__);
141 freqs.new = freqs.old;
142 goto done;
143 }
144 }
117 145
118 ret = clk_set_rate(mpu_clk, freqs.new * 1000); 146 ret = clk_set_rate(mpu_clk, freqs.new * 1000);
119 freqs.new = omap_getspeed(policy->cpu);
120 147
148 /* scaling down? scale voltage after frequency */
149 if (mpu_reg && (freqs.new < freqs.old)) {
150 r = regulator_set_voltage(mpu_reg, volt, volt);
151 if (r < 0) {
152 dev_warn(mpu_dev, "%s: unable to scale voltage down.\n",
153 __func__);
154 ret = clk_set_rate(mpu_clk, freqs.old * 1000);
155 freqs.new = freqs.old;
156 goto done;
157 }
158 }
159
160 freqs.new = omap_getspeed(policy->cpu);
121#ifdef CONFIG_SMP 161#ifdef CONFIG_SMP
122 /* 162 /*
123 * Note that loops_per_jiffy is not updated on SMP systems in 163 * Note that loops_per_jiffy is not updated on SMP systems in
@@ -144,6 +184,7 @@ static int omap_target(struct cpufreq_policy *policy,
144 freqs.new); 184 freqs.new);
145#endif 185#endif
146 186
187done:
147 /* notifiers */ 188 /* notifiers */
148 for_each_cpu(i, policy->cpus) { 189 for_each_cpu(i, policy->cpus) {
149 freqs.cpu = i; 190 freqs.cpu = i;
@@ -260,6 +301,23 @@ static int __init omap_cpufreq_init(void)
260 return -EINVAL; 301 return -EINVAL;
261 } 302 }
262 303
304 mpu_reg = regulator_get(mpu_dev, "vcc");
305 if (IS_ERR(mpu_reg)) {
306 pr_warning("%s: unable to get MPU regulator\n", __func__);
307 mpu_reg = NULL;
308 } else {
309 /*
310 * Ensure physical regulator is present.
311 * (e.g. could be dummy regulator.)
312 */
313 if (regulator_get_voltage(mpu_reg) < 0) {
314 pr_warn("%s: physical regulator not present for MPU\n",
315 __func__);
316 regulator_put(mpu_reg);
317 mpu_reg = NULL;
318 }
319 }
320
263 return cpufreq_register_driver(&omap_driver); 321 return cpufreq_register_driver(&omap_driver);
264} 322}
265 323