]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/cpufreq/s3c2416-cpufreq.c
Merge branch 'timers/core' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip...
[karo-tx-linux.git] / drivers / cpufreq / s3c2416-cpufreq.c
1 /*
2  * S3C2416/2450 CPUfreq Support
3  *
4  * Copyright 2011 Heiko Stuebner <heiko@sntech.de>
5  *
6  * based on s3c64xx_cpufreq.c
7  *
8  * Copyright 2009 Wolfson Microelectronics plc
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as
12  * published by the Free Software Foundation.
13  */
14
15 #include <linux/kernel.h>
16 #include <linux/types.h>
17 #include <linux/init.h>
18 #include <linux/cpufreq.h>
19 #include <linux/clk.h>
20 #include <linux/err.h>
21 #include <linux/regulator/consumer.h>
22 #include <linux/reboot.h>
23 #include <linux/module.h>
24
25 static DEFINE_MUTEX(cpufreq_lock);
26
27 struct s3c2416_data {
28         struct clk *armdiv;
29         struct clk *armclk;
30         struct clk *hclk;
31
32         unsigned long regulator_latency;
33 #ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
34         struct regulator *vddarm;
35 #endif
36
37         struct cpufreq_frequency_table *freq_table;
38
39         bool is_dvs;
40         bool disable_dvs;
41 };
42
43 static struct s3c2416_data s3c2416_cpufreq;
44
45 struct s3c2416_dvfs {
46         unsigned int vddarm_min;
47         unsigned int vddarm_max;
48 };
49
50 /* pseudo-frequency for dvs mode */
51 #define FREQ_DVS        132333
52
53 /* frequency to sleep and reboot in
54  * it's essential to leave dvs, as some boards do not reconfigure the
55  * regulator on reboot
56  */
57 #define FREQ_SLEEP      133333
58
59 /* Sources for the ARMCLK */
60 #define SOURCE_HCLK     0
61 #define SOURCE_ARMDIV   1
62
63 #ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
64 /* S3C2416 only supports changing the voltage in the dvs-mode.
65  * Voltages down to 1.0V seem to work, so we take what the regulator
66  * can get us.
67  */
68 static struct s3c2416_dvfs s3c2416_dvfs_table[] = {
69         [SOURCE_HCLK] = {  950000, 1250000 },
70         [SOURCE_ARMDIV] = { 1250000, 1350000 },
71 };
72 #endif
73
74 static struct cpufreq_frequency_table s3c2416_freq_table[] = {
75         { SOURCE_HCLK, FREQ_DVS },
76         { SOURCE_ARMDIV, 133333 },
77         { SOURCE_ARMDIV, 266666 },
78         { SOURCE_ARMDIV, 400000 },
79         { 0, CPUFREQ_TABLE_END },
80 };
81
82 static struct cpufreq_frequency_table s3c2450_freq_table[] = {
83         { SOURCE_HCLK, FREQ_DVS },
84         { SOURCE_ARMDIV, 133500 },
85         { SOURCE_ARMDIV, 267000 },
86         { SOURCE_ARMDIV, 534000 },
87         { 0, CPUFREQ_TABLE_END },
88 };
89
90 static int s3c2416_cpufreq_verify_speed(struct cpufreq_policy *policy)
91 {
92         struct s3c2416_data *s3c_freq = &s3c2416_cpufreq;
93
94         if (policy->cpu != 0)
95                 return -EINVAL;
96
97         return cpufreq_frequency_table_verify(policy, s3c_freq->freq_table);
98 }
99
100 static unsigned int s3c2416_cpufreq_get_speed(unsigned int cpu)
101 {
102         struct s3c2416_data *s3c_freq = &s3c2416_cpufreq;
103
104         if (cpu != 0)
105                 return 0;
106
107         /* return our pseudo-frequency when in dvs mode */
108         if (s3c_freq->is_dvs)
109                 return FREQ_DVS;
110
111         return clk_get_rate(s3c_freq->armclk) / 1000;
112 }
113
114 static int s3c2416_cpufreq_set_armdiv(struct s3c2416_data *s3c_freq,
115                                       unsigned int freq)
116 {
117         int ret;
118
119         if (clk_get_rate(s3c_freq->armdiv) / 1000 != freq) {
120                 ret = clk_set_rate(s3c_freq->armdiv, freq * 1000);
121                 if (ret < 0) {
122                         pr_err("cpufreq: Failed to set armdiv rate %dkHz: %d\n",
123                                freq, ret);
124                         return ret;
125                 }
126         }
127
128         return 0;
129 }
130
131 static int s3c2416_cpufreq_enter_dvs(struct s3c2416_data *s3c_freq, int idx)
132 {
133 #ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
134         struct s3c2416_dvfs *dvfs;
135 #endif
136         int ret;
137
138         if (s3c_freq->is_dvs) {
139                 pr_debug("cpufreq: already in dvs mode, nothing to do\n");
140                 return 0;
141         }
142
143         pr_debug("cpufreq: switching armclk to hclk (%lukHz)\n",
144                  clk_get_rate(s3c_freq->hclk) / 1000);
145         ret = clk_set_parent(s3c_freq->armclk, s3c_freq->hclk);
146         if (ret < 0) {
147                 pr_err("cpufreq: Failed to switch armclk to hclk: %d\n", ret);
148                 return ret;
149         }
150
151 #ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
152         /* changing the core voltage is only allowed when in dvs mode */
153         if (s3c_freq->vddarm) {
154                 dvfs = &s3c2416_dvfs_table[idx];
155
156                 pr_debug("cpufreq: setting regulator to %d-%d\n",
157                          dvfs->vddarm_min, dvfs->vddarm_max);
158                 ret = regulator_set_voltage(s3c_freq->vddarm,
159                                             dvfs->vddarm_min,
160                                             dvfs->vddarm_max);
161
162                 /* when lowering the voltage failed, there is nothing to do */
163                 if (ret != 0)
164                         pr_err("cpufreq: Failed to set VDDARM: %d\n", ret);
165         }
166 #endif
167
168         s3c_freq->is_dvs = 1;
169
170         return 0;
171 }
172
173 static int s3c2416_cpufreq_leave_dvs(struct s3c2416_data *s3c_freq, int idx)
174 {
175 #ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
176         struct s3c2416_dvfs *dvfs;
177 #endif
178         int ret;
179
180         if (!s3c_freq->is_dvs) {
181                 pr_debug("cpufreq: not in dvs mode, so can't leave\n");
182                 return 0;
183         }
184
185 #ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
186         if (s3c_freq->vddarm) {
187                 dvfs = &s3c2416_dvfs_table[idx];
188
189                 pr_debug("cpufreq: setting regulator to %d-%d\n",
190                          dvfs->vddarm_min, dvfs->vddarm_max);
191                 ret = regulator_set_voltage(s3c_freq->vddarm,
192                                             dvfs->vddarm_min,
193                                             dvfs->vddarm_max);
194                 if (ret != 0) {
195                         pr_err("cpufreq: Failed to set VDDARM: %d\n", ret);
196                         return ret;
197                 }
198         }
199 #endif
200
201         /* force armdiv to hclk frequency for transition from dvs*/
202         if (clk_get_rate(s3c_freq->armdiv) > clk_get_rate(s3c_freq->hclk)) {
203                 pr_debug("cpufreq: force armdiv to hclk frequency (%lukHz)\n",
204                          clk_get_rate(s3c_freq->hclk) / 1000);
205                 ret = s3c2416_cpufreq_set_armdiv(s3c_freq,
206                                         clk_get_rate(s3c_freq->hclk) / 1000);
207                 if (ret < 0) {
208                         pr_err("cpufreq: Failed to to set the armdiv to %lukHz: %d\n",
209                                clk_get_rate(s3c_freq->hclk) / 1000, ret);
210                         return ret;
211                 }
212         }
213
214         pr_debug("cpufreq: switching armclk parent to armdiv (%lukHz)\n",
215                         clk_get_rate(s3c_freq->armdiv) / 1000);
216
217         ret = clk_set_parent(s3c_freq->armclk, s3c_freq->armdiv);
218         if (ret < 0) {
219                 pr_err("cpufreq: Failed to switch armclk clock parent to armdiv: %d\n",
220                        ret);
221                 return ret;
222         }
223
224         s3c_freq->is_dvs = 0;
225
226         return 0;
227 }
228
229 static int s3c2416_cpufreq_set_target(struct cpufreq_policy *policy,
230                                       unsigned int target_freq,
231                                       unsigned int relation)
232 {
233         struct s3c2416_data *s3c_freq = &s3c2416_cpufreq;
234         struct cpufreq_freqs freqs;
235         int idx, ret, to_dvs = 0;
236         unsigned int i;
237
238         mutex_lock(&cpufreq_lock);
239
240         pr_debug("cpufreq: to %dKHz, relation %d\n", target_freq, relation);
241
242         ret = cpufreq_frequency_table_target(policy, s3c_freq->freq_table,
243                                              target_freq, relation, &i);
244         if (ret != 0)
245                 goto out;
246
247         idx = s3c_freq->freq_table[i].index;
248
249         if (idx == SOURCE_HCLK)
250                 to_dvs = 1;
251
252         /* switching to dvs when it's not allowed */
253         if (to_dvs && s3c_freq->disable_dvs) {
254                 pr_debug("cpufreq: entering dvs mode not allowed\n");
255                 ret = -EINVAL;
256                 goto out;
257         }
258
259         freqs.cpu = 0;
260         freqs.flags = 0;
261         freqs.old = s3c_freq->is_dvs ? FREQ_DVS
262                                      : clk_get_rate(s3c_freq->armclk) / 1000;
263
264         /* When leavin dvs mode, always switch the armdiv to the hclk rate
265          * The S3C2416 has stability issues when switching directly to
266          * higher frequencies.
267          */
268         freqs.new = (s3c_freq->is_dvs && !to_dvs)
269                                 ? clk_get_rate(s3c_freq->hclk) / 1000
270                                 : s3c_freq->freq_table[i].frequency;
271
272         pr_debug("cpufreq: Transition %d-%dkHz\n", freqs.old, freqs.new);
273
274         if (!to_dvs && freqs.old == freqs.new)
275                 goto out;
276
277         cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
278
279         if (to_dvs) {
280                 pr_debug("cpufreq: enter dvs\n");
281                 ret = s3c2416_cpufreq_enter_dvs(s3c_freq, idx);
282         } else if (s3c_freq->is_dvs) {
283                 pr_debug("cpufreq: leave dvs\n");
284                 ret = s3c2416_cpufreq_leave_dvs(s3c_freq, idx);
285         } else {
286                 pr_debug("cpufreq: change armdiv to %dkHz\n", freqs.new);
287                 ret = s3c2416_cpufreq_set_armdiv(s3c_freq, freqs.new);
288         }
289
290         cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
291
292 out:
293         mutex_unlock(&cpufreq_lock);
294
295         return ret;
296 }
297
298 #ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
299 static void __init s3c2416_cpufreq_cfg_regulator(struct s3c2416_data *s3c_freq)
300 {
301         int count, v, i, found;
302         struct cpufreq_frequency_table *freq;
303         struct s3c2416_dvfs *dvfs;
304
305         count = regulator_count_voltages(s3c_freq->vddarm);
306         if (count < 0) {
307                 pr_err("cpufreq: Unable to check supported voltages\n");
308                 return;
309         }
310
311         freq = s3c_freq->freq_table;
312         while (count > 0 && freq->frequency != CPUFREQ_TABLE_END) {
313                 if (freq->frequency == CPUFREQ_ENTRY_INVALID)
314                         continue;
315
316                 dvfs = &s3c2416_dvfs_table[freq->index];
317                 found = 0;
318
319                 /* Check only the min-voltage, more is always ok on S3C2416 */
320                 for (i = 0; i < count; i++) {
321                         v = regulator_list_voltage(s3c_freq->vddarm, i);
322                         if (v >= dvfs->vddarm_min)
323                                 found = 1;
324                 }
325
326                 if (!found) {
327                         pr_debug("cpufreq: %dkHz unsupported by regulator\n",
328                                  freq->frequency);
329                         freq->frequency = CPUFREQ_ENTRY_INVALID;
330                 }
331
332                 freq++;
333         }
334
335         /* Guessed */
336         s3c_freq->regulator_latency = 1 * 1000 * 1000;
337 }
338 #endif
339
340 static int s3c2416_cpufreq_reboot_notifier_evt(struct notifier_block *this,
341                                                unsigned long event, void *ptr)
342 {
343         struct s3c2416_data *s3c_freq = &s3c2416_cpufreq;
344         int ret;
345
346         mutex_lock(&cpufreq_lock);
347
348         /* disable further changes */
349         s3c_freq->disable_dvs = 1;
350
351         mutex_unlock(&cpufreq_lock);
352
353         /* some boards don't reconfigure the regulator on reboot, which
354          * could lead to undervolting the cpu when the clock is reset.
355          * Therefore we always leave the DVS mode on reboot.
356          */
357         if (s3c_freq->is_dvs) {
358                 pr_debug("cpufreq: leave dvs on reboot\n");
359                 ret = cpufreq_driver_target(cpufreq_cpu_get(0), FREQ_SLEEP, 0);
360                 if (ret < 0)
361                         return NOTIFY_BAD;
362         }
363
364         return NOTIFY_DONE;
365 }
366
367 static struct notifier_block s3c2416_cpufreq_reboot_notifier = {
368         .notifier_call = s3c2416_cpufreq_reboot_notifier_evt,
369 };
370
371 static int __init s3c2416_cpufreq_driver_init(struct cpufreq_policy *policy)
372 {
373         struct s3c2416_data *s3c_freq = &s3c2416_cpufreq;
374         struct cpufreq_frequency_table *freq;
375         struct clk *msysclk;
376         unsigned long rate;
377         int ret;
378
379         if (policy->cpu != 0)
380                 return -EINVAL;
381
382         msysclk = clk_get(NULL, "msysclk");
383         if (IS_ERR(msysclk)) {
384                 ret = PTR_ERR(msysclk);
385                 pr_err("cpufreq: Unable to obtain msysclk: %d\n", ret);
386                 return ret;
387         }
388
389         /*
390          * S3C2416 and S3C2450 share the same processor-ID and also provide no
391          * other means to distinguish them other than through the rate of
392          * msysclk. On S3C2416 msysclk runs at 800MHz and on S3C2450 at 533MHz.
393          */
394         rate = clk_get_rate(msysclk);
395         if (rate == 800 * 1000 * 1000) {
396                 pr_info("cpufreq: msysclk running at %lukHz, using S3C2416 frequency table\n",
397                         rate / 1000);
398                 s3c_freq->freq_table = s3c2416_freq_table;
399                 policy->cpuinfo.max_freq = 400000;
400         } else if (rate / 1000 == 534000) {
401                 pr_info("cpufreq: msysclk running at %lukHz, using S3C2450 frequency table\n",
402                         rate / 1000);
403                 s3c_freq->freq_table = s3c2450_freq_table;
404                 policy->cpuinfo.max_freq = 534000;
405         }
406
407         /* not needed anymore */
408         clk_put(msysclk);
409
410         if (s3c_freq->freq_table == NULL) {
411                 pr_err("cpufreq: No frequency information for this CPU, msysclk at %lukHz\n",
412                        rate / 1000);
413                 return -ENODEV;
414         }
415
416         s3c_freq->is_dvs = 0;
417
418         s3c_freq->armdiv = clk_get(NULL, "armdiv");
419         if (IS_ERR(s3c_freq->armdiv)) {
420                 ret = PTR_ERR(s3c_freq->armdiv);
421                 pr_err("cpufreq: Unable to obtain ARMDIV: %d\n", ret);
422                 return ret;
423         }
424
425         s3c_freq->hclk = clk_get(NULL, "hclk");
426         if (IS_ERR(s3c_freq->hclk)) {
427                 ret = PTR_ERR(s3c_freq->hclk);
428                 pr_err("cpufreq: Unable to obtain HCLK: %d\n", ret);
429                 goto err_hclk;
430         }
431
432         /* chech hclk rate, we only support the common 133MHz for now
433          * hclk could also run at 66MHz, but this not often used
434          */
435         rate = clk_get_rate(s3c_freq->hclk);
436         if (rate < 133 * 1000 * 1000) {
437                 pr_err("cpufreq: HCLK not at 133MHz\n");
438                 clk_put(s3c_freq->hclk);
439                 ret = -EINVAL;
440                 goto err_armclk;
441         }
442
443         s3c_freq->armclk = clk_get(NULL, "armclk");
444         if (IS_ERR(s3c_freq->armclk)) {
445                 ret = PTR_ERR(s3c_freq->armclk);
446                 pr_err("cpufreq: Unable to obtain ARMCLK: %d\n", ret);
447                 goto err_armclk;
448         }
449
450 #ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
451         s3c_freq->vddarm = regulator_get(NULL, "vddarm");
452         if (IS_ERR(s3c_freq->vddarm)) {
453                 ret = PTR_ERR(s3c_freq->vddarm);
454                 pr_err("cpufreq: Failed to obtain VDDARM: %d\n", ret);
455                 goto err_vddarm;
456         }
457
458         s3c2416_cpufreq_cfg_regulator(s3c_freq);
459 #else
460         s3c_freq->regulator_latency = 0;
461 #endif
462
463         freq = s3c_freq->freq_table;
464         while (freq->frequency != CPUFREQ_TABLE_END) {
465                 /* special handling for dvs mode */
466                 if (freq->index == 0) {
467                         if (!s3c_freq->hclk) {
468                                 pr_debug("cpufreq: %dkHz unsupported as it would need unavailable dvs mode\n",
469                                          freq->frequency);
470                                 freq->frequency = CPUFREQ_ENTRY_INVALID;
471                         } else {
472                                 freq++;
473                                 continue;
474                         }
475                 }
476
477                 /* Check for frequencies we can generate */
478                 rate = clk_round_rate(s3c_freq->armdiv,
479                                       freq->frequency * 1000);
480                 rate /= 1000;
481                 if (rate != freq->frequency) {
482                         pr_debug("cpufreq: %dkHz unsupported by clock (clk_round_rate return %lu)\n",
483                                  freq->frequency, rate);
484                         freq->frequency = CPUFREQ_ENTRY_INVALID;
485                 }
486
487                 freq++;
488         }
489
490         policy->cur = clk_get_rate(s3c_freq->armclk) / 1000;
491
492         /* Datasheet says PLL stabalisation time must be at least 300us,
493          * so but add some fudge. (reference in LOCKCON0 register description)
494          */
495         policy->cpuinfo.transition_latency = (500 * 1000) +
496                                              s3c_freq->regulator_latency;
497
498         ret = cpufreq_frequency_table_cpuinfo(policy, s3c_freq->freq_table);
499         if (ret)
500                 goto err_freq_table;
501
502         cpufreq_frequency_table_get_attr(s3c_freq->freq_table, 0);
503
504         register_reboot_notifier(&s3c2416_cpufreq_reboot_notifier);
505
506         return 0;
507
508 err_freq_table:
509 #ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
510         regulator_put(s3c_freq->vddarm);
511 err_vddarm:
512 #endif
513         clk_put(s3c_freq->armclk);
514 err_armclk:
515         clk_put(s3c_freq->hclk);
516 err_hclk:
517         clk_put(s3c_freq->armdiv);
518
519         return ret;
520 }
521
522 static struct freq_attr *s3c2416_cpufreq_attr[] = {
523         &cpufreq_freq_attr_scaling_available_freqs,
524         NULL,
525 };
526
527 static struct cpufreq_driver s3c2416_cpufreq_driver = {
528         .owner          = THIS_MODULE,
529         .flags          = 0,
530         .verify         = s3c2416_cpufreq_verify_speed,
531         .target         = s3c2416_cpufreq_set_target,
532         .get            = s3c2416_cpufreq_get_speed,
533         .init           = s3c2416_cpufreq_driver_init,
534         .name           = "s3c2416",
535         .attr           = s3c2416_cpufreq_attr,
536 };
537
538 static int __init s3c2416_cpufreq_init(void)
539 {
540         return cpufreq_register_driver(&s3c2416_cpufreq_driver);
541 }
542 module_init(s3c2416_cpufreq_init);