Commit | Line | Data |
---|---|---|
1da177e4 | 1 | /* |
b9158556 | 2 | * linux/arch/arm/plat-omap/clock.c |
1da177e4 | 3 | * |
1a8bfa1e | 4 | * Copyright (C) 2004 - 2005 Nokia corporation |
1da177e4 LT |
5 | * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> |
6 | * | |
1a8bfa1e TL |
7 | * Modified for omap shared clock framework by Tony Lindgren <tony@atomide.com> |
8 | * | |
1da177e4 LT |
9 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License version 2 as | |
11 | * published by the Free Software Foundation. | |
12 | */ | |
1a8bfa1e | 13 | #include <linux/version.h> |
1da177e4 | 14 | #include <linux/kernel.h> |
1a8bfa1e TL |
15 | #include <linux/init.h> |
16 | #include <linux/module.h> | |
1da177e4 LT |
17 | #include <linux/list.h> |
18 | #include <linux/errno.h> | |
19 | #include <linux/err.h> | |
4e57b681 | 20 | #include <linux/string.h> |
f8ce2547 | 21 | #include <linux/clk.h> |
00431707 | 22 | #include <linux/mutex.h> |
b824efae | 23 | #include <linux/platform_device.h> |
1da177e4 | 24 | |
bb13b5fd | 25 | #include <asm/io.h> |
1da177e4 | 26 | |
1a8bfa1e | 27 | #include <asm/arch/clock.h> |
1da177e4 | 28 | |
7df3450e | 29 | static LIST_HEAD(clocks); |
00431707 | 30 | static DEFINE_MUTEX(clocks_mutex); |
7df3450e | 31 | static DEFINE_SPINLOCK(clockfw_lock); |
1da177e4 | 32 | |
1a8bfa1e | 33 | static struct clk_functions *arch_clock; |
1da177e4 | 34 | |
0ce33563 JY |
35 | #ifdef CONFIG_PM_DEBUG |
36 | ||
37 | static void print_parents(struct clk *clk) | |
38 | { | |
39 | struct clk *p; | |
40 | int printed = 0; | |
41 | ||
42 | list_for_each_entry(p, &clocks, node) { | |
43 | if (p->parent == clk && p->usecount) { | |
44 | if (!clk->usecount && !printed) { | |
45 | printk("MISMATCH: %s\n", clk->name); | |
46 | printed = 1; | |
47 | } | |
48 | printk("\t%-15s\n", p->name); | |
49 | } | |
50 | } | |
51 | } | |
52 | ||
53 | void clk_print_usecounts(void) | |
54 | { | |
55 | unsigned long flags; | |
56 | struct clk *p; | |
57 | ||
58 | spin_lock_irqsave(&clockfw_lock, flags); | |
59 | list_for_each_entry(p, &clocks, node) { | |
60 | if (p->usecount) | |
61 | printk("%-15s: %d\n", p->name, p->usecount); | |
62 | print_parents(p); | |
63 | ||
64 | } | |
65 | spin_unlock_irqrestore(&clockfw_lock, flags); | |
66 | } | |
67 | ||
68 | #endif | |
69 | ||
1a8bfa1e | 70 | /*------------------------------------------------------------------------- |
f07adc59 | 71 | * Standard clock functions defined in include/linux/clk.h |
1a8bfa1e | 72 | *-------------------------------------------------------------------------*/ |
1da177e4 | 73 | |
b824efae TL |
74 | /* |
75 | * Returns a clock. Note that we first try to use device id on the bus | |
76 | * and clock name. If this fails, we try to use clock name only. | |
77 | */ | |
1a8bfa1e | 78 | struct clk * clk_get(struct device *dev, const char *id) |
1da177e4 LT |
79 | { |
80 | struct clk *p, *clk = ERR_PTR(-ENOENT); | |
b824efae TL |
81 | int idno; |
82 | ||
83 | if (dev == NULL || dev->bus != &platform_bus_type) | |
84 | idno = -1; | |
85 | else | |
86 | idno = to_platform_device(dev)->id; | |
1da177e4 | 87 | |
00431707 | 88 | mutex_lock(&clocks_mutex); |
b824efae TL |
89 | |
90 | list_for_each_entry(p, &clocks, node) { | |
91 | if (p->id == idno && | |
92 | strcmp(id, p->name) == 0 && try_module_get(p->owner)) { | |
93 | clk = p; | |
67d4d835 | 94 | goto found; |
b824efae TL |
95 | } |
96 | } | |
97 | ||
1da177e4 LT |
98 | list_for_each_entry(p, &clocks, node) { |
99 | if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) { | |
100 | clk = p; | |
101 | break; | |
102 | } | |
103 | } | |
b824efae | 104 | |
67d4d835 | 105 | found: |
00431707 | 106 | mutex_unlock(&clocks_mutex); |
1da177e4 LT |
107 | |
108 | return clk; | |
109 | } | |
110 | EXPORT_SYMBOL(clk_get); | |
111 | ||
1da177e4 LT |
112 | int clk_enable(struct clk *clk) |
113 | { | |
114 | unsigned long flags; | |
1a8bfa1e | 115 | int ret = 0; |
1da177e4 | 116 | |
b824efae TL |
117 | if (clk == NULL || IS_ERR(clk)) |
118 | return -EINVAL; | |
119 | ||
1da177e4 | 120 | spin_lock_irqsave(&clockfw_lock, flags); |
f07adc59 | 121 | if (arch_clock->clk_enable) |
1a8bfa1e | 122 | ret = arch_clock->clk_enable(clk); |
1da177e4 | 123 | spin_unlock_irqrestore(&clockfw_lock, flags); |
1a8bfa1e | 124 | |
1da177e4 LT |
125 | return ret; |
126 | } | |
127 | EXPORT_SYMBOL(clk_enable); | |
128 | ||
1da177e4 LT |
129 | void clk_disable(struct clk *clk) |
130 | { | |
131 | unsigned long flags; | |
132 | ||
b824efae TL |
133 | if (clk == NULL || IS_ERR(clk)) |
134 | return; | |
135 | ||
1da177e4 | 136 | spin_lock_irqsave(&clockfw_lock, flags); |
7cf95774 TL |
137 | if (clk->usecount == 0) { |
138 | printk(KERN_ERR "Trying disable clock %s with 0 usecount\n", | |
139 | clk->name); | |
140 | WARN_ON(1); | |
141 | goto out; | |
142 | } | |
143 | ||
f07adc59 | 144 | if (arch_clock->clk_disable) |
1a8bfa1e | 145 | arch_clock->clk_disable(clk); |
7cf95774 TL |
146 | |
147 | out: | |
1da177e4 LT |
148 | spin_unlock_irqrestore(&clockfw_lock, flags); |
149 | } | |
150 | EXPORT_SYMBOL(clk_disable); | |
151 | ||
1da177e4 LT |
152 | int clk_get_usecount(struct clk *clk) |
153 | { | |
1a8bfa1e TL |
154 | unsigned long flags; |
155 | int ret = 0; | |
1da177e4 | 156 | |
b824efae TL |
157 | if (clk == NULL || IS_ERR(clk)) |
158 | return 0; | |
159 | ||
1a8bfa1e TL |
160 | spin_lock_irqsave(&clockfw_lock, flags); |
161 | ret = clk->usecount; | |
162 | spin_unlock_irqrestore(&clockfw_lock, flags); | |
1da177e4 | 163 | |
1a8bfa1e | 164 | return ret; |
1da177e4 | 165 | } |
1a8bfa1e | 166 | EXPORT_SYMBOL(clk_get_usecount); |
1da177e4 | 167 | |
1a8bfa1e | 168 | unsigned long clk_get_rate(struct clk *clk) |
1da177e4 | 169 | { |
1a8bfa1e TL |
170 | unsigned long flags; |
171 | unsigned long ret = 0; | |
1da177e4 | 172 | |
b824efae TL |
173 | if (clk == NULL || IS_ERR(clk)) |
174 | return 0; | |
175 | ||
1a8bfa1e TL |
176 | spin_lock_irqsave(&clockfw_lock, flags); |
177 | ret = clk->rate; | |
178 | spin_unlock_irqrestore(&clockfw_lock, flags); | |
1da177e4 | 179 | |
1a8bfa1e | 180 | return ret; |
1da177e4 | 181 | } |
1a8bfa1e | 182 | EXPORT_SYMBOL(clk_get_rate); |
1da177e4 | 183 | |
1a8bfa1e | 184 | void clk_put(struct clk *clk) |
bb13b5fd | 185 | { |
1a8bfa1e TL |
186 | if (clk && !IS_ERR(clk)) |
187 | module_put(clk->owner); | |
bb13b5fd | 188 | } |
1a8bfa1e | 189 | EXPORT_SYMBOL(clk_put); |
bb13b5fd | 190 | |
1a8bfa1e | 191 | /*------------------------------------------------------------------------- |
f07adc59 | 192 | * Optional clock functions defined in include/linux/clk.h |
1a8bfa1e | 193 | *-------------------------------------------------------------------------*/ |
bb13b5fd | 194 | |
1da177e4 LT |
195 | long clk_round_rate(struct clk *clk, unsigned long rate) |
196 | { | |
1a8bfa1e TL |
197 | unsigned long flags; |
198 | long ret = 0; | |
1da177e4 | 199 | |
b824efae TL |
200 | if (clk == NULL || IS_ERR(clk)) |
201 | return ret; | |
202 | ||
1a8bfa1e TL |
203 | spin_lock_irqsave(&clockfw_lock, flags); |
204 | if (arch_clock->clk_round_rate) | |
205 | ret = arch_clock->clk_round_rate(clk, rate); | |
206 | spin_unlock_irqrestore(&clockfw_lock, flags); | |
1da177e4 | 207 | |
1a8bfa1e | 208 | return ret; |
1da177e4 LT |
209 | } |
210 | EXPORT_SYMBOL(clk_round_rate); | |
211 | ||
1a8bfa1e | 212 | int clk_set_rate(struct clk *clk, unsigned long rate) |
1da177e4 | 213 | { |
1a8bfa1e | 214 | unsigned long flags; |
b824efae TL |
215 | int ret = -EINVAL; |
216 | ||
217 | if (clk == NULL || IS_ERR(clk)) | |
218 | return ret; | |
bb13b5fd | 219 | |
1a8bfa1e TL |
220 | spin_lock_irqsave(&clockfw_lock, flags); |
221 | if (arch_clock->clk_set_rate) | |
222 | ret = arch_clock->clk_set_rate(clk, rate); | |
223 | spin_unlock_irqrestore(&clockfw_lock, flags); | |
1da177e4 | 224 | |
1a8bfa1e | 225 | return ret; |
1da177e4 | 226 | } |
1a8bfa1e | 227 | EXPORT_SYMBOL(clk_set_rate); |
1da177e4 | 228 | |
1a8bfa1e | 229 | int clk_set_parent(struct clk *clk, struct clk *parent) |
1da177e4 | 230 | { |
1a8bfa1e | 231 | unsigned long flags; |
b824efae TL |
232 | int ret = -EINVAL; |
233 | ||
234 | if (clk == NULL || IS_ERR(clk) || parent == NULL || IS_ERR(parent)) | |
235 | return ret; | |
1da177e4 | 236 | |
1a8bfa1e TL |
237 | spin_lock_irqsave(&clockfw_lock, flags); |
238 | if (arch_clock->clk_set_parent) | |
239 | ret = arch_clock->clk_set_parent(clk, parent); | |
240 | spin_unlock_irqrestore(&clockfw_lock, flags); | |
1da177e4 | 241 | |
1a8bfa1e | 242 | return ret; |
1da177e4 | 243 | } |
1a8bfa1e | 244 | EXPORT_SYMBOL(clk_set_parent); |
1da177e4 | 245 | |
1a8bfa1e | 246 | struct clk *clk_get_parent(struct clk *clk) |
1da177e4 | 247 | { |
1a8bfa1e TL |
248 | unsigned long flags; |
249 | struct clk * ret = NULL; | |
1da177e4 | 250 | |
b824efae TL |
251 | if (clk == NULL || IS_ERR(clk)) |
252 | return ret; | |
253 | ||
1a8bfa1e TL |
254 | spin_lock_irqsave(&clockfw_lock, flags); |
255 | if (arch_clock->clk_get_parent) | |
256 | ret = arch_clock->clk_get_parent(clk); | |
257 | spin_unlock_irqrestore(&clockfw_lock, flags); | |
1da177e4 LT |
258 | |
259 | return ret; | |
260 | } | |
1a8bfa1e | 261 | EXPORT_SYMBOL(clk_get_parent); |
1da177e4 | 262 | |
1a8bfa1e TL |
263 | /*------------------------------------------------------------------------- |
264 | * OMAP specific clock functions shared between omap1 and omap2 | |
265 | *-------------------------------------------------------------------------*/ | |
1da177e4 | 266 | |
1a8bfa1e | 267 | unsigned int __initdata mpurate; |
1da177e4 | 268 | |
1a8bfa1e TL |
269 | /* |
270 | * By default we use the rate set by the bootloader. | |
271 | * You can override this with mpurate= cmdline option. | |
272 | */ | |
273 | static int __init omap_clk_setup(char *str) | |
1da177e4 | 274 | { |
1a8bfa1e | 275 | get_option(&str, &mpurate); |
1da177e4 | 276 | |
1a8bfa1e TL |
277 | if (!mpurate) |
278 | return 1; | |
1da177e4 | 279 | |
1a8bfa1e TL |
280 | if (mpurate < 1000) |
281 | mpurate *= 1000000; | |
1da177e4 | 282 | |
1a8bfa1e | 283 | return 1; |
1da177e4 | 284 | } |
1a8bfa1e | 285 | __setup("mpurate=", omap_clk_setup); |
1da177e4 | 286 | |
1a8bfa1e TL |
287 | /* Used for clocks that always have same value as the parent clock */ |
288 | void followparent_recalc(struct clk *clk) | |
1da177e4 | 289 | { |
b824efae TL |
290 | if (clk == NULL || IS_ERR(clk)) |
291 | return; | |
292 | ||
1a8bfa1e | 293 | clk->rate = clk->parent->rate; |
b1465bf7 ID |
294 | if (unlikely(clk->flags & RATE_PROPAGATES)) |
295 | propagate_rate(clk); | |
1da177e4 LT |
296 | } |
297 | ||
1a8bfa1e TL |
298 | /* Propagate rate to children */ |
299 | void propagate_rate(struct clk * tclk) | |
1da177e4 | 300 | { |
1a8bfa1e | 301 | struct clk *clkp; |
1da177e4 | 302 | |
b824efae TL |
303 | if (tclk == NULL || IS_ERR(tclk)) |
304 | return; | |
305 | ||
1a8bfa1e TL |
306 | list_for_each_entry(clkp, &clocks, node) { |
307 | if (likely(clkp->parent != tclk)) | |
308 | continue; | |
309 | if (likely((u32)clkp->recalc)) | |
310 | clkp->recalc(clkp); | |
311 | } | |
1da177e4 LT |
312 | } |
313 | ||
6b8858a9 PW |
314 | /** |
315 | * recalculate_root_clocks - recalculate and propagate all root clocks | |
316 | * | |
317 | * Recalculates all root clocks (clocks with no parent), which if the | |
318 | * clock's .recalc is set correctly, should also propagate their rates. | |
319 | * Called at init. | |
320 | */ | |
321 | void recalculate_root_clocks(void) | |
322 | { | |
323 | struct clk *clkp; | |
324 | ||
325 | list_for_each_entry(clkp, &clocks, node) { | |
326 | if (unlikely(!clkp->parent) && likely((u32)clkp->recalc)) | |
327 | clkp->recalc(clkp); | |
328 | } | |
329 | } | |
330 | ||
1da177e4 LT |
331 | int clk_register(struct clk *clk) |
332 | { | |
b824efae TL |
333 | if (clk == NULL || IS_ERR(clk)) |
334 | return -EINVAL; | |
335 | ||
00431707 | 336 | mutex_lock(&clocks_mutex); |
1da177e4 LT |
337 | list_add(&clk->node, &clocks); |
338 | if (clk->init) | |
339 | clk->init(clk); | |
00431707 | 340 | mutex_unlock(&clocks_mutex); |
1a8bfa1e | 341 | |
1da177e4 LT |
342 | return 0; |
343 | } | |
344 | EXPORT_SYMBOL(clk_register); | |
345 | ||
346 | void clk_unregister(struct clk *clk) | |
347 | { | |
b824efae TL |
348 | if (clk == NULL || IS_ERR(clk)) |
349 | return; | |
350 | ||
00431707 | 351 | mutex_lock(&clocks_mutex); |
1da177e4 | 352 | list_del(&clk->node); |
00431707 | 353 | mutex_unlock(&clocks_mutex); |
1da177e4 LT |
354 | } |
355 | EXPORT_SYMBOL(clk_unregister); | |
356 | ||
1a8bfa1e | 357 | void clk_deny_idle(struct clk *clk) |
bb13b5fd | 358 | { |
1a8bfa1e TL |
359 | unsigned long flags; |
360 | ||
b824efae TL |
361 | if (clk == NULL || IS_ERR(clk)) |
362 | return; | |
363 | ||
1a8bfa1e TL |
364 | spin_lock_irqsave(&clockfw_lock, flags); |
365 | if (arch_clock->clk_deny_idle) | |
366 | arch_clock->clk_deny_idle(clk); | |
367 | spin_unlock_irqrestore(&clockfw_lock, flags); | |
bb13b5fd | 368 | } |
1a8bfa1e | 369 | EXPORT_SYMBOL(clk_deny_idle); |
1da177e4 | 370 | |
1a8bfa1e | 371 | void clk_allow_idle(struct clk *clk) |
1da177e4 | 372 | { |
1a8bfa1e | 373 | unsigned long flags; |
1da177e4 | 374 | |
b824efae TL |
375 | if (clk == NULL || IS_ERR(clk)) |
376 | return; | |
377 | ||
1a8bfa1e TL |
378 | spin_lock_irqsave(&clockfw_lock, flags); |
379 | if (arch_clock->clk_allow_idle) | |
380 | arch_clock->clk_allow_idle(clk); | |
381 | spin_unlock_irqrestore(&clockfw_lock, flags); | |
1da177e4 | 382 | } |
1a8bfa1e | 383 | EXPORT_SYMBOL(clk_allow_idle); |
bb13b5fd | 384 | |
6b8858a9 PW |
385 | void clk_enable_init_clocks(void) |
386 | { | |
387 | struct clk *clkp; | |
388 | ||
389 | list_for_each_entry(clkp, &clocks, node) { | |
390 | if (clkp->flags & ENABLE_ON_INIT) | |
391 | clk_enable(clkp); | |
392 | } | |
393 | } | |
394 | EXPORT_SYMBOL(clk_enable_init_clocks); | |
395 | ||
396 | #ifdef CONFIG_CPU_FREQ | |
397 | void clk_init_cpufreq_table(struct cpufreq_frequency_table **table) | |
398 | { | |
399 | unsigned long flags; | |
400 | ||
401 | spin_lock_irqsave(&clockfw_lock, flags); | |
402 | if (arch_clock->clk_init_cpufreq_table) | |
403 | arch_clock->clk_init_cpufreq_table(table); | |
404 | spin_unlock_irqrestore(&clockfw_lock, flags); | |
405 | } | |
406 | EXPORT_SYMBOL(clk_init_cpufreq_table); | |
407 | #endif | |
408 | ||
1a8bfa1e | 409 | /*-------------------------------------------------------------------------*/ |
bb13b5fd | 410 | |
90afd5cb TL |
411 | #ifdef CONFIG_OMAP_RESET_CLOCKS |
412 | /* | |
413 | * Disable any unused clocks left on by the bootloader | |
414 | */ | |
415 | static int __init clk_disable_unused(void) | |
416 | { | |
417 | struct clk *ck; | |
418 | unsigned long flags; | |
419 | ||
420 | list_for_each_entry(ck, &clocks, node) { | |
421 | if (ck->usecount > 0 || (ck->flags & ALWAYS_ENABLED) || | |
422 | ck->enable_reg == 0) | |
423 | continue; | |
424 | ||
425 | spin_lock_irqsave(&clockfw_lock, flags); | |
426 | if (arch_clock->clk_disable_unused) | |
427 | arch_clock->clk_disable_unused(ck); | |
428 | spin_unlock_irqrestore(&clockfw_lock, flags); | |
429 | } | |
430 | ||
431 | return 0; | |
432 | } | |
433 | late_initcall(clk_disable_unused); | |
434 | #endif | |
435 | ||
1a8bfa1e | 436 | int __init clk_init(struct clk_functions * custom_clocks) |
bb13b5fd | 437 | { |
1a8bfa1e TL |
438 | if (!custom_clocks) { |
439 | printk(KERN_ERR "No custom clock functions registered\n"); | |
440 | BUG(); | |
bb13b5fd TL |
441 | } |
442 | ||
1a8bfa1e TL |
443 | arch_clock = custom_clocks; |
444 | ||
bb13b5fd TL |
445 | return 0; |
446 | } | |
6b8858a9 | 447 |