Merge branch 'upstream'
[pandora-kernel.git] / arch / arm / plat-omap / clock.c
1 /*
2  *  linux/arch/arm/plat-omap/clock.c
3  *
4  *  Copyright (C) 2004 - 2005 Nokia corporation
5  *  Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
6  *
7  *  Modified for omap shared clock framework by Tony Lindgren <tony@atomide.com>
8  *
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  */
13 #include <linux/version.h>
14 #include <linux/config.h>
15 #include <linux/kernel.h>
16 #include <linux/init.h>
17 #include <linux/module.h>
18 #include <linux/list.h>
19 #include <linux/errno.h>
20 #include <linux/err.h>
21 #include <linux/string.h>
22 #include <linux/clk.h>
23 #include <linux/mutex.h>
24
25 #include <asm/io.h>
26 #include <asm/semaphore.h>
27
28 #include <asm/arch/clock.h>
29
30 LIST_HEAD(clocks);
31 static DEFINE_MUTEX(clocks_mutex);
32 DEFINE_SPINLOCK(clockfw_lock);
33
34 static struct clk_functions *arch_clock;
35
36 /*-------------------------------------------------------------------------
37  * Standard clock functions defined in asm/hardware/clock.h
38  *-------------------------------------------------------------------------*/
39
40 struct clk * clk_get(struct device *dev, const char *id)
41 {
42         struct clk *p, *clk = ERR_PTR(-ENOENT);
43
44         mutex_lock(&clocks_mutex);
45         list_for_each_entry(p, &clocks, node) {
46                 if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
47                         clk = p;
48                         break;
49                 }
50         }
51         mutex_unlock(&clocks_mutex);
52
53         return clk;
54 }
55 EXPORT_SYMBOL(clk_get);
56
57 int clk_enable(struct clk *clk)
58 {
59         unsigned long flags;
60         int ret = 0;
61
62         spin_lock_irqsave(&clockfw_lock, flags);
63         if (clk->enable)
64                 ret = clk->enable(clk);
65         else if (arch_clock->clk_enable)
66                 ret = arch_clock->clk_enable(clk);
67         else
68                 printk(KERN_ERR "Could not enable clock %s\n", clk->name);
69         spin_unlock_irqrestore(&clockfw_lock, flags);
70
71         return ret;
72 }
73 EXPORT_SYMBOL(clk_enable);
74
75 void clk_disable(struct clk *clk)
76 {
77         unsigned long flags;
78
79         spin_lock_irqsave(&clockfw_lock, flags);
80         if (clk->disable)
81                 clk->disable(clk);
82         else if (arch_clock->clk_disable)
83                 arch_clock->clk_disable(clk);
84         else
85                 printk(KERN_ERR "Could not disable clock %s\n", clk->name);
86         spin_unlock_irqrestore(&clockfw_lock, flags);
87 }
88 EXPORT_SYMBOL(clk_disable);
89
90 int clk_use(struct clk *clk)
91 {
92         unsigned long flags;
93         int ret = 0;
94
95         spin_lock_irqsave(&clockfw_lock, flags);
96         if (arch_clock->clk_use)
97                 ret = arch_clock->clk_use(clk);
98         spin_unlock_irqrestore(&clockfw_lock, flags);
99
100         return ret;
101 }
102 EXPORT_SYMBOL(clk_use);
103
104 void clk_unuse(struct clk *clk)
105 {
106         unsigned long flags;
107
108         spin_lock_irqsave(&clockfw_lock, flags);
109         if (arch_clock->clk_unuse)
110                 arch_clock->clk_unuse(clk);
111         spin_unlock_irqrestore(&clockfw_lock, flags);
112 }
113 EXPORT_SYMBOL(clk_unuse);
114
115 int clk_get_usecount(struct clk *clk)
116 {
117         unsigned long flags;
118         int ret = 0;
119
120         spin_lock_irqsave(&clockfw_lock, flags);
121         ret = clk->usecount;
122         spin_unlock_irqrestore(&clockfw_lock, flags);
123
124         return ret;
125 }
126 EXPORT_SYMBOL(clk_get_usecount);
127
128 unsigned long clk_get_rate(struct clk *clk)
129 {
130         unsigned long flags;
131         unsigned long ret = 0;
132
133         spin_lock_irqsave(&clockfw_lock, flags);
134         ret = clk->rate;
135         spin_unlock_irqrestore(&clockfw_lock, flags);
136
137         return ret;
138 }
139 EXPORT_SYMBOL(clk_get_rate);
140
141 void clk_put(struct clk *clk)
142 {
143         if (clk && !IS_ERR(clk))
144                 module_put(clk->owner);
145 }
146 EXPORT_SYMBOL(clk_put);
147
148 /*-------------------------------------------------------------------------
149  * Optional clock functions defined in asm/hardware/clock.h
150  *-------------------------------------------------------------------------*/
151
152 long clk_round_rate(struct clk *clk, unsigned long rate)
153 {
154         unsigned long flags;
155         long ret = 0;
156
157         spin_lock_irqsave(&clockfw_lock, flags);
158         if (arch_clock->clk_round_rate)
159                 ret = arch_clock->clk_round_rate(clk, rate);
160         spin_unlock_irqrestore(&clockfw_lock, flags);
161
162         return ret;
163 }
164 EXPORT_SYMBOL(clk_round_rate);
165
166 int clk_set_rate(struct clk *clk, unsigned long rate)
167 {
168         unsigned long flags;
169         int ret = 0;
170
171         spin_lock_irqsave(&clockfw_lock, flags);
172         if (arch_clock->clk_set_rate)
173                 ret = arch_clock->clk_set_rate(clk, rate);
174         spin_unlock_irqrestore(&clockfw_lock, flags);
175
176         return ret;
177 }
178 EXPORT_SYMBOL(clk_set_rate);
179
180 int clk_set_parent(struct clk *clk, struct clk *parent)
181 {
182         unsigned long flags;
183         int ret = 0;
184
185         spin_lock_irqsave(&clockfw_lock, flags);
186         if (arch_clock->clk_set_parent)
187                 ret =  arch_clock->clk_set_parent(clk, parent);
188         spin_unlock_irqrestore(&clockfw_lock, flags);
189
190         return ret;
191 }
192 EXPORT_SYMBOL(clk_set_parent);
193
194 struct clk *clk_get_parent(struct clk *clk)
195 {
196         unsigned long flags;
197         struct clk * ret = NULL;
198
199         spin_lock_irqsave(&clockfw_lock, flags);
200         if (arch_clock->clk_get_parent)
201                 ret = arch_clock->clk_get_parent(clk);
202         spin_unlock_irqrestore(&clockfw_lock, flags);
203
204         return ret;
205 }
206 EXPORT_SYMBOL(clk_get_parent);
207
208 /*-------------------------------------------------------------------------
209  * OMAP specific clock functions shared between omap1 and omap2
210  *-------------------------------------------------------------------------*/
211
212 unsigned int __initdata mpurate;
213
214 /*
215  * By default we use the rate set by the bootloader.
216  * You can override this with mpurate= cmdline option.
217  */
218 static int __init omap_clk_setup(char *str)
219 {
220         get_option(&str, &mpurate);
221
222         if (!mpurate)
223                 return 1;
224
225         if (mpurate < 1000)
226                 mpurate *= 1000000;
227
228         return 1;
229 }
230 __setup("mpurate=", omap_clk_setup);
231
232 /* Used for clocks that always have same value as the parent clock */
233 void followparent_recalc(struct clk *clk)
234 {
235         clk->rate = clk->parent->rate;
236 }
237
238 /* Propagate rate to children */
239 void propagate_rate(struct clk * tclk)
240 {
241         struct clk *clkp;
242
243         list_for_each_entry(clkp, &clocks, node) {
244                 if (likely(clkp->parent != tclk))
245                         continue;
246                 if (likely((u32)clkp->recalc))
247                         clkp->recalc(clkp);
248         }
249 }
250
251 int clk_register(struct clk *clk)
252 {
253         mutex_lock(&clocks_mutex);
254         list_add(&clk->node, &clocks);
255         if (clk->init)
256                 clk->init(clk);
257         mutex_unlock(&clocks_mutex);
258
259         return 0;
260 }
261 EXPORT_SYMBOL(clk_register);
262
263 void clk_unregister(struct clk *clk)
264 {
265         mutex_lock(&clocks_mutex);
266         list_del(&clk->node);
267         mutex_unlock(&clocks_mutex);
268 }
269 EXPORT_SYMBOL(clk_unregister);
270
271 void clk_deny_idle(struct clk *clk)
272 {
273         unsigned long flags;
274
275         spin_lock_irqsave(&clockfw_lock, flags);
276         if (arch_clock->clk_deny_idle)
277                 arch_clock->clk_deny_idle(clk);
278         spin_unlock_irqrestore(&clockfw_lock, flags);
279 }
280 EXPORT_SYMBOL(clk_deny_idle);
281
282 void clk_allow_idle(struct clk *clk)
283 {
284         unsigned long flags;
285
286         spin_lock_irqsave(&clockfw_lock, flags);
287         if (arch_clock->clk_allow_idle)
288                 arch_clock->clk_allow_idle(clk);
289         spin_unlock_irqrestore(&clockfw_lock, flags);
290 }
291 EXPORT_SYMBOL(clk_allow_idle);
292
293 /*-------------------------------------------------------------------------*/
294
295 int __init clk_init(struct clk_functions * custom_clocks)
296 {
297         if (!custom_clocks) {
298                 printk(KERN_ERR "No custom clock functions registered\n");
299                 BUG();
300         }
301
302         arch_clock = custom_clocks;
303
304         return 0;
305 }