aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/cpufreq
diff options
context:
space:
mode:
authorAnson Huang <b20788@freescale.com>2013-09-02 17:18:31 -0400
committerNitin Garg <nitin.garg@freescale.com>2014-04-16 09:01:39 -0400
commitc79a39cf2056854c931aab022a72d56ac8ec9a9e (patch)
tree568360e781ef4e52d3a83f3af0bbdd712aab9e55 /drivers/cpufreq
parent497dc0f51708aad3c37ad0fa2c510d2515724378 (diff)
ENGR00277697 cpufreq: imx: increase cpufreq during suspend/resume
During suspend/resume, when cpufreq driver try to increase voltage/freq, it needs to control I2C/SPI to communicate with external PMIC to adjust voltage, but these I2C/SPI devices may be already suspended, to avoid such scenario, we just increase cpufreq to highest setpoint before suspend. As this pm notification's updating cpu policy may work together with cpufreq governor, both of them may call set_target at same time, so we need to add mutex lock to prevent this scenario, otherwise, the clock use count will be wrong. Signed-off-by: Anson Huang <b20788@freescale.com>
Diffstat (limited to 'drivers/cpufreq')
-rw-r--r--drivers/cpufreq/cpufreq-imx6.c50
1 files changed, 49 insertions, 1 deletions
diff --git a/drivers/cpufreq/cpufreq-imx6.c b/drivers/cpufreq/cpufreq-imx6.c
index d301984bfa41..24dfa7a4b1f7 100644
--- a/drivers/cpufreq/cpufreq-imx6.c
+++ b/drivers/cpufreq/cpufreq-imx6.c
@@ -17,6 +17,7 @@
17#include <linux/platform_device.h> 17#include <linux/platform_device.h>
18#include <linux/regulator/consumer.h> 18#include <linux/regulator/consumer.h>
19#include <linux/slab.h> 19#include <linux/slab.h>
20#include <linux/suspend.h>
20 21
21static struct regulator *arm_reg; 22static struct regulator *arm_reg;
22static struct regulator *pu_reg; 23static struct regulator *pu_reg;
@@ -31,6 +32,7 @@ static struct clk *pll2_pfd2_396m_clk;
31static struct device *cpu_dev; 32static struct device *cpu_dev;
32static struct cpufreq_frequency_table *freq_table; 33static struct cpufreq_frequency_table *freq_table;
33static unsigned int transition_latency; 34static unsigned int transition_latency;
35static struct mutex set_cpufreq_lock;
34 36
35struct soc_opp { 37struct soc_opp {
36 u32 arm_freq; 38 u32 arm_freq;
@@ -59,11 +61,14 @@ static int imx6_set_target(struct cpufreq_policy *policy,
59 unsigned int index, soc_opp_index = 0; 61 unsigned int index, soc_opp_index = 0;
60 int ret; 62 int ret;
61 63
64 mutex_lock(&set_cpufreq_lock);
65
62 ret = cpufreq_frequency_table_target(policy, freq_table, target_freq, 66 ret = cpufreq_frequency_table_target(policy, freq_table, target_freq,
63 relation, &index); 67 relation, &index);
64 if (ret) { 68 if (ret) {
65 dev_err(cpu_dev, "failed to match target frequency %d: %d\n", 69 dev_err(cpu_dev, "failed to match target frequency %d: %d\n",
66 target_freq, ret); 70 target_freq, ret);
71 mutex_unlock(&set_cpufreq_lock);
67 return ret; 72 return ret;
68 } 73 }
69 74
@@ -71,8 +76,10 @@ static int imx6_set_target(struct cpufreq_policy *policy,
71 freq_hz = freqs.new * 1000; 76 freq_hz = freqs.new * 1000;
72 freqs.old = clk_get_rate(arm_clk) / 1000; 77 freqs.old = clk_get_rate(arm_clk) / 1000;
73 78
74 if (freqs.old == freqs.new) 79 if (freqs.old == freqs.new) {
80 mutex_unlock(&set_cpufreq_lock);
75 return 0; 81 return 0;
82 }
76 83
77 cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); 84 cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
78 85
@@ -81,6 +88,7 @@ static int imx6_set_target(struct cpufreq_policy *policy,
81 if (IS_ERR(opp)) { 88 if (IS_ERR(opp)) {
82 rcu_read_unlock(); 89 rcu_read_unlock();
83 dev_err(cpu_dev, "failed to find OPP for %ld\n", freq_hz); 90 dev_err(cpu_dev, "failed to find OPP for %ld\n", freq_hz);
91 mutex_unlock(&set_cpufreq_lock);
84 return PTR_ERR(opp); 92 return PTR_ERR(opp);
85 } 93 }
86 94
@@ -97,6 +105,7 @@ static int imx6_set_target(struct cpufreq_policy *policy,
97 if (soc_opp_index >= soc_opp_count) { 105 if (soc_opp_index >= soc_opp_count) {
98 dev_err(cpu_dev, 106 dev_err(cpu_dev,
99 "Cannot find matching imx6_soc_opp voltage\n"); 107 "Cannot find matching imx6_soc_opp voltage\n");
108 mutex_unlock(&set_cpufreq_lock);
100 return -EINVAL; 109 return -EINVAL;
101 } 110 }
102 111
@@ -215,8 +224,10 @@ static int imx6_set_target(struct cpufreq_policy *policy,
215 224
216 cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); 225 cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
217 226
227 mutex_unlock(&set_cpufreq_lock);
218 return 0; 228 return 0;
219err1: 229err1:
230 mutex_unlock(&set_cpufreq_lock);
220 return -1; 231 return -1;
221} 232}
222 233
@@ -262,6 +273,40 @@ static struct cpufreq_driver imx6_cpufreq_driver = {
262 .attr = imx6_cpufreq_attr, 273 .attr = imx6_cpufreq_attr,
263}; 274};
264 275
276static int imx6_cpufreq_pm_notify(struct notifier_block *nb,
277 unsigned long event, void *dummy)
278{
279 struct cpufreq_policy *data = cpufreq_cpu_get(0);
280 static u32 cpufreq_policy_min_pre_suspend;
281
282 /*
283 * During suspend/resume, When cpufreq driver try to increase
284 * voltage/freq, it needs to control I2C/SPI to communicate
285 * with external PMIC to adjust voltage, but these I2C/SPI
286 * devices may be already suspended, to avoid such scenario,
287 * we just increase cpufreq to highest setpoint before suspend.
288 */
289 switch (event) {
290 case PM_SUSPEND_PREPARE:
291 cpufreq_policy_min_pre_suspend = data->user_policy.min;
292 data->user_policy.min = data->user_policy.max;
293 break;
294 case PM_POST_SUSPEND:
295 data->user_policy.min = cpufreq_policy_min_pre_suspend;
296 break;
297 default:
298 break;
299 }
300
301 cpufreq_update_policy(0);
302
303 return NOTIFY_OK;
304}
305
306static struct notifier_block imx6_cpufreq_pm_notifier = {
307 .notifier_call = imx6_cpufreq_pm_notify,
308};
309
265static int imx6_cpufreq_probe(struct platform_device *pdev) 310static int imx6_cpufreq_probe(struct platform_device *pdev)
266{ 311{
267 struct device_node *np; 312 struct device_node *np;
@@ -419,6 +464,9 @@ static int imx6_cpufreq_probe(struct platform_device *pdev)
419 goto free_freq_table; 464 goto free_freq_table;
420 } 465 }
421 466
467 mutex_init(&set_cpufreq_lock);
468 register_pm_notifier(&imx6_cpufreq_pm_notifier);
469
422 of_node_put(np); 470 of_node_put(np);
423 return 0; 471 return 0;
424 472