diff options
Diffstat (limited to 'drivers/cpufreq/exynos-cpufreq.c')
-rw-r--r-- | drivers/cpufreq/exynos-cpufreq.c | 96 |
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 | ||
26 | static struct exynos_dvfs_info *exynos_info; | 25 | static struct exynos_dvfs_info *exynos_info; |
27 | |||
28 | static struct regulator *arm_regulator; | 26 | static struct regulator *arm_regulator; |
29 | |||
30 | static unsigned int locking_frequency; | 27 | static unsigned int locking_frequency; |
31 | static bool frequency_locked; | ||
32 | static DEFINE_MUTEX(cpufreq_lock); | ||
33 | 28 | ||
34 | static int exynos_cpufreq_get_index(unsigned int freq) | 29 | static int exynos_cpufreq_get_index(unsigned int freq) |
35 | { | 30 | { |
@@ -134,83 +129,13 @@ out: | |||
134 | 129 | ||
135 | static int exynos_target(struct cpufreq_policy *policy, unsigned int index) | 130 | static 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 | |||
147 | out: | ||
148 | mutex_unlock(&cpufreq_lock); | ||
149 | |||
150 | return ret; | ||
151 | } | ||
152 | |||
153 | #ifdef CONFIG_PM | ||
154 | static int exynos_cpufreq_suspend(struct cpufreq_policy *policy) | ||
155 | { | ||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | static 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 | */ | ||
180 | static 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 | ||
207 | static struct notifier_block exynos_cpufreq_nb = { | ||
208 | .notifier_call = exynos_cpufreq_pm_notifier, | ||
209 | }; | ||
210 | |||
211 | static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy) | 135 | static 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; | ||
276 | err_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); |
280 | err_vdd_arm: | 198 | err_vdd_arm: |
281 | kfree(exynos_info); | 199 | kfree(exynos_info); |