aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/cpufreq/exynos-cpufreq.c
diff options
context:
space:
mode:
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);