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