]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame_incremental - arch/arm/plat-omap/clock.c
Merge master.kernel.org:/home/rmk/linux-2.6-arm
[mirror_ubuntu-bionic-kernel.git] / arch / arm / plat-omap / clock.c
... / ...
CommitLineData
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
24#include <asm/io.h>
25#include <asm/semaphore.h>
26
27#include <asm/arch/clock.h>
28
29LIST_HEAD(clocks);
30static DECLARE_MUTEX(clocks_sem);
31DEFINE_SPINLOCK(clockfw_lock);
32
33static struct clk_functions *arch_clock;
34
35/*-------------------------------------------------------------------------
36 * Standard clock functions defined in asm/hardware/clock.h
37 *-------------------------------------------------------------------------*/
38
39struct 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}
54EXPORT_SYMBOL(clk_get);
55
56int 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}
72EXPORT_SYMBOL(clk_enable);
73
74void 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}
87EXPORT_SYMBOL(clk_disable);
88
89int 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}
101EXPORT_SYMBOL(clk_use);
102
103void 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}
112EXPORT_SYMBOL(clk_unuse);
113
114int 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}
125EXPORT_SYMBOL(clk_get_usecount);
126
127unsigned 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}
138EXPORT_SYMBOL(clk_get_rate);
139
140void clk_put(struct clk *clk)
141{
142 if (clk && !IS_ERR(clk))
143 module_put(clk->owner);
144}
145EXPORT_SYMBOL(clk_put);
146
147/*-------------------------------------------------------------------------
148 * Optional clock functions defined in asm/hardware/clock.h
149 *-------------------------------------------------------------------------*/
150
151long 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}
163EXPORT_SYMBOL(clk_round_rate);
164
165int 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}
177EXPORT_SYMBOL(clk_set_rate);
178
179int 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}
191EXPORT_SYMBOL(clk_set_parent);
192
193struct 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}
205EXPORT_SYMBOL(clk_get_parent);
206
207/*-------------------------------------------------------------------------
208 * OMAP specific clock functions shared between omap1 and omap2
209 *-------------------------------------------------------------------------*/
210
211unsigned 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 */
217static 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 */
232void followparent_recalc(struct clk *clk)
233{
234 clk->rate = clk->parent->rate;
235}
236
237/* Propagate rate to children */
238void 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
250int 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}
260EXPORT_SYMBOL(clk_register);
261
262void clk_unregister(struct clk *clk)
263{
264 down(&clocks_sem);
265 list_del(&clk->node);
266 up(&clocks_sem);
267}
268EXPORT_SYMBOL(clk_unregister);
269
270void 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}
279EXPORT_SYMBOL(clk_deny_idle);
280
281void 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}
290EXPORT_SYMBOL(clk_allow_idle);
291
292/*-------------------------------------------------------------------------*/
293
294int __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}