aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/cpufreq/omap-cpufreq.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-03-23 20:51:50 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-03-23 20:51:50 -0400
commit4416b0eaa3d51f3e360d6e171e603ff51848bcf5 (patch)
tree1fa54240a606bc34a35e2eb99f06e91ec269fc01 /drivers/cpufreq/omap-cpufreq.c
parent24613ff927500513eae7e84bb6fc6c3ef268e452 (diff)
parent6139b652c89ecd5ebf72ef895fec9f6d0d320cb1 (diff)
Merge branch 'fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/davej/cpufreq
Pull cpufreq fixes from Dave Jones: "I meant to get some of these in for 3.3 final, but left things too late, so I've got two trees this time." * 'fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/davej/cpufreq: cpufreq: OMAP: specify range for voltage scaling cpufreq: OMAP: scale voltage along with frequency cpufreq: OMAP driver depends CPUfreq tables
Diffstat (limited to 'drivers/cpufreq/omap-cpufreq.c')
-rw-r--r--drivers/cpufreq/omap-cpufreq.c72
1 files changed, 67 insertions, 5 deletions
diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c
index 5d04c57aae30..67bbb06d0460 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>
@@ -37,6 +38,9 @@
37 38
38#include <mach/hardware.h> 39#include <mach/hardware.h>
39 40
41/* OPP tolerance in percentage */
42#define OPP_TOLERANCE 4
43
40#ifdef CONFIG_SMP 44#ifdef CONFIG_SMP
41struct lpj_info { 45struct lpj_info {
42 unsigned long ref; 46 unsigned long ref;
@@ -52,6 +56,7 @@ static atomic_t freq_table_users = ATOMIC_INIT(0);
52static struct clk *mpu_clk; 56static struct clk *mpu_clk;
53static char *mpu_clk_name; 57static char *mpu_clk_name;
54static struct device *mpu_dev; 58static struct device *mpu_dev;
59static struct regulator *mpu_reg;
55 60
56static int omap_verify_speed(struct cpufreq_policy *policy) 61static int omap_verify_speed(struct cpufreq_policy *policy)
57{ 62{
@@ -76,8 +81,10 @@ static int omap_target(struct cpufreq_policy *policy,
76 unsigned int relation) 81 unsigned int relation)
77{ 82{
78 unsigned int i; 83 unsigned int i;
79 int ret = 0; 84 int r, ret = 0;
80 struct cpufreq_freqs freqs; 85 struct cpufreq_freqs freqs;
86 struct opp *opp;
87 unsigned long freq, volt = 0, volt_old = 0, tol = 0;
81 88
82 if (!freq_table) { 89 if (!freq_table) {
83 dev_err(mpu_dev, "%s: cpu%d: no freq table!\n", __func__, 90 dev_err(mpu_dev, "%s: cpu%d: no freq table!\n", __func__,
@@ -111,13 +118,50 @@ static int omap_target(struct cpufreq_policy *policy,
111 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); 118 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
112 } 119 }
113 120
114#ifdef CONFIG_CPU_FREQ_DEBUG 121 freq = freqs.new * 1000;
115 pr_info("cpufreq-omap: transition: %u --> %u\n", freqs.old, freqs.new); 122
116#endif 123 if (mpu_reg) {
124 opp = opp_find_freq_ceil(mpu_dev, &freq);
125 if (IS_ERR(opp)) {
126 dev_err(mpu_dev, "%s: unable to find MPU OPP for %d\n",
127 __func__, freqs.new);
128 return -EINVAL;
129 }
130 volt = opp_get_voltage(opp);
131 tol = volt * OPP_TOLERANCE / 100;
132 volt_old = regulator_get_voltage(mpu_reg);
133 }
134
135 dev_dbg(mpu_dev, "cpufreq-omap: %u MHz, %ld mV --> %u MHz, %ld mV\n",
136 freqs.old / 1000, volt_old ? volt_old / 1000 : -1,
137 freqs.new / 1000, volt ? volt / 1000 : -1);
138
139 /* scaling up? scale voltage before frequency */
140 if (mpu_reg && (freqs.new > freqs.old)) {
141 r = regulator_set_voltage(mpu_reg, volt - tol, volt + tol);
142 if (r < 0) {
143 dev_warn(mpu_dev, "%s: unable to scale voltage up.\n",
144 __func__);
145 freqs.new = freqs.old;
146 goto done;
147 }
148 }
117 149
118 ret = clk_set_rate(mpu_clk, freqs.new * 1000); 150 ret = clk_set_rate(mpu_clk, freqs.new * 1000);
119 freqs.new = omap_getspeed(policy->cpu);
120 151
152 /* scaling down? scale voltage after frequency */
153 if (mpu_reg && (freqs.new < freqs.old)) {
154 r = regulator_set_voltage(mpu_reg, volt - tol, volt + tol);
155 if (r < 0) {
156 dev_warn(mpu_dev, "%s: unable to scale voltage down.\n",
157 __func__);
158 ret = clk_set_rate(mpu_clk, freqs.old * 1000);
159 freqs.new = freqs.old;
160 goto done;
161 }
162 }
163
164 freqs.new = omap_getspeed(policy->cpu);
121#ifdef CONFIG_SMP 165#ifdef CONFIG_SMP
122 /* 166 /*
123 * Note that loops_per_jiffy is not updated on SMP systems in 167 * Note that loops_per_jiffy is not updated on SMP systems in
@@ -144,6 +188,7 @@ static int omap_target(struct cpufreq_policy *policy,
144 freqs.new); 188 freqs.new);
145#endif 189#endif
146 190
191done:
147 /* notifiers */ 192 /* notifiers */
148 for_each_cpu(i, policy->cpus) { 193 for_each_cpu(i, policy->cpus) {
149 freqs.cpu = i; 194 freqs.cpu = i;
@@ -260,6 +305,23 @@ static int __init omap_cpufreq_init(void)
260 return -EINVAL; 305 return -EINVAL;
261 } 306 }
262 307
308 mpu_reg = regulator_get(mpu_dev, "vcc");
309 if (IS_ERR(mpu_reg)) {
310 pr_warning("%s: unable to get MPU regulator\n", __func__);
311 mpu_reg = NULL;
312 } else {
313 /*
314 * Ensure physical regulator is present.
315 * (e.g. could be dummy regulator.)
316 */
317 if (regulator_get_voltage(mpu_reg) < 0) {
318 pr_warn("%s: physical regulator not present for MPU\n",
319 __func__);
320 regulator_put(mpu_reg);
321 mpu_reg = NULL;
322 }
323 }
324
263 return cpufreq_register_driver(&omap_driver); 325 return cpufreq_register_driver(&omap_driver);
264} 326}
265 327