]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/arm/plat-omap/clock.c
ARM: OMAP: Adds support to clock framework to detect device id
[linux-2.6-omap-h63xx.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 #include <linux/platform_device.h>
25
26 #include <asm/io.h>
27 #include <asm/semaphore.h>
28
29 #include <asm/arch/clock.h>
30
31 LIST_HEAD(clocks);
32 static DEFINE_MUTEX(clocks_mutex);
33 DEFINE_SPINLOCK(clockfw_lock);
34
35 static struct clk_functions *arch_clock;
36
37 /*-------------------------------------------------------------------------
38  * Standard clock functions defined in include/linux/clk.h
39  *-------------------------------------------------------------------------*/
40
41 /*
42  * Returns a clock. Note that we first try to use device id on the bus
43  * and clock name. If this fails, we try to use clock name only.
44  */
45 struct clk * clk_get(struct device *dev, const char *id)
46 {
47         struct clk *p, *clk = ERR_PTR(-ENOENT);
48         int idno;
49
50         if (dev == NULL || dev->bus != &platform_bus_type)
51                 idno = -1;
52         else
53                 idno = to_platform_device(dev)->id;
54
55         mutex_lock(&clocks_mutex);
56
57         list_for_each_entry(p, &clocks, node) {
58                 if (p->id == idno &&
59                     strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
60                         clk = p;
61                         break;
62                 }
63         }
64
65         list_for_each_entry(p, &clocks, node) {
66                 if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
67                         clk = p;
68                         break;
69                 }
70         }       
71
72         mutex_unlock(&clocks_mutex);
73
74         return clk;
75 }
76 EXPORT_SYMBOL(clk_get);
77
78 int clk_enable(struct clk *clk)
79 {
80         unsigned long flags;
81         int ret = 0;
82
83         if (clk == NULL || IS_ERR(clk))
84                 return -ENODEV;
85
86         spin_lock_irqsave(&clockfw_lock, flags);
87         if (arch_clock->clk_enable)
88                 ret = arch_clock->clk_enable(clk);
89         spin_unlock_irqrestore(&clockfw_lock, flags);
90
91         return ret;
92 }
93 EXPORT_SYMBOL(clk_enable);
94
95 void clk_disable(struct clk *clk)
96 {
97         unsigned long flags;
98
99         if (clk == NULL || IS_ERR(clk))
100                 return;
101
102         spin_lock_irqsave(&clockfw_lock, flags);
103         if (arch_clock->clk_disable)
104                 arch_clock->clk_disable(clk);
105         spin_unlock_irqrestore(&clockfw_lock, flags);
106 }
107 EXPORT_SYMBOL(clk_disable);
108
109 int clk_get_usecount(struct clk *clk)
110 {
111         unsigned long flags;
112         int ret = 0;
113
114         if (clk == NULL || IS_ERR(clk))
115                 return 0;
116
117         spin_lock_irqsave(&clockfw_lock, flags);
118         ret = clk->usecount;
119         spin_unlock_irqrestore(&clockfw_lock, flags);
120
121         return ret;
122 }
123 EXPORT_SYMBOL(clk_get_usecount);
124
125 unsigned long clk_get_rate(struct clk *clk)
126 {
127         unsigned long flags;
128         unsigned long ret = 0;
129
130         if (clk == NULL || IS_ERR(clk))
131                 return 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 include/linux/clk.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 }
306
307 #ifdef CONFIG_PROC_FS
308 #include <linux/proc_fs.h>
309 #include <linux/seq_file.h>
310
311 static void *omap_ck_start(struct seq_file *m, loff_t *pos)
312 {
313         return *pos < 1 ? (void *)1 : NULL;
314 }
315
316 static void *omap_ck_next(struct seq_file *m, void *v, loff_t *pos)
317 {
318         ++*pos;
319         return NULL;
320 }
321
322 static void omap_ck_stop(struct seq_file *m, void *v)
323 {
324 }
325
326 int omap_ck_show(struct seq_file *m, void *v)
327 {
328         struct clk *cp;
329
330         list_for_each_entry(cp, &clocks, node)
331                 seq_printf(m,"%s %ld %d\n", cp->name, cp->rate, cp->usecount);
332
333         return 0;
334 }
335
336 static struct seq_operations omap_ck_op = {
337         .start =        omap_ck_start,
338         .next =         omap_ck_next,
339         .stop =         omap_ck_stop,
340         .show =         omap_ck_show
341 };
342
343 static int omap_ck_open(struct inode *inode, struct file *file)
344 {
345         return seq_open(file, &omap_ck_op);
346 }
347
348 static struct file_operations proc_omap_ck_operations = {
349         .open           = omap_ck_open,
350         .read           = seq_read,
351         .llseek         = seq_lseek,
352         .release        = seq_release,
353 };
354
355 int __init omap_ck_init(void)
356 {
357     struct proc_dir_entry *entry;
358
359         entry = create_proc_entry("omap_clocks", 0, NULL);
360         if (entry)
361                 entry->proc_fops = &proc_omap_ck_operations;
362         return 0;
363
364 }
365 __initcall(omap_ck_init);
366 #endif /* CONFIG_DEBUG_PROC_FS */
367