diff options
Diffstat (limited to 'arch/arm/mach-omap2/clock.c')
-rw-r--r-- | arch/arm/mach-omap2/clock.c | 135 |
1 files changed, 91 insertions, 44 deletions
diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index d1f115d0edad..a6d0b34b7990 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c | |||
@@ -37,9 +37,9 @@ | |||
37 | 37 | ||
38 | u8 cpu_mask; | 38 | u8 cpu_mask; |
39 | 39 | ||
40 | /*------------------------------------------------------------------------- | 40 | /* |
41 | * OMAP2/3/4 specific clock functions | 41 | * OMAP2+ specific clock functions |
42 | *-------------------------------------------------------------------------*/ | 42 | */ |
43 | 43 | ||
44 | /* Private functions */ | 44 | /* Private functions */ |
45 | 45 | ||
@@ -71,20 +71,6 @@ static void _omap2_module_wait_ready(struct clk *clk) | |||
71 | clk->name); | 71 | clk->name); |
72 | } | 72 | } |
73 | 73 | ||
74 | /* Enables clock without considering parent dependencies or use count | ||
75 | * REVISIT: Maybe change this to use clk->enable like on omap1? | ||
76 | */ | ||
77 | static int _omap2_clk_enable(struct clk *clk) | ||
78 | { | ||
79 | return clk->ops->enable(clk); | ||
80 | } | ||
81 | |||
82 | /* Disables clock without considering parent dependencies or use count */ | ||
83 | static void _omap2_clk_disable(struct clk *clk) | ||
84 | { | ||
85 | clk->ops->disable(clk); | ||
86 | } | ||
87 | |||
88 | /* Public functions */ | 74 | /* Public functions */ |
89 | 75 | ||
90 | /** | 76 | /** |
@@ -245,46 +231,106 @@ const struct clkops clkops_omap2_dflt = { | |||
245 | .disable = omap2_dflt_clk_disable, | 231 | .disable = omap2_dflt_clk_disable, |
246 | }; | 232 | }; |
247 | 233 | ||
234 | /** | ||
235 | * omap2_clk_disable - disable a clock, if the system is not using it | ||
236 | * @clk: struct clk * to disable | ||
237 | * | ||
238 | * Decrements the usecount on struct clk @clk. If there are no users | ||
239 | * left, call the clkops-specific clock disable function to disable it | ||
240 | * in hardware. If the clock is part of a clockdomain (which they all | ||
241 | * should be), request that the clockdomain be disabled. (It too has | ||
242 | * a usecount, and so will not be disabled in the hardware until it no | ||
243 | * longer has any users.) If the clock has a parent clock (most of | ||
244 | * them do), then call ourselves, recursing on the parent clock. This | ||
245 | * can cause an entire branch of the clock tree to be powered off by | ||
246 | * simply disabling one clock. Intended to be called with the clockfw_lock | ||
247 | * spinlock held. No return value. | ||
248 | */ | ||
248 | void omap2_clk_disable(struct clk *clk) | 249 | void omap2_clk_disable(struct clk *clk) |
249 | { | 250 | { |
250 | if (clk->usecount > 0 && !(--clk->usecount)) { | 251 | if (clk->usecount == 0) { |
251 | _omap2_clk_disable(clk); | 252 | WARN(1, "clock: %s: omap2_clk_disable() called, but usecount " |
252 | if (clk->parent) | 253 | "already 0?", clk->name); |
253 | omap2_clk_disable(clk->parent); | 254 | return; |
254 | if (clk->clkdm) | ||
255 | omap2_clkdm_clk_disable(clk->clkdm, clk); | ||
256 | |||
257 | } | 255 | } |
256 | |||
257 | pr_debug("clock: %s: decrementing usecount\n", clk->name); | ||
258 | |||
259 | clk->usecount--; | ||
260 | |||
261 | if (clk->usecount > 0) | ||
262 | return; | ||
263 | |||
264 | pr_debug("clock: %s: disabling in hardware\n", clk->name); | ||
265 | |||
266 | clk->ops->disable(clk); | ||
267 | |||
268 | if (clk->clkdm) | ||
269 | omap2_clkdm_clk_disable(clk->clkdm, clk); | ||
270 | |||
271 | if (clk->parent) | ||
272 | omap2_clk_disable(clk->parent); | ||
258 | } | 273 | } |
259 | 274 | ||
275 | /** | ||
276 | * omap2_clk_enable - request that the system enable a clock | ||
277 | * @clk: struct clk * to enable | ||
278 | * | ||
279 | * Increments the usecount on struct clk @clk. If there were no users | ||
280 | * previously, then recurse up the clock tree, enabling all of the | ||
281 | * clock's parents and all of the parent clockdomains, and finally, | ||
282 | * enabling @clk's clockdomain, and @clk itself. Intended to be | ||
283 | * called with the clockfw_lock spinlock held. Returns 0 upon success | ||
284 | * or a negative error code upon failure. | ||
285 | */ | ||
260 | int omap2_clk_enable(struct clk *clk) | 286 | int omap2_clk_enable(struct clk *clk) |
261 | { | 287 | { |
262 | int ret = 0; | 288 | int ret; |
263 | 289 | ||
264 | if (clk->usecount++ == 0) { | 290 | pr_debug("clock: %s: incrementing usecount\n", clk->name); |
265 | if (clk->clkdm) | ||
266 | omap2_clkdm_clk_enable(clk->clkdm, clk); | ||
267 | 291 | ||
268 | if (clk->parent) { | 292 | clk->usecount++; |
269 | ret = omap2_clk_enable(clk->parent); | 293 | |
270 | if (ret) | 294 | if (clk->usecount > 1) |
271 | goto err; | 295 | return 0; |
272 | } | ||
273 | 296 | ||
274 | ret = _omap2_clk_enable(clk); | 297 | pr_debug("clock: %s: enabling in hardware\n", clk->name); |
298 | |||
299 | if (clk->parent) { | ||
300 | ret = omap2_clk_enable(clk->parent); | ||
275 | if (ret) { | 301 | if (ret) { |
276 | if (clk->parent) | 302 | WARN(1, "clock: %s: could not enable parent %s: %d\n", |
277 | omap2_clk_disable(clk->parent); | 303 | clk->name, clk->parent->name, ret); |
304 | goto oce_err1; | ||
305 | } | ||
306 | } | ||
278 | 307 | ||
279 | goto err; | 308 | if (clk->clkdm) { |
309 | ret = omap2_clkdm_clk_enable(clk->clkdm, clk); | ||
310 | if (ret) { | ||
311 | WARN(1, "clock: %s: could not enable clockdomain %s: " | ||
312 | "%d\n", clk->name, clk->clkdm->name, ret); | ||
313 | goto oce_err2; | ||
280 | } | 314 | } |
281 | } | 315 | } |
282 | return ret; | ||
283 | 316 | ||
284 | err: | 317 | ret = clk->ops->enable(clk); |
318 | if (ret) { | ||
319 | WARN(1, "clock: %s: could not enable: %d\n", clk->name, ret); | ||
320 | goto oce_err3; | ||
321 | } | ||
322 | |||
323 | return 0; | ||
324 | |||
325 | oce_err3: | ||
285 | if (clk->clkdm) | 326 | if (clk->clkdm) |
286 | omap2_clkdm_clk_disable(clk->clkdm, clk); | 327 | omap2_clkdm_clk_disable(clk->clkdm, clk); |
328 | oce_err2: | ||
329 | if (clk->parent) | ||
330 | omap2_clk_disable(clk->parent); | ||
331 | oce_err1: | ||
287 | clk->usecount--; | 332 | clk->usecount--; |
333 | |||
288 | return ret; | 334 | return ret; |
289 | } | 335 | } |
290 | 336 | ||
@@ -325,9 +371,9 @@ const struct clkops clkops_omap3_noncore_dpll_ops = { | |||
325 | #endif | 371 | #endif |
326 | 372 | ||
327 | 373 | ||
328 | /*------------------------------------------------------------------------- | 374 | /* |
329 | * Omap2 clock reset and init functions | 375 | * OMAP2+ clock reset and init functions |
330 | *-------------------------------------------------------------------------*/ | 376 | */ |
331 | 377 | ||
332 | #ifdef CONFIG_OMAP_RESET_CLOCKS | 378 | #ifdef CONFIG_OMAP_RESET_CLOCKS |
333 | void omap2_clk_disable_unused(struct clk *clk) | 379 | void omap2_clk_disable_unused(struct clk *clk) |
@@ -344,8 +390,9 @@ void omap2_clk_disable_unused(struct clk *clk) | |||
344 | if (cpu_is_omap34xx()) { | 390 | if (cpu_is_omap34xx()) { |
345 | omap2_clk_enable(clk); | 391 | omap2_clk_enable(clk); |
346 | omap2_clk_disable(clk); | 392 | omap2_clk_disable(clk); |
347 | } else | 393 | } else { |
348 | _omap2_clk_disable(clk); | 394 | clk->ops->disable(clk); |
395 | } | ||
349 | if (clk->clkdm != NULL) | 396 | if (clk->clkdm != NULL) |
350 | pwrdm_clkdm_state_switch(clk->clkdm); | 397 | pwrdm_clkdm_state_switch(clk->clkdm); |
351 | } | 398 | } |