diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /arch/arm/mach-omap2/clockdomain.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'arch/arm/mach-omap2/clockdomain.c')
-rw-r--r-- | arch/arm/mach-omap2/clockdomain.c | 489 |
1 files changed, 153 insertions, 336 deletions
diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c index 5d80cb897489..6cb6c03293df 100644 --- a/arch/arm/mach-omap2/clockdomain.c +++ b/arch/arm/mach-omap2/clockdomain.c | |||
@@ -13,7 +13,6 @@ | |||
13 | */ | 13 | */ |
14 | #undef DEBUG | 14 | #undef DEBUG |
15 | 15 | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
18 | #include <linux/device.h> | 17 | #include <linux/device.h> |
19 | #include <linux/list.h> | 18 | #include <linux/list.h> |
@@ -27,14 +26,8 @@ | |||
27 | 26 | ||
28 | #include <linux/bitops.h> | 27 | #include <linux/bitops.h> |
29 | 28 | ||
30 | #include "prm.h" | ||
31 | #include "prm-regbits-24xx.h" | ||
32 | #include "cm.h" | ||
33 | |||
34 | #include <plat/clock.h> | 29 | #include <plat/clock.h> |
35 | #include <plat/powerdomain.h> | 30 | #include "clockdomain.h" |
36 | #include <plat/clockdomain.h> | ||
37 | #include <plat/prcm.h> | ||
38 | 31 | ||
39 | /* clkdm_list contains all registered struct clockdomains */ | 32 | /* clkdm_list contains all registered struct clockdomains */ |
40 | static LIST_HEAD(clkdm_list); | 33 | static LIST_HEAD(clkdm_list); |
@@ -42,6 +35,7 @@ static LIST_HEAD(clkdm_list); | |||
42 | /* array of clockdomain deps to be added/removed when clkdm in hwsup mode */ | 35 | /* array of clockdomain deps to be added/removed when clkdm in hwsup mode */ |
43 | static struct clkdm_autodep *autodeps; | 36 | static struct clkdm_autodep *autodeps; |
44 | 37 | ||
38 | static struct clkdm_ops *arch_clkdm; | ||
45 | 39 | ||
46 | /* Private functions */ | 40 | /* Private functions */ |
47 | 41 | ||
@@ -141,6 +135,9 @@ static struct clkdm_dep *_clkdm_deps_lookup(struct clockdomain *clkdm, | |||
141 | * clockdomain is in hardware-supervised mode. Meant to be called | 135 | * clockdomain is in hardware-supervised mode. Meant to be called |
142 | * once at clockdomain layer initialization, since these should remain | 136 | * once at clockdomain layer initialization, since these should remain |
143 | * fixed for a particular architecture. No return value. | 137 | * fixed for a particular architecture. No return value. |
138 | * | ||
139 | * XXX autodeps are deprecated and should be removed at the earliest | ||
140 | * opportunity | ||
144 | */ | 141 | */ |
145 | static void _autodep_lookup(struct clkdm_autodep *autodep) | 142 | static void _autodep_lookup(struct clkdm_autodep *autodep) |
146 | { | 143 | { |
@@ -168,12 +165,15 @@ static void _autodep_lookup(struct clkdm_autodep *autodep) | |||
168 | * Add the "autodep" sleep & wakeup dependencies to clockdomain 'clkdm' | 165 | * Add the "autodep" sleep & wakeup dependencies to clockdomain 'clkdm' |
169 | * in hardware-supervised mode. Meant to be called from clock framework | 166 | * in hardware-supervised mode. Meant to be called from clock framework |
170 | * when a clock inside clockdomain 'clkdm' is enabled. No return value. | 167 | * when a clock inside clockdomain 'clkdm' is enabled. No return value. |
168 | * | ||
169 | * XXX autodeps are deprecated and should be removed at the earliest | ||
170 | * opportunity | ||
171 | */ | 171 | */ |
172 | static void _clkdm_add_autodeps(struct clockdomain *clkdm) | 172 | void _clkdm_add_autodeps(struct clockdomain *clkdm) |
173 | { | 173 | { |
174 | struct clkdm_autodep *autodep; | 174 | struct clkdm_autodep *autodep; |
175 | 175 | ||
176 | if (!autodeps) | 176 | if (!autodeps || clkdm->flags & CLKDM_NO_AUTODEPS) |
177 | return; | 177 | return; |
178 | 178 | ||
179 | for (autodep = autodeps; autodep->clkdm.ptr; autodep++) { | 179 | for (autodep = autodeps; autodep->clkdm.ptr; autodep++) { |
@@ -199,12 +199,15 @@ static void _clkdm_add_autodeps(struct clockdomain *clkdm) | |||
199 | * Remove the "autodep" sleep & wakeup dependencies from clockdomain 'clkdm' | 199 | * Remove the "autodep" sleep & wakeup dependencies from clockdomain 'clkdm' |
200 | * in hardware-supervised mode. Meant to be called from clock framework | 200 | * in hardware-supervised mode. Meant to be called from clock framework |
201 | * when a clock inside clockdomain 'clkdm' is disabled. No return value. | 201 | * when a clock inside clockdomain 'clkdm' is disabled. No return value. |
202 | * | ||
203 | * XXX autodeps are deprecated and should be removed at the earliest | ||
204 | * opportunity | ||
202 | */ | 205 | */ |
203 | static void _clkdm_del_autodeps(struct clockdomain *clkdm) | 206 | void _clkdm_del_autodeps(struct clockdomain *clkdm) |
204 | { | 207 | { |
205 | struct clkdm_autodep *autodep; | 208 | struct clkdm_autodep *autodep; |
206 | 209 | ||
207 | if (!autodeps) | 210 | if (!autodeps || clkdm->flags & CLKDM_NO_AUTODEPS) |
208 | return; | 211 | return; |
209 | 212 | ||
210 | for (autodep = autodeps; autodep->clkdm.ptr; autodep++) { | 213 | for (autodep = autodeps; autodep->clkdm.ptr; autodep++) { |
@@ -223,138 +226,39 @@ static void _clkdm_del_autodeps(struct clockdomain *clkdm) | |||
223 | } | 226 | } |
224 | } | 227 | } |
225 | 228 | ||
226 | /* | ||
227 | * _omap2_clkdm_set_hwsup - set the hwsup idle transition bit | ||
228 | * @clkdm: struct clockdomain * | ||
229 | * @enable: int 0 to disable, 1 to enable | ||
230 | * | ||
231 | * Internal helper for actually switching the bit that controls hwsup | ||
232 | * idle transitions for clkdm. | ||
233 | */ | ||
234 | static void _omap2_clkdm_set_hwsup(struct clockdomain *clkdm, int enable) | ||
235 | { | ||
236 | u32 bits, v; | ||
237 | |||
238 | if (cpu_is_omap24xx()) { | ||
239 | if (enable) | ||
240 | bits = OMAP24XX_CLKSTCTRL_ENABLE_AUTO; | ||
241 | else | ||
242 | bits = OMAP24XX_CLKSTCTRL_DISABLE_AUTO; | ||
243 | } else if (cpu_is_omap34xx() || cpu_is_omap44xx()) { | ||
244 | if (enable) | ||
245 | bits = OMAP34XX_CLKSTCTRL_ENABLE_AUTO; | ||
246 | else | ||
247 | bits = OMAP34XX_CLKSTCTRL_DISABLE_AUTO; | ||
248 | } else { | ||
249 | BUG(); | ||
250 | } | ||
251 | |||
252 | bits = bits << __ffs(clkdm->clktrctrl_mask); | ||
253 | |||
254 | v = __raw_readl(clkdm->clkstctrl_reg); | ||
255 | v &= ~(clkdm->clktrctrl_mask); | ||
256 | v |= bits; | ||
257 | __raw_writel(v, clkdm->clkstctrl_reg); | ||
258 | |||
259 | } | ||
260 | |||
261 | /** | 229 | /** |
262 | * _init_wkdep_usecount - initialize wkdep usecounts to match hardware | 230 | * _resolve_clkdm_deps() - resolve clkdm_names in @clkdm_deps to clkdms |
263 | * @clkdm: clockdomain to initialize wkdep usecounts | 231 | * @clkdm: clockdomain that we are resolving dependencies for |
232 | * @clkdm_deps: ptr to array of struct clkdm_deps to resolve | ||
264 | * | 233 | * |
265 | * Initialize the wakeup dependency usecount variables for clockdomain @clkdm. | 234 | * Iterates through @clkdm_deps, looking up the struct clockdomain named by |
266 | * If a wakeup dependency is present in the hardware, the usecount will be | 235 | * clkdm_name and storing the clockdomain pointer in the struct clkdm_dep. |
267 | * set to 1; otherwise, it will be set to 0. Software should clear all | 236 | * No return value. |
268 | * software wakeup dependencies prior to calling this function if it wishes | ||
269 | * to ensure that all usecounts start at 0. No return value. | ||
270 | */ | 237 | */ |
271 | static void _init_wkdep_usecount(struct clockdomain *clkdm) | 238 | static void _resolve_clkdm_deps(struct clockdomain *clkdm, |
239 | struct clkdm_dep *clkdm_deps) | ||
272 | { | 240 | { |
273 | u32 v; | ||
274 | struct clkdm_dep *cd; | 241 | struct clkdm_dep *cd; |
275 | 242 | ||
276 | if (!clkdm->wkdep_srcs) | 243 | for (cd = clkdm_deps; cd && cd->clkdm_name; cd++) { |
277 | return; | ||
278 | |||
279 | for (cd = clkdm->wkdep_srcs; cd->clkdm_name; cd++) { | ||
280 | if (!omap_chip_is(cd->omap_chip)) | 244 | if (!omap_chip_is(cd->omap_chip)) |
281 | continue; | 245 | continue; |
282 | 246 | if (cd->clkdm) | |
283 | if (!cd->clkdm && cd->clkdm_name) | ||
284 | cd->clkdm = _clkdm_lookup(cd->clkdm_name); | ||
285 | |||
286 | if (!cd->clkdm) { | ||
287 | WARN(!cd->clkdm, "clockdomain: %s: wkdep clkdm %s not " | ||
288 | "found\n", clkdm->name, cd->clkdm_name); | ||
289 | continue; | 247 | continue; |
290 | } | 248 | cd->clkdm = _clkdm_lookup(cd->clkdm_name); |
291 | |||
292 | v = prm_read_mod_bits_shift(clkdm->pwrdm.ptr->prcm_offs, | ||
293 | PM_WKDEP, | ||
294 | (1 << cd->clkdm->dep_bit)); | ||
295 | 249 | ||
296 | if (v) | 250 | WARN(!cd->clkdm, "clockdomain: %s: could not find clkdm %s while resolving dependencies - should never happen", |
297 | pr_debug("clockdomain: %s: wakeup dependency already " | 251 | clkdm->name, cd->clkdm_name); |
298 | "set to wake up when %s wakes\n", | ||
299 | clkdm->name, cd->clkdm->name); | ||
300 | |||
301 | atomic_set(&cd->wkdep_usecount, (v) ? 1 : 0); | ||
302 | } | 252 | } |
303 | } | 253 | } |
304 | 254 | ||
305 | /** | ||
306 | * _init_sleepdep_usecount - initialize sleepdep usecounts to match hardware | ||
307 | * @clkdm: clockdomain to initialize sleepdep usecounts | ||
308 | * | ||
309 | * Initialize the sleep dependency usecount variables for clockdomain @clkdm. | ||
310 | * If a sleep dependency is present in the hardware, the usecount will be | ||
311 | * set to 1; otherwise, it will be set to 0. Software should clear all | ||
312 | * software sleep dependencies prior to calling this function if it wishes | ||
313 | * to ensure that all usecounts start at 0. No return value. | ||
314 | */ | ||
315 | static void _init_sleepdep_usecount(struct clockdomain *clkdm) | ||
316 | { | ||
317 | u32 v; | ||
318 | struct clkdm_dep *cd; | ||
319 | |||
320 | if (!cpu_is_omap34xx()) | ||
321 | return; | ||
322 | |||
323 | if (!clkdm->sleepdep_srcs) | ||
324 | return; | ||
325 | |||
326 | for (cd = clkdm->sleepdep_srcs; cd->clkdm_name; cd++) { | ||
327 | if (!omap_chip_is(cd->omap_chip)) | ||
328 | continue; | ||
329 | |||
330 | if (!cd->clkdm && cd->clkdm_name) | ||
331 | cd->clkdm = _clkdm_lookup(cd->clkdm_name); | ||
332 | |||
333 | if (!cd->clkdm) { | ||
334 | WARN(!cd->clkdm, "clockdomain: %s: sleepdep clkdm %s " | ||
335 | "not found\n", clkdm->name, cd->clkdm_name); | ||
336 | continue; | ||
337 | } | ||
338 | |||
339 | v = prm_read_mod_bits_shift(clkdm->pwrdm.ptr->prcm_offs, | ||
340 | OMAP3430_CM_SLEEPDEP, | ||
341 | (1 << cd->clkdm->dep_bit)); | ||
342 | |||
343 | if (v) | ||
344 | pr_debug("clockdomain: %s: sleep dependency already " | ||
345 | "set to prevent from idling until %s " | ||
346 | "idles\n", clkdm->name, cd->clkdm->name); | ||
347 | |||
348 | atomic_set(&cd->sleepdep_usecount, (v) ? 1 : 0); | ||
349 | } | ||
350 | }; | ||
351 | |||
352 | /* Public functions */ | 255 | /* Public functions */ |
353 | 256 | ||
354 | /** | 257 | /** |
355 | * clkdm_init - set up the clockdomain layer | 258 | * clkdm_init - set up the clockdomain layer |
356 | * @clkdms: optional pointer to an array of clockdomains to register | 259 | * @clkdms: optional pointer to an array of clockdomains to register |
357 | * @init_autodeps: optional pointer to an array of autodeps to register | 260 | * @init_autodeps: optional pointer to an array of autodeps to register |
261 | * @custom_funcs: func pointers for arch specific implementations | ||
358 | * | 262 | * |
359 | * Set up internal state. If a pointer to an array of clockdomains | 263 | * Set up internal state. If a pointer to an array of clockdomains |
360 | * @clkdms was supplied, loop through the list of clockdomains, | 264 | * @clkdms was supplied, loop through the list of clockdomains, |
@@ -363,12 +267,18 @@ static void _init_sleepdep_usecount(struct clockdomain *clkdm) | |||
363 | * @init_autodeps was provided, register those. No return value. | 267 | * @init_autodeps was provided, register those. No return value. |
364 | */ | 268 | */ |
365 | void clkdm_init(struct clockdomain **clkdms, | 269 | void clkdm_init(struct clockdomain **clkdms, |
366 | struct clkdm_autodep *init_autodeps) | 270 | struct clkdm_autodep *init_autodeps, |
271 | struct clkdm_ops *custom_funcs) | ||
367 | { | 272 | { |
368 | struct clockdomain **c = NULL; | 273 | struct clockdomain **c = NULL; |
369 | struct clockdomain *clkdm; | 274 | struct clockdomain *clkdm; |
370 | struct clkdm_autodep *autodep = NULL; | 275 | struct clkdm_autodep *autodep = NULL; |
371 | 276 | ||
277 | if (!custom_funcs) | ||
278 | WARN(1, "No custom clkdm functions registered\n"); | ||
279 | else | ||
280 | arch_clkdm = custom_funcs; | ||
281 | |||
372 | if (clkdms) | 282 | if (clkdms) |
373 | for (c = clkdms; *c; c++) | 283 | for (c = clkdms; *c; c++) |
374 | _clkdm_register(*c); | 284 | _clkdm_register(*c); |
@@ -379,12 +289,20 @@ void clkdm_init(struct clockdomain **clkdms, | |||
379 | _autodep_lookup(autodep); | 289 | _autodep_lookup(autodep); |
380 | 290 | ||
381 | /* | 291 | /* |
382 | * Ensure that the *dep_usecount registers reflect the current | 292 | * Put all clockdomains into software-supervised mode; PM code |
383 | * state of the PRCM. | 293 | * should later enable hardware-supervised mode as appropriate |
384 | */ | 294 | */ |
385 | list_for_each_entry(clkdm, &clkdm_list, node) { | 295 | list_for_each_entry(clkdm, &clkdm_list, node) { |
386 | _init_wkdep_usecount(clkdm); | 296 | if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP) |
387 | _init_sleepdep_usecount(clkdm); | 297 | clkdm_wakeup(clkdm); |
298 | else if (clkdm->flags & CLKDM_CAN_DISABLE_AUTO) | ||
299 | clkdm_deny_idle(clkdm); | ||
300 | |||
301 | _resolve_clkdm_deps(clkdm, clkdm->wkdep_srcs); | ||
302 | clkdm_clear_all_wkdeps(clkdm); | ||
303 | |||
304 | _resolve_clkdm_deps(clkdm, clkdm->sleepdep_srcs); | ||
305 | clkdm_clear_all_sleepdeps(clkdm); | ||
388 | } | 306 | } |
389 | } | 307 | } |
390 | 308 | ||
@@ -480,26 +398,32 @@ struct powerdomain *clkdm_get_pwrdm(struct clockdomain *clkdm) | |||
480 | int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) | 398 | int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) |
481 | { | 399 | { |
482 | struct clkdm_dep *cd; | 400 | struct clkdm_dep *cd; |
401 | int ret = 0; | ||
483 | 402 | ||
484 | if (!clkdm1 || !clkdm2) | 403 | if (!clkdm1 || !clkdm2) |
485 | return -EINVAL; | 404 | return -EINVAL; |
486 | 405 | ||
487 | cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); | 406 | cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); |
488 | if (IS_ERR(cd)) { | 407 | if (IS_ERR(cd)) |
408 | ret = PTR_ERR(cd); | ||
409 | |||
410 | if (!arch_clkdm || !arch_clkdm->clkdm_add_wkdep) | ||
411 | ret = -EINVAL; | ||
412 | |||
413 | if (ret) { | ||
489 | pr_debug("clockdomain: hardware cannot set/clear wake up of " | 414 | pr_debug("clockdomain: hardware cannot set/clear wake up of " |
490 | "%s when %s wakes up\n", clkdm1->name, clkdm2->name); | 415 | "%s when %s wakes up\n", clkdm1->name, clkdm2->name); |
491 | return PTR_ERR(cd); | 416 | return ret; |
492 | } | 417 | } |
493 | 418 | ||
494 | if (atomic_inc_return(&cd->wkdep_usecount) == 1) { | 419 | if (atomic_inc_return(&cd->wkdep_usecount) == 1) { |
495 | pr_debug("clockdomain: hardware will wake up %s when %s wakes " | 420 | pr_debug("clockdomain: hardware will wake up %s when %s wakes " |
496 | "up\n", clkdm1->name, clkdm2->name); | 421 | "up\n", clkdm1->name, clkdm2->name); |
497 | 422 | ||
498 | prm_set_mod_reg_bits((1 << clkdm2->dep_bit), | 423 | ret = arch_clkdm->clkdm_add_wkdep(clkdm1, clkdm2); |
499 | clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP); | ||
500 | } | 424 | } |
501 | 425 | ||
502 | return 0; | 426 | return ret; |
503 | } | 427 | } |
504 | 428 | ||
505 | /** | 429 | /** |
@@ -515,26 +439,32 @@ int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) | |||
515 | int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) | 439 | int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) |
516 | { | 440 | { |
517 | struct clkdm_dep *cd; | 441 | struct clkdm_dep *cd; |
442 | int ret = 0; | ||
518 | 443 | ||
519 | if (!clkdm1 || !clkdm2) | 444 | if (!clkdm1 || !clkdm2) |
520 | return -EINVAL; | 445 | return -EINVAL; |
521 | 446 | ||
522 | cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); | 447 | cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); |
523 | if (IS_ERR(cd)) { | 448 | if (IS_ERR(cd)) |
449 | ret = PTR_ERR(cd); | ||
450 | |||
451 | if (!arch_clkdm || !arch_clkdm->clkdm_del_wkdep) | ||
452 | ret = -EINVAL; | ||
453 | |||
454 | if (ret) { | ||
524 | pr_debug("clockdomain: hardware cannot set/clear wake up of " | 455 | pr_debug("clockdomain: hardware cannot set/clear wake up of " |
525 | "%s when %s wakes up\n", clkdm1->name, clkdm2->name); | 456 | "%s when %s wakes up\n", clkdm1->name, clkdm2->name); |
526 | return PTR_ERR(cd); | 457 | return ret; |
527 | } | 458 | } |
528 | 459 | ||
529 | if (atomic_dec_return(&cd->wkdep_usecount) == 0) { | 460 | if (atomic_dec_return(&cd->wkdep_usecount) == 0) { |
530 | pr_debug("clockdomain: hardware will no longer wake up %s " | 461 | pr_debug("clockdomain: hardware will no longer wake up %s " |
531 | "after %s wakes up\n", clkdm1->name, clkdm2->name); | 462 | "after %s wakes up\n", clkdm1->name, clkdm2->name); |
532 | 463 | ||
533 | prm_clear_mod_reg_bits((1 << clkdm2->dep_bit), | 464 | ret = arch_clkdm->clkdm_del_wkdep(clkdm1, clkdm2); |
534 | clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP); | ||
535 | } | 465 | } |
536 | 466 | ||
537 | return 0; | 467 | return ret; |
538 | } | 468 | } |
539 | 469 | ||
540 | /** | 470 | /** |
@@ -554,20 +484,26 @@ int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) | |||
554 | int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) | 484 | int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) |
555 | { | 485 | { |
556 | struct clkdm_dep *cd; | 486 | struct clkdm_dep *cd; |
487 | int ret = 0; | ||
557 | 488 | ||
558 | if (!clkdm1 || !clkdm2) | 489 | if (!clkdm1 || !clkdm2) |
559 | return -EINVAL; | 490 | return -EINVAL; |
560 | 491 | ||
561 | cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); | 492 | cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); |
562 | if (IS_ERR(cd)) { | 493 | if (IS_ERR(cd)) |
494 | ret = PTR_ERR(cd); | ||
495 | |||
496 | if (!arch_clkdm || !arch_clkdm->clkdm_read_wkdep) | ||
497 | ret = -EINVAL; | ||
498 | |||
499 | if (ret) { | ||
563 | pr_debug("clockdomain: hardware cannot set/clear wake up of " | 500 | pr_debug("clockdomain: hardware cannot set/clear wake up of " |
564 | "%s when %s wakes up\n", clkdm1->name, clkdm2->name); | 501 | "%s when %s wakes up\n", clkdm1->name, clkdm2->name); |
565 | return PTR_ERR(cd); | 502 | return ret; |
566 | } | 503 | } |
567 | 504 | ||
568 | /* XXX It's faster to return the atomic wkdep_usecount */ | 505 | /* XXX It's faster to return the atomic wkdep_usecount */ |
569 | return prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP, | 506 | return arch_clkdm->clkdm_read_wkdep(clkdm1, clkdm2); |
570 | (1 << clkdm2->dep_bit)); | ||
571 | } | 507 | } |
572 | 508 | ||
573 | /** | 509 | /** |
@@ -582,24 +518,13 @@ int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) | |||
582 | */ | 518 | */ |
583 | int clkdm_clear_all_wkdeps(struct clockdomain *clkdm) | 519 | int clkdm_clear_all_wkdeps(struct clockdomain *clkdm) |
584 | { | 520 | { |
585 | struct clkdm_dep *cd; | ||
586 | u32 mask = 0; | ||
587 | |||
588 | if (!clkdm) | 521 | if (!clkdm) |
589 | return -EINVAL; | 522 | return -EINVAL; |
590 | 523 | ||
591 | for (cd = clkdm->wkdep_srcs; cd && cd->clkdm_name; cd++) { | 524 | if (!arch_clkdm || !arch_clkdm->clkdm_clear_all_wkdeps) |
592 | if (!omap_chip_is(cd->omap_chip)) | 525 | return -EINVAL; |
593 | continue; | ||
594 | |||
595 | /* PRM accesses are slow, so minimize them */ | ||
596 | mask |= 1 << cd->clkdm->dep_bit; | ||
597 | atomic_set(&cd->wkdep_usecount, 0); | ||
598 | } | ||
599 | |||
600 | prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs, PM_WKDEP); | ||
601 | 526 | ||
602 | return 0; | 527 | return arch_clkdm->clkdm_clear_all_wkdeps(clkdm); |
603 | } | 528 | } |
604 | 529 | ||
605 | /** | 530 | /** |
@@ -617,31 +542,33 @@ int clkdm_clear_all_wkdeps(struct clockdomain *clkdm) | |||
617 | int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) | 542 | int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) |
618 | { | 543 | { |
619 | struct clkdm_dep *cd; | 544 | struct clkdm_dep *cd; |
620 | 545 | int ret = 0; | |
621 | if (!cpu_is_omap34xx()) | ||
622 | return -EINVAL; | ||
623 | 546 | ||
624 | if (!clkdm1 || !clkdm2) | 547 | if (!clkdm1 || !clkdm2) |
625 | return -EINVAL; | 548 | return -EINVAL; |
626 | 549 | ||
627 | cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); | 550 | cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); |
628 | if (IS_ERR(cd)) { | 551 | if (IS_ERR(cd)) |
552 | ret = PTR_ERR(cd); | ||
553 | |||
554 | if (!arch_clkdm || !arch_clkdm->clkdm_add_sleepdep) | ||
555 | ret = -EINVAL; | ||
556 | |||
557 | if (ret) { | ||
629 | pr_debug("clockdomain: hardware cannot set/clear sleep " | 558 | pr_debug("clockdomain: hardware cannot set/clear sleep " |
630 | "dependency affecting %s from %s\n", clkdm1->name, | 559 | "dependency affecting %s from %s\n", clkdm1->name, |
631 | clkdm2->name); | 560 | clkdm2->name); |
632 | return PTR_ERR(cd); | 561 | return ret; |
633 | } | 562 | } |
634 | 563 | ||
635 | if (atomic_inc_return(&cd->sleepdep_usecount) == 1) { | 564 | if (atomic_inc_return(&cd->sleepdep_usecount) == 1) { |
636 | pr_debug("clockdomain: will prevent %s from sleeping if %s " | 565 | pr_debug("clockdomain: will prevent %s from sleeping if %s " |
637 | "is active\n", clkdm1->name, clkdm2->name); | 566 | "is active\n", clkdm1->name, clkdm2->name); |
638 | 567 | ||
639 | cm_set_mod_reg_bits((1 << clkdm2->dep_bit), | 568 | ret = arch_clkdm->clkdm_add_sleepdep(clkdm1, clkdm2); |
640 | clkdm1->pwrdm.ptr->prcm_offs, | ||
641 | OMAP3430_CM_SLEEPDEP); | ||
642 | } | 569 | } |
643 | 570 | ||
644 | return 0; | 571 | return ret; |
645 | } | 572 | } |
646 | 573 | ||
647 | /** | 574 | /** |
@@ -659,19 +586,23 @@ int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) | |||
659 | int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) | 586 | int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) |
660 | { | 587 | { |
661 | struct clkdm_dep *cd; | 588 | struct clkdm_dep *cd; |
662 | 589 | int ret = 0; | |
663 | if (!cpu_is_omap34xx()) | ||
664 | return -EINVAL; | ||
665 | 590 | ||
666 | if (!clkdm1 || !clkdm2) | 591 | if (!clkdm1 || !clkdm2) |
667 | return -EINVAL; | 592 | return -EINVAL; |
668 | 593 | ||
669 | cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); | 594 | cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); |
670 | if (IS_ERR(cd)) { | 595 | if (IS_ERR(cd)) |
596 | ret = PTR_ERR(cd); | ||
597 | |||
598 | if (!arch_clkdm || !arch_clkdm->clkdm_del_sleepdep) | ||
599 | ret = -EINVAL; | ||
600 | |||
601 | if (ret) { | ||
671 | pr_debug("clockdomain: hardware cannot set/clear sleep " | 602 | pr_debug("clockdomain: hardware cannot set/clear sleep " |
672 | "dependency affecting %s from %s\n", clkdm1->name, | 603 | "dependency affecting %s from %s\n", clkdm1->name, |
673 | clkdm2->name); | 604 | clkdm2->name); |
674 | return PTR_ERR(cd); | 605 | return ret; |
675 | } | 606 | } |
676 | 607 | ||
677 | if (atomic_dec_return(&cd->sleepdep_usecount) == 0) { | 608 | if (atomic_dec_return(&cd->sleepdep_usecount) == 0) { |
@@ -679,12 +610,10 @@ int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) | |||
679 | "sleeping if %s is active\n", clkdm1->name, | 610 | "sleeping if %s is active\n", clkdm1->name, |
680 | clkdm2->name); | 611 | clkdm2->name); |
681 | 612 | ||
682 | cm_clear_mod_reg_bits((1 << clkdm2->dep_bit), | 613 | ret = arch_clkdm->clkdm_del_sleepdep(clkdm1, clkdm2); |
683 | clkdm1->pwrdm.ptr->prcm_offs, | ||
684 | OMAP3430_CM_SLEEPDEP); | ||
685 | } | 614 | } |
686 | 615 | ||
687 | return 0; | 616 | return ret; |
688 | } | 617 | } |
689 | 618 | ||
690 | /** | 619 | /** |
@@ -706,25 +635,27 @@ int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) | |||
706 | int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) | 635 | int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) |
707 | { | 636 | { |
708 | struct clkdm_dep *cd; | 637 | struct clkdm_dep *cd; |
709 | 638 | int ret = 0; | |
710 | if (!cpu_is_omap34xx()) | ||
711 | return -EINVAL; | ||
712 | 639 | ||
713 | if (!clkdm1 || !clkdm2) | 640 | if (!clkdm1 || !clkdm2) |
714 | return -EINVAL; | 641 | return -EINVAL; |
715 | 642 | ||
716 | cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); | 643 | cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); |
717 | if (IS_ERR(cd)) { | 644 | if (IS_ERR(cd)) |
645 | ret = PTR_ERR(cd); | ||
646 | |||
647 | if (!arch_clkdm || !arch_clkdm->clkdm_read_sleepdep) | ||
648 | ret = -EINVAL; | ||
649 | |||
650 | if (ret) { | ||
718 | pr_debug("clockdomain: hardware cannot set/clear sleep " | 651 | pr_debug("clockdomain: hardware cannot set/clear sleep " |
719 | "dependency affecting %s from %s\n", clkdm1->name, | 652 | "dependency affecting %s from %s\n", clkdm1->name, |
720 | clkdm2->name); | 653 | clkdm2->name); |
721 | return PTR_ERR(cd); | 654 | return ret; |
722 | } | 655 | } |
723 | 656 | ||
724 | /* XXX It's faster to return the atomic sleepdep_usecount */ | 657 | /* XXX It's faster to return the atomic sleepdep_usecount */ |
725 | return prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs, | 658 | return arch_clkdm->clkdm_read_sleepdep(clkdm1, clkdm2); |
726 | OMAP3430_CM_SLEEPDEP, | ||
727 | (1 << clkdm2->dep_bit)); | ||
728 | } | 659 | } |
729 | 660 | ||
730 | /** | 661 | /** |
@@ -739,54 +670,17 @@ int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) | |||
739 | */ | 670 | */ |
740 | int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm) | 671 | int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm) |
741 | { | 672 | { |
742 | struct clkdm_dep *cd; | ||
743 | u32 mask = 0; | ||
744 | |||
745 | if (!cpu_is_omap34xx()) | ||
746 | return -EINVAL; | ||
747 | |||
748 | if (!clkdm) | 673 | if (!clkdm) |
749 | return -EINVAL; | 674 | return -EINVAL; |
750 | 675 | ||
751 | for (cd = clkdm->sleepdep_srcs; cd && cd->clkdm_name; cd++) { | 676 | if (!arch_clkdm || !arch_clkdm->clkdm_clear_all_sleepdeps) |
752 | if (!omap_chip_is(cd->omap_chip)) | ||
753 | continue; | ||
754 | |||
755 | /* PRM accesses are slow, so minimize them */ | ||
756 | mask |= 1 << cd->clkdm->dep_bit; | ||
757 | atomic_set(&cd->sleepdep_usecount, 0); | ||
758 | } | ||
759 | |||
760 | prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs, | ||
761 | OMAP3430_CM_SLEEPDEP); | ||
762 | |||
763 | return 0; | ||
764 | } | ||
765 | |||
766 | /** | ||
767 | * omap2_clkdm_clktrctrl_read - read the clkdm's current state transition mode | ||
768 | * @clkdm: struct clkdm * of a clockdomain | ||
769 | * | ||
770 | * Return the clockdomain @clkdm current state transition mode from the | ||
771 | * corresponding domain CM_CLKSTCTRL register. Returns -EINVAL if @clkdm | ||
772 | * is NULL or the current mode upon success. | ||
773 | */ | ||
774 | static int omap2_clkdm_clktrctrl_read(struct clockdomain *clkdm) | ||
775 | { | ||
776 | u32 v; | ||
777 | |||
778 | if (!clkdm) | ||
779 | return -EINVAL; | 677 | return -EINVAL; |
780 | 678 | ||
781 | v = __raw_readl(clkdm->clkstctrl_reg); | 679 | return arch_clkdm->clkdm_clear_all_sleepdeps(clkdm); |
782 | v &= clkdm->clktrctrl_mask; | ||
783 | v >>= __ffs(clkdm->clktrctrl_mask); | ||
784 | |||
785 | return v; | ||
786 | } | 680 | } |
787 | 681 | ||
788 | /** | 682 | /** |
789 | * omap2_clkdm_sleep - force clockdomain sleep transition | 683 | * clkdm_sleep - force clockdomain sleep transition |
790 | * @clkdm: struct clockdomain * | 684 | * @clkdm: struct clockdomain * |
791 | * | 685 | * |
792 | * Instruct the CM to force a sleep transition on the specified | 686 | * Instruct the CM to force a sleep transition on the specified |
@@ -794,7 +688,7 @@ static int omap2_clkdm_clktrctrl_read(struct clockdomain *clkdm) | |||
794 | * clockdomain does not support software-initiated sleep; 0 upon | 688 | * clockdomain does not support software-initiated sleep; 0 upon |
795 | * success. | 689 | * success. |
796 | */ | 690 | */ |
797 | int omap2_clkdm_sleep(struct clockdomain *clkdm) | 691 | int clkdm_sleep(struct clockdomain *clkdm) |
798 | { | 692 | { |
799 | if (!clkdm) | 693 | if (!clkdm) |
800 | return -EINVAL; | 694 | return -EINVAL; |
@@ -805,32 +699,16 @@ int omap2_clkdm_sleep(struct clockdomain *clkdm) | |||
805 | return -EINVAL; | 699 | return -EINVAL; |
806 | } | 700 | } |
807 | 701 | ||
808 | pr_debug("clockdomain: forcing sleep on %s\n", clkdm->name); | 702 | if (!arch_clkdm || !arch_clkdm->clkdm_sleep) |
809 | 703 | return -EINVAL; | |
810 | if (cpu_is_omap24xx()) { | ||
811 | |||
812 | cm_set_mod_reg_bits(OMAP24XX_FORCESTATE_MASK, | ||
813 | clkdm->pwrdm.ptr->prcm_offs, OMAP2_PM_PWSTCTRL); | ||
814 | |||
815 | } else if (cpu_is_omap34xx() || cpu_is_omap44xx()) { | ||
816 | |||
817 | u32 bits = (OMAP34XX_CLKSTCTRL_FORCE_SLEEP << | ||
818 | __ffs(clkdm->clktrctrl_mask)); | ||
819 | |||
820 | u32 v = __raw_readl(clkdm->clkstctrl_reg); | ||
821 | v &= ~(clkdm->clktrctrl_mask); | ||
822 | v |= bits; | ||
823 | __raw_writel(v, clkdm->clkstctrl_reg); | ||
824 | 704 | ||
825 | } else { | 705 | pr_debug("clockdomain: forcing sleep on %s\n", clkdm->name); |
826 | BUG(); | ||
827 | }; | ||
828 | 706 | ||
829 | return 0; | 707 | return arch_clkdm->clkdm_sleep(clkdm); |
830 | } | 708 | } |
831 | 709 | ||
832 | /** | 710 | /** |
833 | * omap2_clkdm_wakeup - force clockdomain wakeup transition | 711 | * clkdm_wakeup - force clockdomain wakeup transition |
834 | * @clkdm: struct clockdomain * | 712 | * @clkdm: struct clockdomain * |
835 | * | 713 | * |
836 | * Instruct the CM to force a wakeup transition on the specified | 714 | * Instruct the CM to force a wakeup transition on the specified |
@@ -838,7 +716,7 @@ int omap2_clkdm_sleep(struct clockdomain *clkdm) | |||
838 | * clockdomain does not support software-controlled wakeup; 0 upon | 716 | * clockdomain does not support software-controlled wakeup; 0 upon |
839 | * success. | 717 | * success. |
840 | */ | 718 | */ |
841 | int omap2_clkdm_wakeup(struct clockdomain *clkdm) | 719 | int clkdm_wakeup(struct clockdomain *clkdm) |
842 | { | 720 | { |
843 | if (!clkdm) | 721 | if (!clkdm) |
844 | return -EINVAL; | 722 | return -EINVAL; |
@@ -849,32 +727,16 @@ int omap2_clkdm_wakeup(struct clockdomain *clkdm) | |||
849 | return -EINVAL; | 727 | return -EINVAL; |
850 | } | 728 | } |
851 | 729 | ||
852 | pr_debug("clockdomain: forcing wakeup on %s\n", clkdm->name); | 730 | if (!arch_clkdm || !arch_clkdm->clkdm_wakeup) |
853 | 731 | return -EINVAL; | |
854 | if (cpu_is_omap24xx()) { | ||
855 | |||
856 | cm_clear_mod_reg_bits(OMAP24XX_FORCESTATE_MASK, | ||
857 | clkdm->pwrdm.ptr->prcm_offs, OMAP2_PM_PWSTCTRL); | ||
858 | |||
859 | } else if (cpu_is_omap34xx() || cpu_is_omap44xx()) { | ||
860 | |||
861 | u32 bits = (OMAP34XX_CLKSTCTRL_FORCE_WAKEUP << | ||
862 | __ffs(clkdm->clktrctrl_mask)); | ||
863 | |||
864 | u32 v = __raw_readl(clkdm->clkstctrl_reg); | ||
865 | v &= ~(clkdm->clktrctrl_mask); | ||
866 | v |= bits; | ||
867 | __raw_writel(v, clkdm->clkstctrl_reg); | ||
868 | 732 | ||
869 | } else { | 733 | pr_debug("clockdomain: forcing wakeup on %s\n", clkdm->name); |
870 | BUG(); | ||
871 | }; | ||
872 | 734 | ||
873 | return 0; | 735 | return arch_clkdm->clkdm_wakeup(clkdm); |
874 | } | 736 | } |
875 | 737 | ||
876 | /** | 738 | /** |
877 | * omap2_clkdm_allow_idle - enable hwsup idle transitions for clkdm | 739 | * clkdm_allow_idle - enable hwsup idle transitions for clkdm |
878 | * @clkdm: struct clockdomain * | 740 | * @clkdm: struct clockdomain * |
879 | * | 741 | * |
880 | * Allow the hardware to automatically switch the clockdomain @clkdm into | 742 | * Allow the hardware to automatically switch the clockdomain @clkdm into |
@@ -883,7 +745,7 @@ int omap2_clkdm_wakeup(struct clockdomain *clkdm) | |||
883 | * framework, wkdep/sleepdep autodependencies are added; this is so | 745 | * framework, wkdep/sleepdep autodependencies are added; this is so |
884 | * device drivers can read and write to the device. No return value. | 746 | * device drivers can read and write to the device. No return value. |
885 | */ | 747 | */ |
886 | void omap2_clkdm_allow_idle(struct clockdomain *clkdm) | 748 | void clkdm_allow_idle(struct clockdomain *clkdm) |
887 | { | 749 | { |
888 | if (!clkdm) | 750 | if (!clkdm) |
889 | return; | 751 | return; |
@@ -894,28 +756,18 @@ void omap2_clkdm_allow_idle(struct clockdomain *clkdm) | |||
894 | return; | 756 | return; |
895 | } | 757 | } |
896 | 758 | ||
759 | if (!arch_clkdm || !arch_clkdm->clkdm_allow_idle) | ||
760 | return; | ||
761 | |||
897 | pr_debug("clockdomain: enabling automatic idle transitions for %s\n", | 762 | pr_debug("clockdomain: enabling automatic idle transitions for %s\n", |
898 | clkdm->name); | 763 | clkdm->name); |
899 | 764 | ||
900 | /* | 765 | arch_clkdm->clkdm_allow_idle(clkdm); |
901 | * XXX This should be removed once TI adds wakeup/sleep | ||
902 | * dependency code and data for OMAP4. | ||
903 | */ | ||
904 | if (cpu_is_omap44xx()) { | ||
905 | WARN_ONCE(1, "clockdomain: OMAP4 wakeup/sleep dependency " | ||
906 | "support is not yet implemented\n"); | ||
907 | } else { | ||
908 | if (atomic_read(&clkdm->usecount) > 0) | ||
909 | _clkdm_add_autodeps(clkdm); | ||
910 | } | ||
911 | |||
912 | _omap2_clkdm_set_hwsup(clkdm, 1); | ||
913 | |||
914 | pwrdm_clkdm_state_switch(clkdm); | 766 | pwrdm_clkdm_state_switch(clkdm); |
915 | } | 767 | } |
916 | 768 | ||
917 | /** | 769 | /** |
918 | * omap2_clkdm_deny_idle - disable hwsup idle transitions for clkdm | 770 | * clkdm_deny_idle - disable hwsup idle transitions for clkdm |
919 | * @clkdm: struct clockdomain * | 771 | * @clkdm: struct clockdomain * |
920 | * | 772 | * |
921 | * Prevent the hardware from automatically switching the clockdomain | 773 | * Prevent the hardware from automatically switching the clockdomain |
@@ -923,7 +775,7 @@ void omap2_clkdm_allow_idle(struct clockdomain *clkdm) | |||
923 | * downstream clocks enabled in the clock framework, wkdep/sleepdep | 775 | * downstream clocks enabled in the clock framework, wkdep/sleepdep |
924 | * autodependencies are removed. No return value. | 776 | * autodependencies are removed. No return value. |
925 | */ | 777 | */ |
926 | void omap2_clkdm_deny_idle(struct clockdomain *clkdm) | 778 | void clkdm_deny_idle(struct clockdomain *clkdm) |
927 | { | 779 | { |
928 | if (!clkdm) | 780 | if (!clkdm) |
929 | return; | 781 | return; |
@@ -934,29 +786,20 @@ void omap2_clkdm_deny_idle(struct clockdomain *clkdm) | |||
934 | return; | 786 | return; |
935 | } | 787 | } |
936 | 788 | ||
789 | if (!arch_clkdm || !arch_clkdm->clkdm_deny_idle) | ||
790 | return; | ||
791 | |||
937 | pr_debug("clockdomain: disabling automatic idle transitions for %s\n", | 792 | pr_debug("clockdomain: disabling automatic idle transitions for %s\n", |
938 | clkdm->name); | 793 | clkdm->name); |
939 | 794 | ||
940 | _omap2_clkdm_set_hwsup(clkdm, 0); | 795 | arch_clkdm->clkdm_deny_idle(clkdm); |
941 | |||
942 | /* | ||
943 | * XXX This should be removed once TI adds wakeup/sleep | ||
944 | * dependency code and data for OMAP4. | ||
945 | */ | ||
946 | if (cpu_is_omap44xx()) { | ||
947 | WARN_ONCE(1, "clockdomain: OMAP4 wakeup/sleep dependency " | ||
948 | "support is not yet implemented\n"); | ||
949 | } else { | ||
950 | if (atomic_read(&clkdm->usecount) > 0) | ||
951 | _clkdm_del_autodeps(clkdm); | ||
952 | } | ||
953 | } | 796 | } |
954 | 797 | ||
955 | 798 | ||
956 | /* Clockdomain-to-clock framework interface code */ | 799 | /* Clockdomain-to-clock framework interface code */ |
957 | 800 | ||
958 | /** | 801 | /** |
959 | * omap2_clkdm_clk_enable - add an enabled downstream clock to this clkdm | 802 | * clkdm_clk_enable - add an enabled downstream clock to this clkdm |
960 | * @clkdm: struct clockdomain * | 803 | * @clkdm: struct clockdomain * |
961 | * @clk: struct clk * of the enabled downstream clock | 804 | * @clk: struct clk * of the enabled downstream clock |
962 | * | 805 | * |
@@ -969,10 +812,8 @@ void omap2_clkdm_deny_idle(struct clockdomain *clkdm) | |||
969 | * by on-chip processors. Returns -EINVAL if passed null pointers; | 812 | * by on-chip processors. Returns -EINVAL if passed null pointers; |
970 | * returns 0 upon success or if the clockdomain is in hwsup idle mode. | 813 | * returns 0 upon success or if the clockdomain is in hwsup idle mode. |
971 | */ | 814 | */ |
972 | int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk) | 815 | int clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk) |
973 | { | 816 | { |
974 | int v; | ||
975 | |||
976 | /* | 817 | /* |
977 | * XXX Rewrite this code to maintain a list of enabled | 818 | * XXX Rewrite this code to maintain a list of enabled |
978 | * downstream clocks for debugging purposes? | 819 | * downstream clocks for debugging purposes? |
@@ -981,6 +822,9 @@ int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk) | |||
981 | if (!clkdm || !clk) | 822 | if (!clkdm || !clk) |
982 | return -EINVAL; | 823 | return -EINVAL; |
983 | 824 | ||
825 | if (!arch_clkdm || !arch_clkdm->clkdm_clk_enable) | ||
826 | return -EINVAL; | ||
827 | |||
984 | if (atomic_inc_return(&clkdm->usecount) > 1) | 828 | if (atomic_inc_return(&clkdm->usecount) > 1) |
985 | return 0; | 829 | return 0; |
986 | 830 | ||
@@ -989,21 +833,7 @@ int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk) | |||
989 | pr_debug("clockdomain: clkdm %s: clk %s now enabled\n", clkdm->name, | 833 | pr_debug("clockdomain: clkdm %s: clk %s now enabled\n", clkdm->name, |
990 | clk->name); | 834 | clk->name); |
991 | 835 | ||
992 | if (!clkdm->clkstctrl_reg) | 836 | arch_clkdm->clkdm_clk_enable(clkdm); |
993 | return 0; | ||
994 | |||
995 | v = omap2_clkdm_clktrctrl_read(clkdm); | ||
996 | |||
997 | if ((cpu_is_omap34xx() && v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) || | ||
998 | (cpu_is_omap24xx() && v == OMAP24XX_CLKSTCTRL_ENABLE_AUTO)) { | ||
999 | /* Disable HW transitions when we are changing deps */ | ||
1000 | _omap2_clkdm_set_hwsup(clkdm, 0); | ||
1001 | _clkdm_add_autodeps(clkdm); | ||
1002 | _omap2_clkdm_set_hwsup(clkdm, 1); | ||
1003 | } else { | ||
1004 | omap2_clkdm_wakeup(clkdm); | ||
1005 | } | ||
1006 | |||
1007 | pwrdm_wait_transition(clkdm->pwrdm.ptr); | 837 | pwrdm_wait_transition(clkdm->pwrdm.ptr); |
1008 | pwrdm_clkdm_state_switch(clkdm); | 838 | pwrdm_clkdm_state_switch(clkdm); |
1009 | 839 | ||
@@ -1011,7 +841,7 @@ int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk) | |||
1011 | } | 841 | } |
1012 | 842 | ||
1013 | /** | 843 | /** |
1014 | * omap2_clkdm_clk_disable - remove an enabled downstream clock from this clkdm | 844 | * clkdm_clk_disable - remove an enabled downstream clock from this clkdm |
1015 | * @clkdm: struct clockdomain * | 845 | * @clkdm: struct clockdomain * |
1016 | * @clk: struct clk * of the disabled downstream clock | 846 | * @clk: struct clk * of the disabled downstream clock |
1017 | * | 847 | * |
@@ -1024,10 +854,8 @@ int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk) | |||
1024 | * is enabled; or returns 0 upon success or if the clockdomain is in | 854 | * is enabled; or returns 0 upon success or if the clockdomain is in |
1025 | * hwsup idle mode. | 855 | * hwsup idle mode. |
1026 | */ | 856 | */ |
1027 | int omap2_clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk) | 857 | int clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk) |
1028 | { | 858 | { |
1029 | int v; | ||
1030 | |||
1031 | /* | 859 | /* |
1032 | * XXX Rewrite this code to maintain a list of enabled | 860 | * XXX Rewrite this code to maintain a list of enabled |
1033 | * downstream clocks for debugging purposes? | 861 | * downstream clocks for debugging purposes? |
@@ -1036,6 +864,9 @@ int omap2_clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk) | |||
1036 | if (!clkdm || !clk) | 864 | if (!clkdm || !clk) |
1037 | return -EINVAL; | 865 | return -EINVAL; |
1038 | 866 | ||
867 | if (!arch_clkdm || !arch_clkdm->clkdm_clk_disable) | ||
868 | return -EINVAL; | ||
869 | |||
1039 | #ifdef DEBUG | 870 | #ifdef DEBUG |
1040 | if (atomic_read(&clkdm->usecount) == 0) { | 871 | if (atomic_read(&clkdm->usecount) == 0) { |
1041 | WARN_ON(1); /* underflow */ | 872 | WARN_ON(1); /* underflow */ |
@@ -1051,21 +882,7 @@ int omap2_clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk) | |||
1051 | pr_debug("clockdomain: clkdm %s: clk %s now disabled\n", clkdm->name, | 882 | pr_debug("clockdomain: clkdm %s: clk %s now disabled\n", clkdm->name, |
1052 | clk->name); | 883 | clk->name); |
1053 | 884 | ||
1054 | if (!clkdm->clkstctrl_reg) | 885 | arch_clkdm->clkdm_clk_disable(clkdm); |
1055 | return 0; | ||
1056 | |||
1057 | v = omap2_clkdm_clktrctrl_read(clkdm); | ||
1058 | |||
1059 | if ((cpu_is_omap34xx() && v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) || | ||
1060 | (cpu_is_omap24xx() && v == OMAP24XX_CLKSTCTRL_ENABLE_AUTO)) { | ||
1061 | /* Disable HW transitions when we are changing deps */ | ||
1062 | _omap2_clkdm_set_hwsup(clkdm, 0); | ||
1063 | _clkdm_del_autodeps(clkdm); | ||
1064 | _omap2_clkdm_set_hwsup(clkdm, 1); | ||
1065 | } else { | ||
1066 | omap2_clkdm_sleep(clkdm); | ||
1067 | } | ||
1068 | |||
1069 | pwrdm_clkdm_state_switch(clkdm); | 886 | pwrdm_clkdm_state_switch(clkdm); |
1070 | 887 | ||
1071 | return 0; | 888 | return 0; |