blob: 2946c193a7d63195806e431bc63d5b5db281a919 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Tony Lindgrenb9158552005-07-10 19:58:14 +01002 * linux/arch/arm/plat-omap/clock.c
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 *
Tony Lindgren1a8bfa12005-11-10 14:26:50 +00004 * Copyright (C) 2004 - 2005 Nokia corporation
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
6 *
Tony Lindgren1a8bfa12005-11-10 14:26:50 +00007 * Modified for omap shared clock framework by Tony Lindgren <tony@atomide.com>
8 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 * 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 */
Tony Lindgren1a8bfa12005-11-10 14:26:50 +000013#include <linux/version.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070014#include <linux/kernel.h>
Tony Lindgren1a8bfa12005-11-10 14:26:50 +000015#include <linux/init.h>
16#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include <linux/list.h>
18#include <linux/errno.h>
19#include <linux/err.h>
Tim Schmielau4e57b682005-10-30 15:03:48 -080020#include <linux/string.h>
Russell Kingf8ce2542006-01-07 16:15:52 +000021#include <linux/clk.h>
Arjan van de Ven00431702006-01-12 18:42:23 +000022#include <linux/mutex.h>
Tony Lindgrenb824efa2006-04-02 17:46:20 +010023#include <linux/platform_device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070024
Tony Lindgrenbb13b5f2005-07-10 19:58:18 +010025#include <asm/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026
Tony Lindgren1a8bfa12005-11-10 14:26:50 +000027#include <asm/arch/clock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070028
Juha Yrjola7df34502006-06-26 16:16:22 -070029static LIST_HEAD(clocks);
Arjan van de Ven00431702006-01-12 18:42:23 +000030static DEFINE_MUTEX(clocks_mutex);
Juha Yrjola7df34502006-06-26 16:16:22 -070031static DEFINE_SPINLOCK(clockfw_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070032
Tony Lindgren1a8bfa12005-11-10 14:26:50 +000033static struct clk_functions *arch_clock;
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
Juha Yrjola0ce33562006-12-06 17:13:49 -080035#ifdef CONFIG_PM_DEBUG
36
37static 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
53void 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
Tony Lindgren1a8bfa12005-11-10 14:26:50 +000070/*-------------------------------------------------------------------------
Tony Lindgrenf07adc52006-01-17 15:27:09 -080071 * Standard clock functions defined in include/linux/clk.h
Tony Lindgren1a8bfa12005-11-10 14:26:50 +000072 *-------------------------------------------------------------------------*/
Linus Torvalds1da177e2005-04-16 15:20:36 -070073
Tony Lindgrenb824efa2006-04-02 17:46:20 +010074/*
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 */
Tony Lindgren1a8bfa12005-11-10 14:26:50 +000078struct clk * clk_get(struct device *dev, const char *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -070079{
80 struct clk *p, *clk = ERR_PTR(-ENOENT);
Tony Lindgrenb824efa2006-04-02 17:46:20 +010081 int idno;
82
83 if (dev == NULL || dev->bus != &platform_bus_type)
84 idno = -1;
85 else
86 idno = to_platform_device(dev)->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -070087
Arjan van de Ven00431702006-01-12 18:42:23 +000088 mutex_lock(&clocks_mutex);
Tony Lindgrenb824efa2006-04-02 17:46:20 +010089
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;
Tony Lindgren67d4d832006-04-09 22:21:05 +010094 goto found;
Tony Lindgrenb824efa2006-04-02 17:46:20 +010095 }
96 }
97
Linus Torvalds1da177e2005-04-16 15:20:36 -070098 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 }
Tony Lindgrenb824efa2006-04-02 17:46:20 +0100104
Tony Lindgren67d4d832006-04-09 22:21:05 +0100105found:
Arjan van de Ven00431702006-01-12 18:42:23 +0000106 mutex_unlock(&clocks_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107
108 return clk;
109}
110EXPORT_SYMBOL(clk_get);
111
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000112int clk_enable(struct clk *clk)
113{
114 unsigned long flags;
115 int ret = 0;
116
Tony Lindgrenb824efa2006-04-02 17:46:20 +0100117 if (clk == NULL || IS_ERR(clk))
118 return -EINVAL;
119
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000120 spin_lock_irqsave(&clockfw_lock, flags);
Tony Lindgrenf07adc52006-01-17 15:27:09 -0800121 if (arch_clock->clk_enable)
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000122 ret = arch_clock->clk_enable(clk);
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000123 spin_unlock_irqrestore(&clockfw_lock, flags);
124
125 return ret;
126}
127EXPORT_SYMBOL(clk_enable);
128
129void clk_disable(struct clk *clk)
130{
131 unsigned long flags;
132
Tony Lindgrenb824efa2006-04-02 17:46:20 +0100133 if (clk == NULL || IS_ERR(clk))
134 return;
135
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000136 spin_lock_irqsave(&clockfw_lock, flags);
Tony Lindgren7cf95772007-08-07 05:20:00 -0700137 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
Tony Lindgrenf07adc52006-01-17 15:27:09 -0800144 if (arch_clock->clk_disable)
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000145 arch_clock->clk_disable(clk);
Tony Lindgren7cf95772007-08-07 05:20:00 -0700146
147out:
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000148 spin_unlock_irqrestore(&clockfw_lock, flags);
149}
150EXPORT_SYMBOL(clk_disable);
151
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000152int clk_get_usecount(struct clk *clk)
153{
154 unsigned long flags;
155 int ret = 0;
156
Tony Lindgrenb824efa2006-04-02 17:46:20 +0100157 if (clk == NULL || IS_ERR(clk))
158 return 0;
159
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000160 spin_lock_irqsave(&clockfw_lock, flags);
161 ret = clk->usecount;
162 spin_unlock_irqrestore(&clockfw_lock, flags);
163
164 return ret;
165}
166EXPORT_SYMBOL(clk_get_usecount);
167
168unsigned long clk_get_rate(struct clk *clk)
169{
170 unsigned long flags;
171 unsigned long ret = 0;
172
Tony Lindgrenb824efa2006-04-02 17:46:20 +0100173 if (clk == NULL || IS_ERR(clk))
174 return 0;
175
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000176 spin_lock_irqsave(&clockfw_lock, flags);
177 ret = clk->rate;
178 spin_unlock_irqrestore(&clockfw_lock, flags);
179
180 return ret;
181}
182EXPORT_SYMBOL(clk_get_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183
184void clk_put(struct clk *clk)
185{
186 if (clk && !IS_ERR(clk))
187 module_put(clk->owner);
188}
189EXPORT_SYMBOL(clk_put);
190
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000191/*-------------------------------------------------------------------------
Tony Lindgrenf07adc52006-01-17 15:27:09 -0800192 * Optional clock functions defined in include/linux/clk.h
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000193 *-------------------------------------------------------------------------*/
Tony Lindgrenbb13b5f2005-07-10 19:58:18 +0100194
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195long clk_round_rate(struct clk *clk, unsigned long rate)
196{
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000197 unsigned long flags;
198 long ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199
Tony Lindgrenb824efa2006-04-02 17:46:20 +0100200 if (clk == NULL || IS_ERR(clk))
201 return ret;
202
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000203 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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000208 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209}
210EXPORT_SYMBOL(clk_round_rate);
211
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212int clk_set_rate(struct clk *clk, unsigned long rate)
213{
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000214 unsigned long flags;
Tony Lindgrenb824efa2006-04-02 17:46:20 +0100215 int ret = -EINVAL;
216
217 if (clk == NULL || IS_ERR(clk))
218 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000220 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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224
225 return ret;
226}
227EXPORT_SYMBOL(clk_set_rate);
228
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000229int clk_set_parent(struct clk *clk, struct clk *parent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230{
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000231 unsigned long flags;
Tony Lindgrenb824efa2006-04-02 17:46:20 +0100232 int ret = -EINVAL;
233
234 if (clk == NULL || IS_ERR(clk) || parent == NULL || IS_ERR(parent))
235 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000237 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);
241
242 return ret;
243}
244EXPORT_SYMBOL(clk_set_parent);
245
246struct clk *clk_get_parent(struct clk *clk)
247{
248 unsigned long flags;
249 struct clk * ret = NULL;
250
Tony Lindgrenb824efa2006-04-02 17:46:20 +0100251 if (clk == NULL || IS_ERR(clk))
252 return ret;
253
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000254 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);
258
259 return ret;
260}
261EXPORT_SYMBOL(clk_get_parent);
262
263/*-------------------------------------------------------------------------
264 * OMAP specific clock functions shared between omap1 and omap2
265 *-------------------------------------------------------------------------*/
266
267unsigned int __initdata mpurate;
268
269/*
270 * By default we use the rate set by the bootloader.
271 * You can override this with mpurate= cmdline option.
272 */
273static int __init omap_clk_setup(char *str)
274{
275 get_option(&str, &mpurate);
276
277 if (!mpurate)
278 return 1;
279
280 if (mpurate < 1000)
281 mpurate *= 1000000;
282
283 return 1;
284}
285__setup("mpurate=", omap_clk_setup);
286
287/* Used for clocks that always have same value as the parent clock */
288void followparent_recalc(struct clk *clk)
289{
Tony Lindgrenb824efa2006-04-02 17:46:20 +0100290 if (clk == NULL || IS_ERR(clk))
291 return;
292
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000293 clk->rate = clk->parent->rate;
Imre Deakb1465bf2007-03-06 03:52:01 -0800294 if (unlikely(clk->flags & RATE_PROPAGATES))
295 propagate_rate(clk);
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000296}
297
298/* Propagate rate to children */
299void propagate_rate(struct clk * tclk)
300{
301 struct clk *clkp;
302
Tony Lindgrenb824efa2006-04-02 17:46:20 +0100303 if (tclk == NULL || IS_ERR(tclk))
304 return;
305
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000306 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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312}
313
Paul Walmsley6b8858a2008-03-18 10:35:15 +0200314/**
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 */
321void 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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331int clk_register(struct clk *clk)
332{
Tony Lindgrenb824efa2006-04-02 17:46:20 +0100333 if (clk == NULL || IS_ERR(clk))
334 return -EINVAL;
335
Arjan van de Ven00431702006-01-12 18:42:23 +0000336 mutex_lock(&clocks_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 list_add(&clk->node, &clocks);
338 if (clk->init)
339 clk->init(clk);
Arjan van de Ven00431702006-01-12 18:42:23 +0000340 mutex_unlock(&clocks_mutex);
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000341
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 return 0;
343}
344EXPORT_SYMBOL(clk_register);
345
346void clk_unregister(struct clk *clk)
347{
Tony Lindgrenb824efa2006-04-02 17:46:20 +0100348 if (clk == NULL || IS_ERR(clk))
349 return;
350
Arjan van de Ven00431702006-01-12 18:42:23 +0000351 mutex_lock(&clocks_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 list_del(&clk->node);
Arjan van de Ven00431702006-01-12 18:42:23 +0000353 mutex_unlock(&clocks_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354}
355EXPORT_SYMBOL(clk_unregister);
356
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000357void clk_deny_idle(struct clk *clk)
Tony Lindgrenbb13b5f2005-07-10 19:58:18 +0100358{
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000359 unsigned long flags;
360
Tony Lindgrenb824efa2006-04-02 17:46:20 +0100361 if (clk == NULL || IS_ERR(clk))
362 return;
363
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000364 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);
Tony Lindgrenbb13b5f2005-07-10 19:58:18 +0100368}
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000369EXPORT_SYMBOL(clk_deny_idle);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000371void clk_allow_idle(struct clk *clk)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372{
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000373 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374
Tony Lindgrenb824efa2006-04-02 17:46:20 +0100375 if (clk == NULL || IS_ERR(clk))
376 return;
377
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000378 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);
382}
383EXPORT_SYMBOL(clk_allow_idle);
Tony Lindgrenbb13b5f2005-07-10 19:58:18 +0100384
Paul Walmsley6b8858a2008-03-18 10:35:15 +0200385void 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}
394EXPORT_SYMBOL(clk_enable_init_clocks);
395
396#ifdef CONFIG_CPU_FREQ
397void 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}
406EXPORT_SYMBOL(clk_init_cpufreq_table);
407#endif
408
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000409/*-------------------------------------------------------------------------*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410
Tony Lindgren90afd5c2006-09-25 13:27:20 +0300411#ifdef CONFIG_OMAP_RESET_CLOCKS
412/*
413 * Disable any unused clocks left on by the bootloader
414 */
415static 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}
433late_initcall(clk_disable_unused);
434#endif
435
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000436int __init clk_init(struct clk_functions * custom_clocks)
437{
438 if (!custom_clocks) {
439 printk(KERN_ERR "No custom clock functions registered\n");
440 BUG();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 }
442
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000443 arch_clock = custom_clocks;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444
445 return 0;
446}
Paul Walmsley6b8858a2008-03-18 10:35:15 +0200447