diff options
Diffstat (limited to 'arch/arm/plat-omap/clock.c')
-rw-r--r-- | arch/arm/plat-omap/clock.c | 198 |
1 files changed, 76 insertions, 122 deletions
diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c index be6aab9c6834..2e0614552ac8 100644 --- a/arch/arm/plat-omap/clock.c +++ b/arch/arm/plat-omap/clock.c | |||
@@ -36,44 +36,6 @@ static struct clk_functions *arch_clock; | |||
36 | * Standard clock functions defined in include/linux/clk.h | 36 | * Standard clock functions defined in include/linux/clk.h |
37 | *-------------------------------------------------------------------------*/ | 37 | *-------------------------------------------------------------------------*/ |
38 | 38 | ||
39 | /* | ||
40 | * Returns a clock. Note that we first try to use device id on the bus | ||
41 | * and clock name. If this fails, we try to use clock name only. | ||
42 | */ | ||
43 | struct clk * clk_get(struct device *dev, const char *id) | ||
44 | { | ||
45 | struct clk *p, *clk = ERR_PTR(-ENOENT); | ||
46 | int idno; | ||
47 | |||
48 | if (dev == NULL || dev->bus != &platform_bus_type) | ||
49 | idno = -1; | ||
50 | else | ||
51 | idno = to_platform_device(dev)->id; | ||
52 | |||
53 | mutex_lock(&clocks_mutex); | ||
54 | |||
55 | list_for_each_entry(p, &clocks, node) { | ||
56 | if (p->id == idno && | ||
57 | strcmp(id, p->name) == 0 && try_module_get(p->owner)) { | ||
58 | clk = p; | ||
59 | goto found; | ||
60 | } | ||
61 | } | ||
62 | |||
63 | list_for_each_entry(p, &clocks, node) { | ||
64 | if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) { | ||
65 | clk = p; | ||
66 | break; | ||
67 | } | ||
68 | } | ||
69 | |||
70 | found: | ||
71 | mutex_unlock(&clocks_mutex); | ||
72 | |||
73 | return clk; | ||
74 | } | ||
75 | EXPORT_SYMBOL(clk_get); | ||
76 | |||
77 | int clk_enable(struct clk *clk) | 39 | int clk_enable(struct clk *clk) |
78 | { | 40 | { |
79 | unsigned long flags; | 41 | unsigned long flags; |
@@ -114,22 +76,6 @@ out: | |||
114 | } | 76 | } |
115 | EXPORT_SYMBOL(clk_disable); | 77 | EXPORT_SYMBOL(clk_disable); |
116 | 78 | ||
117 | int clk_get_usecount(struct clk *clk) | ||
118 | { | ||
119 | unsigned long flags; | ||
120 | int ret = 0; | ||
121 | |||
122 | if (clk == NULL || IS_ERR(clk)) | ||
123 | return 0; | ||
124 | |||
125 | spin_lock_irqsave(&clockfw_lock, flags); | ||
126 | ret = clk->usecount; | ||
127 | spin_unlock_irqrestore(&clockfw_lock, flags); | ||
128 | |||
129 | return ret; | ||
130 | } | ||
131 | EXPORT_SYMBOL(clk_get_usecount); | ||
132 | |||
133 | unsigned long clk_get_rate(struct clk *clk) | 79 | unsigned long clk_get_rate(struct clk *clk) |
134 | { | 80 | { |
135 | unsigned long flags; | 81 | unsigned long flags; |
@@ -146,13 +92,6 @@ unsigned long clk_get_rate(struct clk *clk) | |||
146 | } | 92 | } |
147 | EXPORT_SYMBOL(clk_get_rate); | 93 | EXPORT_SYMBOL(clk_get_rate); |
148 | 94 | ||
149 | void clk_put(struct clk *clk) | ||
150 | { | ||
151 | if (clk && !IS_ERR(clk)) | ||
152 | module_put(clk->owner); | ||
153 | } | ||
154 | EXPORT_SYMBOL(clk_put); | ||
155 | |||
156 | /*------------------------------------------------------------------------- | 95 | /*------------------------------------------------------------------------- |
157 | * Optional clock functions defined in include/linux/clk.h | 96 | * Optional clock functions defined in include/linux/clk.h |
158 | *-------------------------------------------------------------------------*/ | 97 | *-------------------------------------------------------------------------*/ |
@@ -185,6 +124,11 @@ int clk_set_rate(struct clk *clk, unsigned long rate) | |||
185 | spin_lock_irqsave(&clockfw_lock, flags); | 124 | spin_lock_irqsave(&clockfw_lock, flags); |
186 | if (arch_clock->clk_set_rate) | 125 | if (arch_clock->clk_set_rate) |
187 | ret = arch_clock->clk_set_rate(clk, rate); | 126 | ret = arch_clock->clk_set_rate(clk, rate); |
127 | if (ret == 0) { | ||
128 | if (clk->recalc) | ||
129 | clk->rate = clk->recalc(clk); | ||
130 | propagate_rate(clk); | ||
131 | } | ||
188 | spin_unlock_irqrestore(&clockfw_lock, flags); | 132 | spin_unlock_irqrestore(&clockfw_lock, flags); |
189 | 133 | ||
190 | return ret; | 134 | return ret; |
@@ -200,8 +144,16 @@ int clk_set_parent(struct clk *clk, struct clk *parent) | |||
200 | return ret; | 144 | return ret; |
201 | 145 | ||
202 | spin_lock_irqsave(&clockfw_lock, flags); | 146 | spin_lock_irqsave(&clockfw_lock, flags); |
203 | if (arch_clock->clk_set_parent) | 147 | if (clk->usecount == 0) { |
204 | ret = arch_clock->clk_set_parent(clk, parent); | 148 | if (arch_clock->clk_set_parent) |
149 | ret = arch_clock->clk_set_parent(clk, parent); | ||
150 | if (ret == 0) { | ||
151 | if (clk->recalc) | ||
152 | clk->rate = clk->recalc(clk); | ||
153 | propagate_rate(clk); | ||
154 | } | ||
155 | } else | ||
156 | ret = -EBUSY; | ||
205 | spin_unlock_irqrestore(&clockfw_lock, flags); | 157 | spin_unlock_irqrestore(&clockfw_lock, flags); |
206 | 158 | ||
207 | return ret; | 159 | return ret; |
@@ -210,18 +162,7 @@ EXPORT_SYMBOL(clk_set_parent); | |||
210 | 162 | ||
211 | struct clk *clk_get_parent(struct clk *clk) | 163 | struct clk *clk_get_parent(struct clk *clk) |
212 | { | 164 | { |
213 | unsigned long flags; | 165 | return clk->parent; |
214 | struct clk * ret = NULL; | ||
215 | |||
216 | if (clk == NULL || IS_ERR(clk)) | ||
217 | return ret; | ||
218 | |||
219 | spin_lock_irqsave(&clockfw_lock, flags); | ||
220 | if (arch_clock->clk_get_parent) | ||
221 | ret = arch_clock->clk_get_parent(clk); | ||
222 | spin_unlock_irqrestore(&clockfw_lock, flags); | ||
223 | |||
224 | return ret; | ||
225 | } | 166 | } |
226 | EXPORT_SYMBOL(clk_get_parent); | 167 | EXPORT_SYMBOL(clk_get_parent); |
227 | 168 | ||
@@ -250,14 +191,20 @@ static int __init omap_clk_setup(char *str) | |||
250 | __setup("mpurate=", omap_clk_setup); | 191 | __setup("mpurate=", omap_clk_setup); |
251 | 192 | ||
252 | /* Used for clocks that always have same value as the parent clock */ | 193 | /* Used for clocks that always have same value as the parent clock */ |
253 | void followparent_recalc(struct clk *clk) | 194 | unsigned long followparent_recalc(struct clk *clk) |
254 | { | 195 | { |
255 | if (clk == NULL || IS_ERR(clk)) | 196 | return clk->parent->rate; |
256 | return; | 197 | } |
257 | 198 | ||
258 | clk->rate = clk->parent->rate; | 199 | void clk_reparent(struct clk *child, struct clk *parent) |
259 | if (unlikely(clk->flags & RATE_PROPAGATES)) | 200 | { |
260 | propagate_rate(clk); | 201 | list_del_init(&child->sibling); |
202 | if (parent) | ||
203 | list_add(&child->sibling, &parent->children); | ||
204 | child->parent = parent; | ||
205 | |||
206 | /* now do the debugfs renaming to reattach the child | ||
207 | to the proper parent */ | ||
261 | } | 208 | } |
262 | 209 | ||
263 | /* Propagate rate to children */ | 210 | /* Propagate rate to children */ |
@@ -265,17 +212,15 @@ void propagate_rate(struct clk * tclk) | |||
265 | { | 212 | { |
266 | struct clk *clkp; | 213 | struct clk *clkp; |
267 | 214 | ||
268 | if (tclk == NULL || IS_ERR(tclk)) | 215 | list_for_each_entry(clkp, &tclk->children, sibling) { |
269 | return; | 216 | if (clkp->recalc) |
270 | 217 | clkp->rate = clkp->recalc(clkp); | |
271 | list_for_each_entry(clkp, &clocks, node) { | 218 | propagate_rate(clkp); |
272 | if (likely(clkp->parent != tclk)) | ||
273 | continue; | ||
274 | if (likely((u32)clkp->recalc)) | ||
275 | clkp->recalc(clkp); | ||
276 | } | 219 | } |
277 | } | 220 | } |
278 | 221 | ||
222 | static LIST_HEAD(root_clks); | ||
223 | |||
279 | /** | 224 | /** |
280 | * recalculate_root_clocks - recalculate and propagate all root clocks | 225 | * recalculate_root_clocks - recalculate and propagate all root clocks |
281 | * | 226 | * |
@@ -287,18 +232,35 @@ void recalculate_root_clocks(void) | |||
287 | { | 232 | { |
288 | struct clk *clkp; | 233 | struct clk *clkp; |
289 | 234 | ||
290 | list_for_each_entry(clkp, &clocks, node) { | 235 | list_for_each_entry(clkp, &root_clks, sibling) { |
291 | if (unlikely(!clkp->parent) && likely((u32)clkp->recalc)) | 236 | if (clkp->recalc) |
292 | clkp->recalc(clkp); | 237 | clkp->rate = clkp->recalc(clkp); |
238 | propagate_rate(clkp); | ||
293 | } | 239 | } |
294 | } | 240 | } |
295 | 241 | ||
242 | void clk_init_one(struct clk *clk) | ||
243 | { | ||
244 | INIT_LIST_HEAD(&clk->children); | ||
245 | } | ||
246 | |||
296 | int clk_register(struct clk *clk) | 247 | int clk_register(struct clk *clk) |
297 | { | 248 | { |
298 | if (clk == NULL || IS_ERR(clk)) | 249 | if (clk == NULL || IS_ERR(clk)) |
299 | return -EINVAL; | 250 | return -EINVAL; |
300 | 251 | ||
252 | /* | ||
253 | * trap out already registered clocks | ||
254 | */ | ||
255 | if (clk->node.next || clk->node.prev) | ||
256 | return 0; | ||
257 | |||
301 | mutex_lock(&clocks_mutex); | 258 | mutex_lock(&clocks_mutex); |
259 | if (clk->parent) | ||
260 | list_add(&clk->sibling, &clk->parent->children); | ||
261 | else | ||
262 | list_add(&clk->sibling, &root_clks); | ||
263 | |||
302 | list_add(&clk->node, &clocks); | 264 | list_add(&clk->node, &clocks); |
303 | if (clk->init) | 265 | if (clk->init) |
304 | clk->init(clk); | 266 | clk->init(clk); |
@@ -314,39 +276,12 @@ void clk_unregister(struct clk *clk) | |||
314 | return; | 276 | return; |
315 | 277 | ||
316 | mutex_lock(&clocks_mutex); | 278 | mutex_lock(&clocks_mutex); |
279 | list_del(&clk->sibling); | ||
317 | list_del(&clk->node); | 280 | list_del(&clk->node); |
318 | mutex_unlock(&clocks_mutex); | 281 | mutex_unlock(&clocks_mutex); |
319 | } | 282 | } |
320 | EXPORT_SYMBOL(clk_unregister); | 283 | EXPORT_SYMBOL(clk_unregister); |
321 | 284 | ||
322 | void clk_deny_idle(struct clk *clk) | ||
323 | { | ||
324 | unsigned long flags; | ||
325 | |||
326 | if (clk == NULL || IS_ERR(clk)) | ||
327 | return; | ||
328 | |||
329 | spin_lock_irqsave(&clockfw_lock, flags); | ||
330 | if (arch_clock->clk_deny_idle) | ||
331 | arch_clock->clk_deny_idle(clk); | ||
332 | spin_unlock_irqrestore(&clockfw_lock, flags); | ||
333 | } | ||
334 | EXPORT_SYMBOL(clk_deny_idle); | ||
335 | |||
336 | void clk_allow_idle(struct clk *clk) | ||
337 | { | ||
338 | unsigned long flags; | ||
339 | |||
340 | if (clk == NULL || IS_ERR(clk)) | ||
341 | return; | ||
342 | |||
343 | spin_lock_irqsave(&clockfw_lock, flags); | ||
344 | if (arch_clock->clk_allow_idle) | ||
345 | arch_clock->clk_allow_idle(clk); | ||
346 | spin_unlock_irqrestore(&clockfw_lock, flags); | ||
347 | } | ||
348 | EXPORT_SYMBOL(clk_allow_idle); | ||
349 | |||
350 | void clk_enable_init_clocks(void) | 285 | void clk_enable_init_clocks(void) |
351 | { | 286 | { |
352 | struct clk *clkp; | 287 | struct clk *clkp; |
@@ -358,6 +293,23 @@ void clk_enable_init_clocks(void) | |||
358 | } | 293 | } |
359 | EXPORT_SYMBOL(clk_enable_init_clocks); | 294 | EXPORT_SYMBOL(clk_enable_init_clocks); |
360 | 295 | ||
296 | /* | ||
297 | * Low level helpers | ||
298 | */ | ||
299 | static int clkll_enable_null(struct clk *clk) | ||
300 | { | ||
301 | return 0; | ||
302 | } | ||
303 | |||
304 | static void clkll_disable_null(struct clk *clk) | ||
305 | { | ||
306 | } | ||
307 | |||
308 | const struct clkops clkops_null = { | ||
309 | .enable = clkll_enable_null, | ||
310 | .disable = clkll_disable_null, | ||
311 | }; | ||
312 | |||
361 | #ifdef CONFIG_CPU_FREQ | 313 | #ifdef CONFIG_CPU_FREQ |
362 | void clk_init_cpufreq_table(struct cpufreq_frequency_table **table) | 314 | void clk_init_cpufreq_table(struct cpufreq_frequency_table **table) |
363 | { | 315 | { |
@@ -383,8 +335,10 @@ static int __init clk_disable_unused(void) | |||
383 | unsigned long flags; | 335 | unsigned long flags; |
384 | 336 | ||
385 | list_for_each_entry(ck, &clocks, node) { | 337 | list_for_each_entry(ck, &clocks, node) { |
386 | if (ck->usecount > 0 || (ck->flags & ALWAYS_ENABLED) || | 338 | if (ck->ops == &clkops_null) |
387 | ck->enable_reg == 0) | 339 | continue; |
340 | |||
341 | if (ck->usecount > 0 || ck->enable_reg == 0) | ||
388 | continue; | 342 | continue; |
389 | 343 | ||
390 | spin_lock_irqsave(&clockfw_lock, flags); | 344 | spin_lock_irqsave(&clockfw_lock, flags); |