aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/cpufreq/exynos-cpufreq.c
diff options
context:
space:
mode:
authorViresh Kumar <viresh.kumar@linaro.org>2014-03-03 22:00:28 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-03-06 09:04:12 -0500
commitd248bb89f94c193d5f88dbaeb32858d8d3c5762a (patch)
tree28f4ce2b9a3302d4f4ac3d305e0309770852c99c /drivers/cpufreq/exynos-cpufreq.c
parente28867eab7c0a60cddf0cb59f9f6cbbd9561425d (diff)
cpufreq: exynos: Use cpufreq_generic_suspend()
The cpufreq core now supports suspending and resuming of cpufreq drivers and governors during systems suspend and resume, so use the common infrastructure instead of defining special PM notifiers for the same thing. Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> [rjw: Changelog] Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/cpufreq/exynos-cpufreq.c')
-rw-r--r--drivers/cpufreq/exynos-cpufreq.c96
1 files changed, 7 insertions, 89 deletions
diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c
index fcd2914d081a..307f02e0e19c 100644
--- a/drivers/cpufreq/exynos-cpufreq.c
+++ b/drivers/cpufreq/exynos-cpufreq.c
@@ -16,7 +16,6 @@
16#include <linux/slab.h> 16#include <linux/slab.h>
17#include <linux/regulator/consumer.h> 17#include <linux/regulator/consumer.h>
18#include <linux/cpufreq.h> 18#include <linux/cpufreq.h>
19#include <linux/suspend.h>
20#include <linux/platform_device.h> 19#include <linux/platform_device.h>
21 20
22#include <plat/cpu.h> 21#include <plat/cpu.h>
@@ -24,12 +23,8 @@
24#include "exynos-cpufreq.h" 23#include "exynos-cpufreq.h"
25 24
26static struct exynos_dvfs_info *exynos_info; 25static struct exynos_dvfs_info *exynos_info;
27
28static struct regulator *arm_regulator; 26static struct regulator *arm_regulator;
29
30static unsigned int locking_frequency; 27static unsigned int locking_frequency;
31static bool frequency_locked;
32static DEFINE_MUTEX(cpufreq_lock);
33 28
34static int exynos_cpufreq_get_index(unsigned int freq) 29static int exynos_cpufreq_get_index(unsigned int freq)
35{ 30{
@@ -134,83 +129,13 @@ out:
134 129
135static int exynos_target(struct cpufreq_policy *policy, unsigned int index) 130static int exynos_target(struct cpufreq_policy *policy, unsigned int index)
136{ 131{
137 struct cpufreq_frequency_table *freq_table = exynos_info->freq_table; 132 return exynos_cpufreq_scale(exynos_info->freq_table[index].frequency);
138 int ret = 0;
139
140 mutex_lock(&cpufreq_lock);
141
142 if (frequency_locked)
143 goto out;
144
145 ret = exynos_cpufreq_scale(freq_table[index].frequency);
146
147out:
148 mutex_unlock(&cpufreq_lock);
149
150 return ret;
151}
152
153#ifdef CONFIG_PM
154static int exynos_cpufreq_suspend(struct cpufreq_policy *policy)
155{
156 return 0;
157}
158
159static int exynos_cpufreq_resume(struct cpufreq_policy *policy)
160{
161 return 0;
162}
163#endif
164
165/**
166 * exynos_cpufreq_pm_notifier - block CPUFREQ's activities in suspend-resume
167 * context
168 * @notifier
169 * @pm_event
170 * @v
171 *
172 * While frequency_locked == true, target() ignores every frequency but
173 * locking_frequency. The locking_frequency value is the initial frequency,
174 * which is set by the bootloader. In order to eliminate possible
175 * inconsistency in clock values, we save and restore frequencies during
176 * suspend and resume and block CPUFREQ activities. Note that the standard
177 * suspend/resume cannot be used as they are too deep (syscore_ops) for
178 * regulator actions.
179 */
180static int exynos_cpufreq_pm_notifier(struct notifier_block *notifier,
181 unsigned long pm_event, void *v)
182{
183 int ret;
184
185 switch (pm_event) {
186 case PM_SUSPEND_PREPARE:
187 mutex_lock(&cpufreq_lock);
188 frequency_locked = true;
189 mutex_unlock(&cpufreq_lock);
190
191 ret = exynos_cpufreq_scale(locking_frequency);
192 if (ret < 0)
193 return NOTIFY_BAD;
194
195 break;
196
197 case PM_POST_SUSPEND:
198 mutex_lock(&cpufreq_lock);
199 frequency_locked = false;
200 mutex_unlock(&cpufreq_lock);
201 break;
202 }
203
204 return NOTIFY_OK;
205} 133}
206 134
207static struct notifier_block exynos_cpufreq_nb = {
208 .notifier_call = exynos_cpufreq_pm_notifier,
209};
210
211static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy) 135static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy)
212{ 136{
213 policy->clk = exynos_info->cpu_clk; 137 policy->clk = exynos_info->cpu_clk;
138 policy->suspend_freq = locking_frequency;
214 return cpufreq_generic_init(policy, exynos_info->freq_table, 100000); 139 return cpufreq_generic_init(policy, exynos_info->freq_table, 100000);
215} 140}
216 141
@@ -227,8 +152,7 @@ static struct cpufreq_driver exynos_driver = {
227 .boost_supported = true, 152 .boost_supported = true,
228#endif 153#endif
229#ifdef CONFIG_PM 154#ifdef CONFIG_PM
230 .suspend = exynos_cpufreq_suspend, 155 .suspend = cpufreq_generic_suspend,
231 .resume = exynos_cpufreq_resume,
232#endif 156#endif
233}; 157};
234 158
@@ -263,19 +187,13 @@ static int exynos_cpufreq_probe(struct platform_device *pdev)
263 goto err_vdd_arm; 187 goto err_vdd_arm;
264 } 188 }
265 189
190 /* Done here as we want to capture boot frequency */
266 locking_frequency = clk_get_rate(exynos_info->cpu_clk) / 1000; 191 locking_frequency = clk_get_rate(exynos_info->cpu_clk) / 1000;
267 192
268 register_pm_notifier(&exynos_cpufreq_nb); 193 if (!cpufreq_register_driver(&exynos_driver))
269 194 return 0;
270 if (cpufreq_register_driver(&exynos_driver)) {
271 pr_err("%s: failed to register cpufreq driver\n", __func__);
272 goto err_cpufreq;
273 }
274
275 return 0;
276err_cpufreq:
277 unregister_pm_notifier(&exynos_cpufreq_nb);
278 195
196 pr_err("%s: failed to register cpufreq driver\n", __func__);
279 regulator_put(arm_regulator); 197 regulator_put(arm_regulator);
280err_vdd_arm: 198err_vdd_arm:
281 kfree(exynos_info); 199 kfree(exynos_info);