blob: 8fd96bfb0cde9b76126cab2dd837a326f99049a9 [file] [log] [blame]
Colin Crossd8611962010-01-28 16:40:29 -08001/*
2 *
3 * Copyright (C) 2010 Google, Inc.
4 *
5 * Author:
6 * Colin Cross <ccross@google.com>
7 *
8 * This software is licensed under the terms of the GNU General Public
9 * License version 2, as published by the Free Software Foundation, and
10 * may be copied, distributed, and modified under those terms.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 */
18
19#include <linux/kernel.h>
20#include <linux/clk.h>
21#include <linux/list.h>
22#include <linux/init.h>
23#include <linux/module.h>
24#include <linux/debugfs.h>
25#include <linux/slab.h>
26#include <linux/seq_file.h>
Jean-Christop PLAGNIOL-VILLARD6d803ba2010-11-17 10:04:33 +010027#include <linux/clkdev.h>
Colin Crossd8611962010-01-28 16:40:29 -080028
Colin Cross71fc84c2010-06-07 20:49:46 -070029#include "board.h"
Colin Cross41cfe362011-02-12 15:52:04 -080030#include "clock.h"
Colin Crossd8611962010-01-28 16:40:29 -080031
32static LIST_HEAD(clocks);
33
34static DEFINE_SPINLOCK(clock_lock);
Colin Crossd8611962010-01-28 16:40:29 -080035struct clk *tegra_get_clock_by_name(const char *name)
36{
37 struct clk *c;
38 struct clk *ret = NULL;
39 unsigned long flags;
40 spin_lock_irqsave(&clock_lock, flags);
41 list_for_each_entry(c, &clocks, node) {
42 if (strcmp(c->name, name) == 0) {
43 ret = c;
44 break;
45 }
46 }
47 spin_unlock_irqrestore(&clock_lock, flags);
48 return ret;
49}
50
Colin Cross71fc84c2010-06-07 20:49:46 -070051static void clk_recalculate_rate(struct clk *c)
52{
53 u64 rate;
54
55 if (!c->parent)
56 return;
57
58 rate = c->parent->rate;
59
60 if (c->mul != 0 && c->div != 0) {
61 rate = rate * c->mul;
62 do_div(rate, c->div);
63 }
64
65 if (rate > c->max_rate)
66 pr_warn("clocks: Set clock %s to rate %llu, max is %lu\n",
67 c->name, rate, c->max_rate);
68
69 c->rate = rate;
70}
71
Colin Crossd8611962010-01-28 16:40:29 -080072int clk_reparent(struct clk *c, struct clk *parent)
73{
Colin Crossd8611962010-01-28 16:40:29 -080074 c->parent = parent;
Colin Crossd8611962010-01-28 16:40:29 -080075 list_del(&c->sibling);
76 list_add_tail(&c->sibling, &parent->children);
77 return 0;
78}
79
80static void propagate_rate(struct clk *c)
81{
82 struct clk *clkp;
Colin Crossbd41ef52010-09-08 20:01:04 -070083
Colin Crossd8611962010-01-28 16:40:29 -080084 list_for_each_entry(clkp, &c->children, sibling) {
Colin Cross71fc84c2010-06-07 20:49:46 -070085 clk_recalculate_rate(clkp);
Colin Crossd8611962010-01-28 16:40:29 -080086 propagate_rate(clkp);
87 }
88}
89
90void clk_init(struct clk *c)
91{
92 unsigned long flags;
93
94 spin_lock_irqsave(&clock_lock, flags);
95
96 INIT_LIST_HEAD(&c->children);
97 INIT_LIST_HEAD(&c->sibling);
98
99 if (c->ops && c->ops->init)
100 c->ops->init(c);
101
Colin Crossf0355302010-10-13 19:16:02 -0700102 if (!c->ops || !c->ops->enable) {
103 c->refcnt++;
104 c->set = 1;
105 if (c->parent)
106 c->state = c->parent->state;
107 else
108 c->state = ON;
109 }
110
Colin Cross71fc84c2010-06-07 20:49:46 -0700111 clk_recalculate_rate(c);
112
Colin Crossd8611962010-01-28 16:40:29 -0800113 list_add(&c->node, &clocks);
114
115 if (c->parent)
116 list_add_tail(&c->sibling, &c->parent->children);
117
118 spin_unlock_irqrestore(&clock_lock, flags);
119}
120
121int clk_enable_locked(struct clk *c)
122{
123 int ret;
Colin Crossbd41ef52010-09-08 20:01:04 -0700124
Colin Crossd8611962010-01-28 16:40:29 -0800125 if (c->refcnt == 0) {
126 if (c->parent) {
127 ret = clk_enable_locked(c->parent);
128 if (ret)
129 return ret;
130 }
131
132 if (c->ops && c->ops->enable) {
133 ret = c->ops->enable(c);
134 if (ret) {
135 if (c->parent)
136 clk_disable_locked(c->parent);
137 return ret;
138 }
139 c->state = ON;
140#ifdef CONFIG_DEBUG_FS
141 c->set = 1;
142#endif
143 }
144 }
145 c->refcnt++;
146
147 return 0;
148}
149
150int clk_enable(struct clk *c)
151{
152 int ret;
153 unsigned long flags;
Colin Cross71fc84c2010-06-07 20:49:46 -0700154
Colin Crossd8611962010-01-28 16:40:29 -0800155 spin_lock_irqsave(&clock_lock, flags);
156 ret = clk_enable_locked(c);
157 spin_unlock_irqrestore(&clock_lock, flags);
Colin Cross71fc84c2010-06-07 20:49:46 -0700158
Colin Crossd8611962010-01-28 16:40:29 -0800159 return ret;
160}
161EXPORT_SYMBOL(clk_enable);
162
163void clk_disable_locked(struct clk *c)
164{
Colin Crossd8611962010-01-28 16:40:29 -0800165 if (c->refcnt == 0) {
166 WARN(1, "Attempting to disable clock %s with refcnt 0", c->name);
167 return;
168 }
169 if (c->refcnt == 1) {
170 if (c->ops && c->ops->disable)
171 c->ops->disable(c);
172
173 if (c->parent)
174 clk_disable_locked(c->parent);
175
176 c->state = OFF;
177 }
178 c->refcnt--;
179}
180
181void clk_disable(struct clk *c)
182{
183 unsigned long flags;
Colin Cross71fc84c2010-06-07 20:49:46 -0700184
Colin Crossd8611962010-01-28 16:40:29 -0800185 spin_lock_irqsave(&clock_lock, flags);
186 clk_disable_locked(c);
187 spin_unlock_irqrestore(&clock_lock, flags);
188}
189EXPORT_SYMBOL(clk_disable);
190
191int clk_set_parent_locked(struct clk *c, struct clk *parent)
192{
193 int ret;
194
Colin Crossd8611962010-01-28 16:40:29 -0800195 if (!c->ops || !c->ops->set_parent)
196 return -ENOSYS;
197
198 ret = c->ops->set_parent(c, parent);
199
200 if (ret)
201 return ret;
202
Colin Cross71fc84c2010-06-07 20:49:46 -0700203 clk_recalculate_rate(c);
204
Colin Crossd8611962010-01-28 16:40:29 -0800205 propagate_rate(c);
206
207 return 0;
208}
209
210int clk_set_parent(struct clk *c, struct clk *parent)
211{
212 int ret;
213 unsigned long flags;
214 spin_lock_irqsave(&clock_lock, flags);
215 ret = clk_set_parent_locked(c, parent);
216 spin_unlock_irqrestore(&clock_lock, flags);
217 return ret;
218}
219EXPORT_SYMBOL(clk_set_parent);
220
221struct clk *clk_get_parent(struct clk *c)
222{
223 return c->parent;
224}
225EXPORT_SYMBOL(clk_get_parent);
226
Colin Cross71fc84c2010-06-07 20:49:46 -0700227int clk_set_rate_locked(struct clk *c, unsigned long rate)
228{
229 int ret;
230
231 if (rate > c->max_rate)
232 rate = c->max_rate;
233
234 if (!c->ops || !c->ops->set_rate)
235 return -ENOSYS;
236
237 ret = c->ops->set_rate(c, rate);
238
239 if (ret)
240 return ret;
241
242 clk_recalculate_rate(c);
243
244 propagate_rate(c);
245
246 return 0;
247}
248
Colin Crossd8611962010-01-28 16:40:29 -0800249int clk_set_rate(struct clk *c, unsigned long rate)
250{
251 int ret = 0;
252 unsigned long flags;
253
Colin Cross71fc84c2010-06-07 20:49:46 -0700254 spin_lock_irqsave(&clock_lock, flags);
255 ret = clk_set_rate_locked(c, rate);
Colin Crossd8611962010-01-28 16:40:29 -0800256 spin_unlock_irqrestore(&clock_lock, flags);
257
258 return ret;
259}
260EXPORT_SYMBOL(clk_set_rate);
261
262unsigned long clk_get_rate(struct clk *c)
263{
264 unsigned long flags;
265 unsigned long ret;
266
267 spin_lock_irqsave(&clock_lock, flags);
268
Colin Crossd8611962010-01-28 16:40:29 -0800269 ret = c->rate;
270
271 spin_unlock_irqrestore(&clock_lock, flags);
272 return ret;
273}
274EXPORT_SYMBOL(clk_get_rate);
275
Colin Cross71fc84c2010-06-07 20:49:46 -0700276long clk_round_rate(struct clk *c, unsigned long rate)
277{
Colin Cross71fc84c2010-06-07 20:49:46 -0700278 if (!c->ops || !c->ops->round_rate)
279 return -ENOSYS;
280
281 if (rate > c->max_rate)
282 rate = c->max_rate;
283
284 return c->ops->round_rate(c, rate);
285}
286EXPORT_SYMBOL(clk_round_rate);
287
Colin Crossd8611962010-01-28 16:40:29 -0800288static int tegra_clk_init_one_from_table(struct tegra_clk_init_table *table)
289{
290 struct clk *c;
291 struct clk *p;
292
293 int ret = 0;
294
295 c = tegra_get_clock_by_name(table->name);
296
297 if (!c) {
298 pr_warning("Unable to initialize clock %s\n",
299 table->name);
300 return -ENODEV;
301 }
302
303 if (table->parent) {
304 p = tegra_get_clock_by_name(table->parent);
305 if (!p) {
306 pr_warning("Unable to find parent %s of clock %s\n",
307 table->parent, table->name);
308 return -ENODEV;
309 }
310
311 if (c->parent != p) {
312 ret = clk_set_parent(c, p);
313 if (ret) {
314 pr_warning("Unable to set parent %s of clock %s: %d\n",
315 table->parent, table->name, ret);
316 return -EINVAL;
317 }
318 }
319 }
320
321 if (table->rate && table->rate != clk_get_rate(c)) {
322 ret = clk_set_rate(c, table->rate);
323 if (ret) {
324 pr_warning("Unable to set clock %s to rate %lu: %d\n",
325 table->name, table->rate, ret);
326 return -EINVAL;
327 }
328 }
329
330 if (table->enabled) {
331 ret = clk_enable(c);
332 if (ret) {
333 pr_warning("Unable to enable clock %s: %d\n",
334 table->name, ret);
335 return -EINVAL;
336 }
337 }
338
339 return 0;
340}
341
342void tegra_clk_init_from_table(struct tegra_clk_init_table *table)
343{
344 for (; table->name; table++)
345 tegra_clk_init_one_from_table(table);
346}
347EXPORT_SYMBOL(tegra_clk_init_from_table);
348
349void tegra_periph_reset_deassert(struct clk *c)
350{
351 tegra2_periph_reset_deassert(c);
352}
353EXPORT_SYMBOL(tegra_periph_reset_deassert);
354
355void tegra_periph_reset_assert(struct clk *c)
356{
357 tegra2_periph_reset_assert(c);
358}
359EXPORT_SYMBOL(tegra_periph_reset_assert);
360
Colin Cross71fc84c2010-06-07 20:49:46 -0700361void __init tegra_init_clock(void)
Colin Crossd8611962010-01-28 16:40:29 -0800362{
363 tegra2_init_clocks();
Colin Cross71fc84c2010-06-07 20:49:46 -0700364}
365
Colin Crossd8611962010-01-28 16:40:29 -0800366#ifdef CONFIG_DEBUG_FS
367static struct dentry *clk_debugfs_root;
368
369
370static void clock_tree_show_one(struct seq_file *s, struct clk *c, int level)
371{
372 struct clk *child;
373 struct clk *safe;
374 const char *state = "uninit";
Colin Cross71fc84c2010-06-07 20:49:46 -0700375 char div[8] = {0};
Colin Crossd8611962010-01-28 16:40:29 -0800376
377 if (c->state == ON)
378 state = "on";
379 else if (c->state == OFF)
380 state = "off";
381
382 if (c->mul != 0 && c->div != 0) {
Colin Cross71fc84c2010-06-07 20:49:46 -0700383 if (c->mul > c->div) {
384 int mul = c->mul / c->div;
385 int mul2 = (c->mul * 10 / c->div) % 10;
386 int mul3 = (c->mul * 10) % c->div;
387 if (mul2 == 0 && mul3 == 0)
388 snprintf(div, sizeof(div), "x%d", mul);
389 else if (mul3 == 0)
390 snprintf(div, sizeof(div), "x%d.%d", mul, mul2);
391 else
392 snprintf(div, sizeof(div), "x%d.%d..", mul, mul2);
393 } else {
Colin Crossd8611962010-01-28 16:40:29 -0800394 snprintf(div, sizeof(div), "%d%s", c->div / c->mul,
395 (c->div % c->mul) ? ".5" : "");
Colin Cross71fc84c2010-06-07 20:49:46 -0700396 }
Colin Crossd8611962010-01-28 16:40:29 -0800397 }
398
Colin Cross71fc84c2010-06-07 20:49:46 -0700399 seq_printf(s, "%*s%c%c%-*s %-6s %-3d %-8s %-10lu\n",
400 level * 3 + 1, "",
401 c->rate > c->max_rate ? '!' : ' ',
402 !c->set ? '*' : ' ',
Colin Crossd8611962010-01-28 16:40:29 -0800403 30 - level * 3, c->name,
404 state, c->refcnt, div, c->rate);
405 list_for_each_entry_safe(child, safe, &c->children, sibling) {
406 clock_tree_show_one(s, child, level + 1);
407 }
408}
409
410static int clock_tree_show(struct seq_file *s, void *data)
411{
412 struct clk *c;
413 unsigned long flags;
Colin Cross71fc84c2010-06-07 20:49:46 -0700414 seq_printf(s, " clock state ref div rate\n");
415 seq_printf(s, "--------------------------------------------------------------\n");
Colin Crossd8611962010-01-28 16:40:29 -0800416 spin_lock_irqsave(&clock_lock, flags);
417 list_for_each_entry(c, &clocks, node)
418 if (c->parent == NULL)
419 clock_tree_show_one(s, c, 0);
420 spin_unlock_irqrestore(&clock_lock, flags);
421 return 0;
422}
423
424static int clock_tree_open(struct inode *inode, struct file *file)
425{
426 return single_open(file, clock_tree_show, inode->i_private);
427}
428
429static const struct file_operations clock_tree_fops = {
430 .open = clock_tree_open,
431 .read = seq_read,
432 .llseek = seq_lseek,
433 .release = single_release,
434};
435
436static int possible_parents_show(struct seq_file *s, void *data)
437{
438 struct clk *c = s->private;
439 int i;
440
441 for (i = 0; c->inputs[i].input; i++) {
442 char *first = (i == 0) ? "" : " ";
443 seq_printf(s, "%s%s", first, c->inputs[i].input->name);
444 }
445 seq_printf(s, "\n");
446 return 0;
447}
448
449static int possible_parents_open(struct inode *inode, struct file *file)
450{
451 return single_open(file, possible_parents_show, inode->i_private);
452}
453
454static const struct file_operations possible_parents_fops = {
455 .open = possible_parents_open,
456 .read = seq_read,
457 .llseek = seq_lseek,
458 .release = single_release,
459};
460
461static int clk_debugfs_register_one(struct clk *c)
462{
463 struct dentry *d, *child, *child_tmp;
464
465 d = debugfs_create_dir(c->name, clk_debugfs_root);
466 if (!d)
467 return -ENOMEM;
468 c->dent = d;
469
470 d = debugfs_create_u8("refcnt", S_IRUGO, c->dent, (u8 *)&c->refcnt);
471 if (!d)
472 goto err_out;
473
474 d = debugfs_create_u32("rate", S_IRUGO, c->dent, (u32 *)&c->rate);
475 if (!d)
476 goto err_out;
477
478 d = debugfs_create_x32("flags", S_IRUGO, c->dent, (u32 *)&c->flags);
479 if (!d)
480 goto err_out;
481
482 if (c->inputs) {
483 d = debugfs_create_file("possible_parents", S_IRUGO, c->dent,
484 c, &possible_parents_fops);
485 if (!d)
486 goto err_out;
487 }
488
489 return 0;
490
491err_out:
492 d = c->dent;
493 list_for_each_entry_safe(child, child_tmp, &d->d_subdirs, d_u.d_child)
494 debugfs_remove(child);
495 debugfs_remove(c->dent);
496 return -ENOMEM;
497}
498
499static int clk_debugfs_register(struct clk *c)
500{
501 int err;
502 struct clk *pa = c->parent;
503
504 if (pa && !pa->dent) {
505 err = clk_debugfs_register(pa);
506 if (err)
507 return err;
508 }
509
510 if (!c->dent) {
511 err = clk_debugfs_register_one(c);
512 if (err)
513 return err;
514 }
515 return 0;
516}
517
518static int __init clk_debugfs_init(void)
519{
520 struct clk *c;
521 struct dentry *d;
522 int err = -ENOMEM;
523
524 d = debugfs_create_dir("clock", NULL);
525 if (!d)
526 return -ENOMEM;
527 clk_debugfs_root = d;
528
529 d = debugfs_create_file("clock_tree", S_IRUGO, clk_debugfs_root, NULL,
530 &clock_tree_fops);
531 if (!d)
532 goto err_out;
533
534 list_for_each_entry(c, &clocks, node) {
535 err = clk_debugfs_register(c);
536 if (err)
537 goto err_out;
538 }
539 return 0;
540err_out:
541 debugfs_remove_recursive(clk_debugfs_root);
542 return err;
543}
544
545late_initcall(clk_debugfs_init);
546#endif