aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-tegra/clock.c
diff options
context:
space:
mode:
authorColin Cross <ccross@android.com>2010-06-07 23:49:46 -0400
committerColin Cross <ccross@android.com>2010-10-21 21:12:19 -0400
commit71fc84cc35ee05913306bfe6e2454cdfc5bf7081 (patch)
tree0847b21ba9208dbfc5773c0fada2528da537add6 /arch/arm/mach-tegra/clock.c
parent73625e3e2e2bc36198f5b43e0f32d9dfb8e3b77c (diff)
[ARM] tegra: clock: Add dvfs support, bug fixes, and cleanups
- Add drivers to clock lookup table - Add new pll_m entries - Support I2C U16 divider - Fix rate reporting on 32.768kHz clock - Call propagate rate only if set_rate succeeds - Add support for audio_sync clock - Add 24MHz to PLLA frequency list - Correct i2s1/2/spdifout mux - Add suspend support - Fix enable/disable parent clocks in set_parent - Add max_rate parameter to all clocks - DVFS support - Add virtual cpu clock with dvfs - Support clk_round_rate - Fix requesting very high periph frequencies - Add quirks for PLLU: PLLU is slightly different from the rest of the PLLs. The lock enable bit is at bit 22 instead of 18 in the MISC register, and the post divider field is a single bit with reversed values from other PLLs. - Simplify recalculating clock rates - Fix UART divider flags - Remove unused clock ops Signed-off-by: Colin Cross <ccross@android.com>
Diffstat (limited to 'arch/arm/mach-tegra/clock.c')
-rw-r--r--arch/arm/mach-tegra/clock.c267
1 files changed, 244 insertions, 23 deletions
diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c
index 03ad578349b9..ae19f95585be 100644
--- a/arch/arm/mach-tegra/clock.c
+++ b/arch/arm/mach-tegra/clock.c
@@ -24,13 +24,80 @@
24#include <linux/debugfs.h> 24#include <linux/debugfs.h>
25#include <linux/slab.h> 25#include <linux/slab.h>
26#include <linux/seq_file.h> 26#include <linux/seq_file.h>
27#include <linux/regulator/consumer.h>
27#include <asm/clkdev.h> 28#include <asm/clkdev.h>
28 29
29#include "clock.h" 30#include "clock.h"
31#include "board.h"
32#include "fuse.h"
30 33
31static LIST_HEAD(clocks); 34static LIST_HEAD(clocks);
32 35
33static DEFINE_SPINLOCK(clock_lock); 36static DEFINE_SPINLOCK(clock_lock);
37static DEFINE_MUTEX(dvfs_lock);
38
39static int clk_is_dvfs(struct clk *c)
40{
41 return (c->dvfs != NULL);
42};
43
44static int dvfs_set_rate(struct dvfs *d, unsigned long rate)
45{
46 struct dvfs_table *t;
47
48 if (d->table == NULL)
49 return -ENODEV;
50
51 for (t = d->table; t->rate != 0; t++) {
52 if (rate <= t->rate) {
53 if (!d->reg)
54 return 0;
55
56 return regulator_set_voltage(d->reg,
57 t->millivolts * 1000,
58 d->max_millivolts * 1000);
59 }
60 }
61
62 return -EINVAL;
63}
64
65static void dvfs_init(struct clk *c)
66{
67 int process_id;
68 int i;
69 struct dvfs_table *table;
70
71 process_id = c->dvfs->cpu ? tegra_core_process_id() :
72 tegra_cpu_process_id();
73
74 for (i = 0; i < c->dvfs->process_id_table_length; i++)
75 if (process_id == c->dvfs->process_id_table[i].process_id)
76 c->dvfs->table = c->dvfs->process_id_table[i].table;
77
78 if (c->dvfs->table == NULL) {
79 pr_err("Failed to find dvfs table for clock %s process %d\n",
80 c->name, process_id);
81 return;
82 }
83
84 c->dvfs->max_millivolts = 0;
85 for (table = c->dvfs->table; table->rate != 0; table++)
86 if (c->dvfs->max_millivolts < table->millivolts)
87 c->dvfs->max_millivolts = table->millivolts;
88
89 c->dvfs->reg = regulator_get(NULL, c->dvfs->reg_id);
90
91 if (IS_ERR(c->dvfs->reg)) {
92 pr_err("Failed to get regulator %s for clock %s\n",
93 c->dvfs->reg_id, c->name);
94 c->dvfs->reg = NULL;
95 return;
96 }
97
98 if (c->refcnt > 0)
99 dvfs_set_rate(c->dvfs, c->rate);
100}
34 101
35struct clk *tegra_get_clock_by_name(const char *name) 102struct clk *tegra_get_clock_by_name(const char *name)
36{ 103{
@@ -48,14 +115,31 @@ struct clk *tegra_get_clock_by_name(const char *name)
48 return ret; 115 return ret;
49} 116}
50 117
118static void clk_recalculate_rate(struct clk *c)
119{
120 u64 rate;
121
122 if (!c->parent)
123 return;
124
125 rate = c->parent->rate;
126
127 if (c->mul != 0 && c->div != 0) {
128 rate = rate * c->mul;
129 do_div(rate, c->div);
130 }
131
132 if (rate > c->max_rate)
133 pr_warn("clocks: Set clock %s to rate %llu, max is %lu\n",
134 c->name, rate, c->max_rate);
135
136 c->rate = rate;
137}
138
51int clk_reparent(struct clk *c, struct clk *parent) 139int clk_reparent(struct clk *c, struct clk *parent)
52{ 140{
53 pr_debug("%s: %s\n", __func__, c->name); 141 pr_debug("%s: %s\n", __func__, c->name);
54 if (c->refcnt && c->parent)
55 clk_disable_locked(c->parent);
56 c->parent = parent; 142 c->parent = parent;
57 if (c->refcnt && c->parent)
58 clk_enable_locked(c->parent);
59 list_del(&c->sibling); 143 list_del(&c->sibling);
60 list_add_tail(&c->sibling, &parent->children); 144 list_add_tail(&c->sibling, &parent->children);
61 return 0; 145 return 0;
@@ -67,8 +151,7 @@ static void propagate_rate(struct clk *c)
67 pr_debug("%s: %s\n", __func__, c->name); 151 pr_debug("%s: %s\n", __func__, c->name);
68 list_for_each_entry(clkp, &c->children, sibling) { 152 list_for_each_entry(clkp, &c->children, sibling) {
69 pr_debug(" %s\n", clkp->name); 153 pr_debug(" %s\n", clkp->name);
70 if (clkp->ops->recalculate_rate) 154 clk_recalculate_rate(clkp);
71 clkp->ops->recalculate_rate(clkp);
72 propagate_rate(clkp); 155 propagate_rate(clkp);
73 } 156 }
74} 157}
@@ -77,6 +160,8 @@ void clk_init(struct clk *c)
77{ 160{
78 unsigned long flags; 161 unsigned long flags;
79 162
163 pr_debug("%s: %s\n", __func__, c->name);
164
80 spin_lock_irqsave(&clock_lock, flags); 165 spin_lock_irqsave(&clock_lock, flags);
81 166
82 INIT_LIST_HEAD(&c->children); 167 INIT_LIST_HEAD(&c->children);
@@ -85,6 +170,8 @@ void clk_init(struct clk *c)
85 if (c->ops && c->ops->init) 170 if (c->ops && c->ops->init)
86 c->ops->init(c); 171 c->ops->init(c);
87 172
173 clk_recalculate_rate(c);
174
88 list_add(&c->node, &clocks); 175 list_add(&c->node, &clocks);
89 176
90 if (c->parent) 177 if (c->parent)
@@ -122,13 +209,38 @@ int clk_enable_locked(struct clk *c)
122 return 0; 209 return 0;
123} 210}
124 211
212int clk_enable_cansleep(struct clk *c)
213{
214 int ret;
215 unsigned long flags;
216
217 mutex_lock(&dvfs_lock);
218
219 if (clk_is_dvfs(c) && c->refcnt > 0)
220 dvfs_set_rate(c->dvfs, c->rate);
221
222 spin_lock_irqsave(&clock_lock, flags);
223 ret = clk_enable_locked(c);
224 spin_unlock_irqrestore(&clock_lock, flags);
225
226 mutex_unlock(&dvfs_lock);
227
228 return ret;
229}
230EXPORT_SYMBOL(clk_enable_cansleep);
231
125int clk_enable(struct clk *c) 232int clk_enable(struct clk *c)
126{ 233{
127 int ret; 234 int ret;
128 unsigned long flags; 235 unsigned long flags;
236
237 if (clk_is_dvfs(c))
238 BUG();
239
129 spin_lock_irqsave(&clock_lock, flags); 240 spin_lock_irqsave(&clock_lock, flags);
130 ret = clk_enable_locked(c); 241 ret = clk_enable_locked(c);
131 spin_unlock_irqrestore(&clock_lock, flags); 242 spin_unlock_irqrestore(&clock_lock, flags);
243
132 return ret; 244 return ret;
133} 245}
134EXPORT_SYMBOL(clk_enable); 246EXPORT_SYMBOL(clk_enable);
@@ -152,9 +264,30 @@ void clk_disable_locked(struct clk *c)
152 c->refcnt--; 264 c->refcnt--;
153} 265}
154 266
267void clk_disable_cansleep(struct clk *c)
268{
269 unsigned long flags;
270
271 mutex_lock(&dvfs_lock);
272
273 spin_lock_irqsave(&clock_lock, flags);
274 clk_disable_locked(c);
275 spin_unlock_irqrestore(&clock_lock, flags);
276
277 if (clk_is_dvfs(c) && c->refcnt == 0)
278 dvfs_set_rate(c->dvfs, c->rate);
279
280 mutex_unlock(&dvfs_lock);
281}
282EXPORT_SYMBOL(clk_disable_cansleep);
283
155void clk_disable(struct clk *c) 284void clk_disable(struct clk *c)
156{ 285{
157 unsigned long flags; 286 unsigned long flags;
287
288 if (clk_is_dvfs(c))
289 BUG();
290
158 spin_lock_irqsave(&clock_lock, flags); 291 spin_lock_irqsave(&clock_lock, flags);
159 clk_disable_locked(c); 292 clk_disable_locked(c);
160 spin_unlock_irqrestore(&clock_lock, flags); 293 spin_unlock_irqrestore(&clock_lock, flags);
@@ -175,6 +308,8 @@ int clk_set_parent_locked(struct clk *c, struct clk *parent)
175 if (ret) 308 if (ret)
176 return ret; 309 return ret;
177 310
311 clk_recalculate_rate(c);
312
178 propagate_rate(c); 313 propagate_rate(c);
179 314
180 return 0; 315 return 0;
@@ -197,22 +332,69 @@ struct clk *clk_get_parent(struct clk *c)
197} 332}
198EXPORT_SYMBOL(clk_get_parent); 333EXPORT_SYMBOL(clk_get_parent);
199 334
200int clk_set_rate(struct clk *c, unsigned long rate) 335int clk_set_rate_locked(struct clk *c, unsigned long rate)
336{
337 int ret;
338
339 if (rate > c->max_rate)
340 rate = c->max_rate;
341
342 if (!c->ops || !c->ops->set_rate)
343 return -ENOSYS;
344
345 ret = c->ops->set_rate(c, rate);
346
347 if (ret)
348 return ret;
349
350 clk_recalculate_rate(c);
351
352 propagate_rate(c);
353
354 return 0;
355}
356
357int clk_set_rate_cansleep(struct clk *c, unsigned long rate)
201{ 358{
202 int ret = 0; 359 int ret = 0;
203 unsigned long flags; 360 unsigned long flags;
204 361
362 pr_debug("%s: %s\n", __func__, c->name);
363
364 mutex_lock(&dvfs_lock);
365
366 if (rate > c->rate)
367 ret = dvfs_set_rate(c->dvfs, rate);
368 if (ret)
369 goto out;
370
205 spin_lock_irqsave(&clock_lock, flags); 371 spin_lock_irqsave(&clock_lock, flags);
372 ret = clk_set_rate_locked(c, rate);
373 spin_unlock_irqrestore(&clock_lock, flags);
206 374
207 pr_debug("%s: %s\n", __func__, c->name); 375 if (ret)
376 goto out;
208 377
209 if (c->ops && c->ops->set_rate) 378 ret = dvfs_set_rate(c->dvfs, rate);
210 ret = c->ops->set_rate(c, rate);
211 else
212 ret = -ENOSYS;
213 379
214 propagate_rate(c); 380out:
381 mutex_unlock(&dvfs_lock);
382 return ret;
383}
384EXPORT_SYMBOL(clk_set_rate_cansleep);
385
386int clk_set_rate(struct clk *c, unsigned long rate)
387{
388 int ret = 0;
389 unsigned long flags;
390
391 pr_debug("%s: %s\n", __func__, c->name);
392
393 if (clk_is_dvfs(c))
394 BUG();
215 395
396 spin_lock_irqsave(&clock_lock, flags);
397 ret = clk_set_rate_locked(c, rate);
216 spin_unlock_irqrestore(&clock_lock, flags); 398 spin_unlock_irqrestore(&clock_lock, flags);
217 399
218 return ret; 400 return ret;
@@ -235,6 +417,20 @@ unsigned long clk_get_rate(struct clk *c)
235} 417}
236EXPORT_SYMBOL(clk_get_rate); 418EXPORT_SYMBOL(clk_get_rate);
237 419
420long clk_round_rate(struct clk *c, unsigned long rate)
421{
422 pr_debug("%s: %s\n", __func__, c->name);
423
424 if (!c->ops || !c->ops->round_rate)
425 return -ENOSYS;
426
427 if (rate > c->max_rate)
428 rate = c->max_rate;
429
430 return c->ops->round_rate(c, rate);
431}
432EXPORT_SYMBOL(clk_round_rate);
433
238static int tegra_clk_init_one_from_table(struct tegra_clk_init_table *table) 434static int tegra_clk_init_one_from_table(struct tegra_clk_init_table *table)
239{ 435{
240 struct clk *c; 436 struct clk *c;
@@ -308,13 +504,28 @@ void tegra_periph_reset_assert(struct clk *c)
308} 504}
309EXPORT_SYMBOL(tegra_periph_reset_assert); 505EXPORT_SYMBOL(tegra_periph_reset_assert);
310 506
311int __init tegra_init_clock(void) 507void __init tegra_init_clock(void)
312{ 508{
313 tegra2_init_clocks(); 509 tegra2_init_clocks();
510}
511
512int __init tegra_init_dvfs(void)
513{
514 struct clk *c, *safe;
515
516 mutex_lock(&dvfs_lock);
517
518 list_for_each_entry_safe(c, safe, &clocks, node)
519 if (c->dvfs)
520 dvfs_init(c);
521
522 mutex_unlock(&dvfs_lock);
314 523
315 return 0; 524 return 0;
316} 525}
317 526
527late_initcall(tegra_init_dvfs);
528
318#ifdef CONFIG_DEBUG_FS 529#ifdef CONFIG_DEBUG_FS
319static struct dentry *clk_debugfs_root; 530static struct dentry *clk_debugfs_root;
320 531
@@ -324,7 +535,7 @@ static void clock_tree_show_one(struct seq_file *s, struct clk *c, int level)
324 struct clk *child; 535 struct clk *child;
325 struct clk *safe; 536 struct clk *safe;
326 const char *state = "uninit"; 537 const char *state = "uninit";
327 char div[5] = {0}; 538 char div[8] = {0};
328 539
329 if (c->state == ON) 540 if (c->state == ON)
330 state = "on"; 541 state = "on";
@@ -332,16 +543,26 @@ static void clock_tree_show_one(struct seq_file *s, struct clk *c, int level)
332 state = "off"; 543 state = "off";
333 544
334 if (c->mul != 0 && c->div != 0) { 545 if (c->mul != 0 && c->div != 0) {
335 BUG_ON(c->mul > 2); 546 if (c->mul > c->div) {
336 if (c->mul > c->div) 547 int mul = c->mul / c->div;
337 snprintf(div, sizeof(div), "x%d", c->mul / c->div); 548 int mul2 = (c->mul * 10 / c->div) % 10;
338 else 549 int mul3 = (c->mul * 10) % c->div;
550 if (mul2 == 0 && mul3 == 0)
551 snprintf(div, sizeof(div), "x%d", mul);
552 else if (mul3 == 0)
553 snprintf(div, sizeof(div), "x%d.%d", mul, mul2);
554 else
555 snprintf(div, sizeof(div), "x%d.%d..", mul, mul2);
556 } else {
339 snprintf(div, sizeof(div), "%d%s", c->div / c->mul, 557 snprintf(div, sizeof(div), "%d%s", c->div / c->mul,
340 (c->div % c->mul) ? ".5" : ""); 558 (c->div % c->mul) ? ".5" : "");
559 }
341 } 560 }
342 561
343 seq_printf(s, "%*s%-*s %-6s %-3d %-5s %-10lu\n", 562 seq_printf(s, "%*s%c%c%-*s %-6s %-3d %-8s %-10lu\n",
344 level * 3 + 1, c->set ? "" : "*", 563 level * 3 + 1, "",
564 c->rate > c->max_rate ? '!' : ' ',
565 !c->set ? '*' : ' ',
345 30 - level * 3, c->name, 566 30 - level * 3, c->name,
346 state, c->refcnt, div, c->rate); 567 state, c->refcnt, div, c->rate);
347 list_for_each_entry_safe(child, safe, &c->children, sibling) { 568 list_for_each_entry_safe(child, safe, &c->children, sibling) {
@@ -353,8 +574,8 @@ static int clock_tree_show(struct seq_file *s, void *data)
353{ 574{
354 struct clk *c; 575 struct clk *c;
355 unsigned long flags; 576 unsigned long flags;
356 seq_printf(s, " clock state ref div rate \n"); 577 seq_printf(s, " clock state ref div rate\n");
357 seq_printf(s, "-----------------------------------------------------------\n"); 578 seq_printf(s, "--------------------------------------------------------------\n");
358 spin_lock_irqsave(&clock_lock, flags); 579 spin_lock_irqsave(&clock_lock, flags);
359 list_for_each_entry(c, &clocks, node) 580 list_for_each_entry(c, &clocks, node)
360 if (c->parent == NULL) 581 if (c->parent == NULL)