diff options
Diffstat (limited to 'arch/arm/mach-omap2/clockdomain.c')
-rw-r--r-- | arch/arm/mach-omap2/clockdomain.c | 439 |
1 files changed, 143 insertions, 296 deletions
diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c index 58e42f76603f..ab878545bd9b 100644 --- a/arch/arm/mach-omap2/clockdomain.c +++ b/arch/arm/mach-omap2/clockdomain.c | |||
@@ -26,17 +26,8 @@ | |||
26 | 26 | ||
27 | #include <linux/bitops.h> | 27 | #include <linux/bitops.h> |
28 | 28 | ||
29 | #include "prm2xxx_3xxx.h" | ||
30 | #include "prm-regbits-24xx.h" | ||
31 | #include "cm2xxx_3xxx.h" | ||
32 | #include "cm-regbits-24xx.h" | ||
33 | #include "cminst44xx.h" | ||
34 | #include "prcm44xx.h" | ||
35 | |||
36 | #include <plat/clock.h> | 29 | #include <plat/clock.h> |
37 | #include "powerdomain.h" | ||
38 | #include "clockdomain.h" | 30 | #include "clockdomain.h" |
39 | #include <plat/prcm.h> | ||
40 | 31 | ||
41 | /* clkdm_list contains all registered struct clockdomains */ | 32 | /* clkdm_list contains all registered struct clockdomains */ |
42 | static LIST_HEAD(clkdm_list); | 33 | static LIST_HEAD(clkdm_list); |
@@ -44,6 +35,7 @@ static LIST_HEAD(clkdm_list); | |||
44 | /* 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 */ |
45 | static struct clkdm_autodep *autodeps; | 36 | static struct clkdm_autodep *autodeps; |
46 | 37 | ||
38 | static struct clkdm_ops *arch_clkdm; | ||
47 | 39 | ||
48 | /* Private functions */ | 40 | /* Private functions */ |
49 | 41 | ||
@@ -177,11 +169,11 @@ static void _autodep_lookup(struct clkdm_autodep *autodep) | |||
177 | * XXX autodeps are deprecated and should be removed at the earliest | 169 | * XXX autodeps are deprecated and should be removed at the earliest |
178 | * opportunity | 170 | * opportunity |
179 | */ | 171 | */ |
180 | static void _clkdm_add_autodeps(struct clockdomain *clkdm) | 172 | void _clkdm_add_autodeps(struct clockdomain *clkdm) |
181 | { | 173 | { |
182 | struct clkdm_autodep *autodep; | 174 | struct clkdm_autodep *autodep; |
183 | 175 | ||
184 | if (!autodeps) | 176 | if (!autodeps || clkdm->flags & CLKDM_NO_AUTODEPS) |
185 | return; | 177 | return; |
186 | 178 | ||
187 | for (autodep = autodeps; autodep->clkdm.ptr; autodep++) { | 179 | for (autodep = autodeps; autodep->clkdm.ptr; autodep++) { |
@@ -211,11 +203,11 @@ static void _clkdm_add_autodeps(struct clockdomain *clkdm) | |||
211 | * XXX autodeps are deprecated and should be removed at the earliest | 203 | * XXX autodeps are deprecated and should be removed at the earliest |
212 | * opportunity | 204 | * opportunity |
213 | */ | 205 | */ |
214 | static void _clkdm_del_autodeps(struct clockdomain *clkdm) | 206 | void _clkdm_del_autodeps(struct clockdomain *clkdm) |
215 | { | 207 | { |
216 | struct clkdm_autodep *autodep; | 208 | struct clkdm_autodep *autodep; |
217 | 209 | ||
218 | if (!autodeps) | 210 | if (!autodeps || clkdm->flags & CLKDM_NO_AUTODEPS) |
219 | return; | 211 | return; |
220 | 212 | ||
221 | for (autodep = autodeps; autodep->clkdm.ptr; autodep++) { | 213 | for (autodep = autodeps; autodep->clkdm.ptr; autodep++) { |
@@ -235,55 +227,29 @@ static void _clkdm_del_autodeps(struct clockdomain *clkdm) | |||
235 | } | 227 | } |
236 | 228 | ||
237 | /** | 229 | /** |
238 | * _enable_hwsup - place a clockdomain into hardware-supervised idle | 230 | * _resolve_clkdm_deps() - resolve clkdm_names in @clkdm_deps to clkdms |
239 | * @clkdm: struct clockdomain * | 231 | * @clkdm: clockdomain that we are resolving dependencies for |
240 | * | 232 | * @clkdm_deps: ptr to array of struct clkdm_deps to resolve |
241 | * Place the clockdomain into hardware-supervised idle mode. No return | ||
242 | * value. | ||
243 | * | 233 | * |
244 | * XXX Should this return an error if the clockdomain does not support | 234 | * Iterates through @clkdm_deps, looking up the struct clockdomain named by |
245 | * hardware-supervised idle mode? | 235 | * clkdm_name and storing the clockdomain pointer in the struct clkdm_dep. |
246 | */ | ||
247 | static void _enable_hwsup(struct clockdomain *clkdm) | ||
248 | { | ||
249 | if (cpu_is_omap24xx()) | ||
250 | omap2xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs, | ||
251 | clkdm->clktrctrl_mask); | ||
252 | else if (cpu_is_omap34xx()) | ||
253 | omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs, | ||
254 | clkdm->clktrctrl_mask); | ||
255 | else if (cpu_is_omap44xx()) | ||
256 | return omap4_cminst_clkdm_enable_hwsup(clkdm->prcm_partition, | ||
257 | clkdm->cm_inst, | ||
258 | clkdm->clkdm_offs); | ||
259 | else | ||
260 | BUG(); | ||
261 | } | ||
262 | |||
263 | /** | ||
264 | * _disable_hwsup - place a clockdomain into software-supervised idle | ||
265 | * @clkdm: struct clockdomain * | ||
266 | * | ||
267 | * Place the clockdomain @clkdm into software-supervised idle mode. | ||
268 | * No return value. | 236 | * No return value. |
269 | * | ||
270 | * XXX Should this return an error if the clockdomain does not support | ||
271 | * software-supervised idle mode? | ||
272 | */ | 237 | */ |
273 | static void _disable_hwsup(struct clockdomain *clkdm) | 238 | static void _resolve_clkdm_deps(struct clockdomain *clkdm, |
239 | struct clkdm_dep *clkdm_deps) | ||
274 | { | 240 | { |
275 | if (cpu_is_omap24xx()) | 241 | struct clkdm_dep *cd; |
276 | omap2xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs, | 242 | |
277 | clkdm->clktrctrl_mask); | 243 | for (cd = clkdm_deps; cd && cd->clkdm_name; cd++) { |
278 | else if (cpu_is_omap34xx()) | 244 | if (!omap_chip_is(cd->omap_chip)) |
279 | omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs, | 245 | continue; |
280 | clkdm->clktrctrl_mask); | 246 | if (cd->clkdm) |
281 | else if (cpu_is_omap44xx()) | 247 | continue; |
282 | return omap4_cminst_clkdm_disable_hwsup(clkdm->prcm_partition, | 248 | cd->clkdm = _clkdm_lookup(cd->clkdm_name); |
283 | clkdm->cm_inst, | 249 | |
284 | clkdm->clkdm_offs); | 250 | WARN(!cd->clkdm, "clockdomain: %s: could not find clkdm %s while resolving dependencies - should never happen", |
285 | else | 251 | clkdm->name, cd->clkdm_name); |
286 | BUG(); | 252 | } |
287 | } | 253 | } |
288 | 254 | ||
289 | /* Public functions */ | 255 | /* Public functions */ |
@@ -292,6 +258,7 @@ static void _disable_hwsup(struct clockdomain *clkdm) | |||
292 | * clkdm_init - set up the clockdomain layer | 258 | * clkdm_init - set up the clockdomain layer |
293 | * @clkdms: optional pointer to an array of clockdomains to register | 259 | * @clkdms: optional pointer to an array of clockdomains to register |
294 | * @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 specfic implementations | ||
295 | * | 262 | * |
296 | * 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 |
297 | * @clkdms was supplied, loop through the list of clockdomains, | 264 | * @clkdms was supplied, loop through the list of clockdomains, |
@@ -300,12 +267,18 @@ static void _disable_hwsup(struct clockdomain *clkdm) | |||
300 | * @init_autodeps was provided, register those. No return value. | 267 | * @init_autodeps was provided, register those. No return value. |
301 | */ | 268 | */ |
302 | void clkdm_init(struct clockdomain **clkdms, | 269 | void clkdm_init(struct clockdomain **clkdms, |
303 | struct clkdm_autodep *init_autodeps) | 270 | struct clkdm_autodep *init_autodeps, |
271 | struct clkdm_ops *custom_funcs) | ||
304 | { | 272 | { |
305 | struct clockdomain **c = NULL; | 273 | struct clockdomain **c = NULL; |
306 | struct clockdomain *clkdm; | 274 | struct clockdomain *clkdm; |
307 | struct clkdm_autodep *autodep = NULL; | 275 | struct clkdm_autodep *autodep = NULL; |
308 | 276 | ||
277 | if (!custom_funcs) | ||
278 | WARN(1, "No custom clkdm functions registered\n"); | ||
279 | else | ||
280 | arch_clkdm = custom_funcs; | ||
281 | |||
309 | if (clkdms) | 282 | if (clkdms) |
310 | for (c = clkdms; *c; c++) | 283 | for (c = clkdms; *c; c++) |
311 | _clkdm_register(*c); | 284 | _clkdm_register(*c); |
@@ -321,11 +294,14 @@ void clkdm_init(struct clockdomain **clkdms, | |||
321 | */ | 294 | */ |
322 | list_for_each_entry(clkdm, &clkdm_list, node) { | 295 | list_for_each_entry(clkdm, &clkdm_list, node) { |
323 | if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP) | 296 | if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP) |
324 | omap2_clkdm_wakeup(clkdm); | 297 | clkdm_wakeup(clkdm); |
325 | else if (clkdm->flags & CLKDM_CAN_DISABLE_AUTO) | 298 | else if (clkdm->flags & CLKDM_CAN_DISABLE_AUTO) |
326 | omap2_clkdm_deny_idle(clkdm); | 299 | clkdm_deny_idle(clkdm); |
327 | 300 | ||
301 | _resolve_clkdm_deps(clkdm, clkdm->wkdep_srcs); | ||
328 | clkdm_clear_all_wkdeps(clkdm); | 302 | clkdm_clear_all_wkdeps(clkdm); |
303 | |||
304 | _resolve_clkdm_deps(clkdm, clkdm->sleepdep_srcs); | ||
329 | clkdm_clear_all_sleepdeps(clkdm); | 305 | clkdm_clear_all_sleepdeps(clkdm); |
330 | } | 306 | } |
331 | } | 307 | } |
@@ -422,32 +398,32 @@ struct powerdomain *clkdm_get_pwrdm(struct clockdomain *clkdm) | |||
422 | int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) | 398 | int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) |
423 | { | 399 | { |
424 | struct clkdm_dep *cd; | 400 | struct clkdm_dep *cd; |
425 | 401 | int ret = 0; | |
426 | if (!cpu_is_omap24xx() && !cpu_is_omap34xx()) { | ||
427 | pr_err("clockdomain: %s/%s: %s: not yet implemented\n", | ||
428 | clkdm1->name, clkdm2->name, __func__); | ||
429 | return -EINVAL; | ||
430 | } | ||
431 | 402 | ||
432 | if (!clkdm1 || !clkdm2) | 403 | if (!clkdm1 || !clkdm2) |
433 | return -EINVAL; | 404 | return -EINVAL; |
434 | 405 | ||
435 | cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); | 406 | cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); |
436 | 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) { | ||
437 | pr_debug("clockdomain: hardware cannot set/clear wake up of " | 414 | pr_debug("clockdomain: hardware cannot set/clear wake up of " |
438 | "%s when %s wakes up\n", clkdm1->name, clkdm2->name); | 415 | "%s when %s wakes up\n", clkdm1->name, clkdm2->name); |
439 | return PTR_ERR(cd); | 416 | return ret; |
440 | } | 417 | } |
441 | 418 | ||
442 | if (atomic_inc_return(&cd->wkdep_usecount) == 1) { | 419 | if (atomic_inc_return(&cd->wkdep_usecount) == 1) { |
443 | pr_debug("clockdomain: hardware will wake up %s when %s wakes " | 420 | pr_debug("clockdomain: hardware will wake up %s when %s wakes " |
444 | "up\n", clkdm1->name, clkdm2->name); | 421 | "up\n", clkdm1->name, clkdm2->name); |
445 | 422 | ||
446 | omap2_prm_set_mod_reg_bits((1 << clkdm2->dep_bit), | 423 | ret = arch_clkdm->clkdm_add_wkdep(clkdm1, clkdm2); |
447 | clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP); | ||
448 | } | 424 | } |
449 | 425 | ||
450 | return 0; | 426 | return ret; |
451 | } | 427 | } |
452 | 428 | ||
453 | /** | 429 | /** |
@@ -463,32 +439,32 @@ int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) | |||
463 | int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) | 439 | int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) |
464 | { | 440 | { |
465 | struct clkdm_dep *cd; | 441 | struct clkdm_dep *cd; |
466 | 442 | int ret = 0; | |
467 | if (!cpu_is_omap24xx() && !cpu_is_omap34xx()) { | ||
468 | pr_err("clockdomain: %s/%s: %s: not yet implemented\n", | ||
469 | clkdm1->name, clkdm2->name, __func__); | ||
470 | return -EINVAL; | ||
471 | } | ||
472 | 443 | ||
473 | if (!clkdm1 || !clkdm2) | 444 | if (!clkdm1 || !clkdm2) |
474 | return -EINVAL; | 445 | return -EINVAL; |
475 | 446 | ||
476 | cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); | 447 | cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); |
477 | 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) { | ||
478 | pr_debug("clockdomain: hardware cannot set/clear wake up of " | 455 | pr_debug("clockdomain: hardware cannot set/clear wake up of " |
479 | "%s when %s wakes up\n", clkdm1->name, clkdm2->name); | 456 | "%s when %s wakes up\n", clkdm1->name, clkdm2->name); |
480 | return PTR_ERR(cd); | 457 | return ret; |
481 | } | 458 | } |
482 | 459 | ||
483 | if (atomic_dec_return(&cd->wkdep_usecount) == 0) { | 460 | if (atomic_dec_return(&cd->wkdep_usecount) == 0) { |
484 | pr_debug("clockdomain: hardware will no longer wake up %s " | 461 | pr_debug("clockdomain: hardware will no longer wake up %s " |
485 | "after %s wakes up\n", clkdm1->name, clkdm2->name); | 462 | "after %s wakes up\n", clkdm1->name, clkdm2->name); |
486 | 463 | ||
487 | omap2_prm_clear_mod_reg_bits((1 << clkdm2->dep_bit), | 464 | ret = arch_clkdm->clkdm_del_wkdep(clkdm1, clkdm2); |
488 | clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP); | ||
489 | } | 465 | } |
490 | 466 | ||
491 | return 0; | 467 | return ret; |
492 | } | 468 | } |
493 | 469 | ||
494 | /** | 470 | /** |
@@ -508,26 +484,26 @@ int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) | |||
508 | int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) | 484 | int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) |
509 | { | 485 | { |
510 | struct clkdm_dep *cd; | 486 | struct clkdm_dep *cd; |
487 | int ret = 0; | ||
511 | 488 | ||
512 | if (!clkdm1 || !clkdm2) | 489 | if (!clkdm1 || !clkdm2) |
513 | return -EINVAL; | 490 | return -EINVAL; |
514 | 491 | ||
515 | if (!cpu_is_omap24xx() && !cpu_is_omap34xx()) { | ||
516 | pr_err("clockdomain: %s/%s: %s: not yet implemented\n", | ||
517 | clkdm1->name, clkdm2->name, __func__); | ||
518 | return -EINVAL; | ||
519 | } | ||
520 | |||
521 | cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); | 492 | cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); |
522 | 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) { | ||
523 | pr_debug("clockdomain: hardware cannot set/clear wake up of " | 500 | pr_debug("clockdomain: hardware cannot set/clear wake up of " |
524 | "%s when %s wakes up\n", clkdm1->name, clkdm2->name); | 501 | "%s when %s wakes up\n", clkdm1->name, clkdm2->name); |
525 | return PTR_ERR(cd); | 502 | return ret; |
526 | } | 503 | } |
527 | 504 | ||
528 | /* XXX It's faster to return the atomic wkdep_usecount */ | 505 | /* XXX It's faster to return the atomic wkdep_usecount */ |
529 | return omap2_prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP, | 506 | return arch_clkdm->clkdm_read_wkdep(clkdm1, clkdm2); |
530 | (1 << clkdm2->dep_bit)); | ||
531 | } | 507 | } |
532 | 508 | ||
533 | /** | 509 | /** |
@@ -542,33 +518,13 @@ int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) | |||
542 | */ | 518 | */ |
543 | int clkdm_clear_all_wkdeps(struct clockdomain *clkdm) | 519 | int clkdm_clear_all_wkdeps(struct clockdomain *clkdm) |
544 | { | 520 | { |
545 | struct clkdm_dep *cd; | ||
546 | u32 mask = 0; | ||
547 | |||
548 | if (!cpu_is_omap24xx() && !cpu_is_omap34xx()) { | ||
549 | pr_err("clockdomain: %s: %s: not yet implemented\n", | ||
550 | clkdm->name, __func__); | ||
551 | return -EINVAL; | ||
552 | } | ||
553 | |||
554 | if (!clkdm) | 521 | if (!clkdm) |
555 | return -EINVAL; | 522 | return -EINVAL; |
556 | 523 | ||
557 | for (cd = clkdm->wkdep_srcs; cd && cd->clkdm_name; cd++) { | 524 | if (!arch_clkdm || !arch_clkdm->clkdm_clear_all_wkdeps) |
558 | if (!omap_chip_is(cd->omap_chip)) | 525 | return -EINVAL; |
559 | continue; | ||
560 | |||
561 | if (!cd->clkdm && cd->clkdm_name) | ||
562 | cd->clkdm = _clkdm_lookup(cd->clkdm_name); | ||
563 | |||
564 | /* PRM accesses are slow, so minimize them */ | ||
565 | mask |= 1 << cd->clkdm->dep_bit; | ||
566 | atomic_set(&cd->wkdep_usecount, 0); | ||
567 | } | ||
568 | |||
569 | omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs, PM_WKDEP); | ||
570 | 526 | ||
571 | return 0; | 527 | return arch_clkdm->clkdm_clear_all_wkdeps(clkdm); |
572 | } | 528 | } |
573 | 529 | ||
574 | /** | 530 | /** |
@@ -586,31 +542,33 @@ int clkdm_clear_all_wkdeps(struct clockdomain *clkdm) | |||
586 | int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) | 542 | int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) |
587 | { | 543 | { |
588 | struct clkdm_dep *cd; | 544 | struct clkdm_dep *cd; |
589 | 545 | int ret = 0; | |
590 | if (!cpu_is_omap34xx()) | ||
591 | return -EINVAL; | ||
592 | 546 | ||
593 | if (!clkdm1 || !clkdm2) | 547 | if (!clkdm1 || !clkdm2) |
594 | return -EINVAL; | 548 | return -EINVAL; |
595 | 549 | ||
596 | cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); | 550 | cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); |
597 | 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) { | ||
598 | pr_debug("clockdomain: hardware cannot set/clear sleep " | 558 | pr_debug("clockdomain: hardware cannot set/clear sleep " |
599 | "dependency affecting %s from %s\n", clkdm1->name, | 559 | "dependency affecting %s from %s\n", clkdm1->name, |
600 | clkdm2->name); | 560 | clkdm2->name); |
601 | return PTR_ERR(cd); | 561 | return ret; |
602 | } | 562 | } |
603 | 563 | ||
604 | if (atomic_inc_return(&cd->sleepdep_usecount) == 1) { | 564 | if (atomic_inc_return(&cd->sleepdep_usecount) == 1) { |
605 | pr_debug("clockdomain: will prevent %s from sleeping if %s " | 565 | pr_debug("clockdomain: will prevent %s from sleeping if %s " |
606 | "is active\n", clkdm1->name, clkdm2->name); | 566 | "is active\n", clkdm1->name, clkdm2->name); |
607 | 567 | ||
608 | omap2_cm_set_mod_reg_bits((1 << clkdm2->dep_bit), | 568 | ret = arch_clkdm->clkdm_add_sleepdep(clkdm1, clkdm2); |
609 | clkdm1->pwrdm.ptr->prcm_offs, | ||
610 | OMAP3430_CM_SLEEPDEP); | ||
611 | } | 569 | } |
612 | 570 | ||
613 | return 0; | 571 | return ret; |
614 | } | 572 | } |
615 | 573 | ||
616 | /** | 574 | /** |
@@ -628,19 +586,23 @@ int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) | |||
628 | int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) | 586 | int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) |
629 | { | 587 | { |
630 | struct clkdm_dep *cd; | 588 | struct clkdm_dep *cd; |
631 | 589 | int ret = 0; | |
632 | if (!cpu_is_omap34xx()) | ||
633 | return -EINVAL; | ||
634 | 590 | ||
635 | if (!clkdm1 || !clkdm2) | 591 | if (!clkdm1 || !clkdm2) |
636 | return -EINVAL; | 592 | return -EINVAL; |
637 | 593 | ||
638 | cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); | 594 | cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); |
639 | 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) { | ||
640 | pr_debug("clockdomain: hardware cannot set/clear sleep " | 602 | pr_debug("clockdomain: hardware cannot set/clear sleep " |
641 | "dependency affecting %s from %s\n", clkdm1->name, | 603 | "dependency affecting %s from %s\n", clkdm1->name, |
642 | clkdm2->name); | 604 | clkdm2->name); |
643 | return PTR_ERR(cd); | 605 | return ret; |
644 | } | 606 | } |
645 | 607 | ||
646 | if (atomic_dec_return(&cd->sleepdep_usecount) == 0) { | 608 | if (atomic_dec_return(&cd->sleepdep_usecount) == 0) { |
@@ -648,12 +610,10 @@ int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) | |||
648 | "sleeping if %s is active\n", clkdm1->name, | 610 | "sleeping if %s is active\n", clkdm1->name, |
649 | clkdm2->name); | 611 | clkdm2->name); |
650 | 612 | ||
651 | omap2_cm_clear_mod_reg_bits((1 << clkdm2->dep_bit), | 613 | ret = arch_clkdm->clkdm_del_sleepdep(clkdm1, clkdm2); |
652 | clkdm1->pwrdm.ptr->prcm_offs, | ||
653 | OMAP3430_CM_SLEEPDEP); | ||
654 | } | 614 | } |
655 | 615 | ||
656 | return 0; | 616 | return ret; |
657 | } | 617 | } |
658 | 618 | ||
659 | /** | 619 | /** |
@@ -675,25 +635,27 @@ int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) | |||
675 | int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) | 635 | int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) |
676 | { | 636 | { |
677 | struct clkdm_dep *cd; | 637 | struct clkdm_dep *cd; |
678 | 638 | int ret = 0; | |
679 | if (!cpu_is_omap34xx()) | ||
680 | return -EINVAL; | ||
681 | 639 | ||
682 | if (!clkdm1 || !clkdm2) | 640 | if (!clkdm1 || !clkdm2) |
683 | return -EINVAL; | 641 | return -EINVAL; |
684 | 642 | ||
685 | cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); | 643 | cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); |
686 | 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) { | ||
687 | pr_debug("clockdomain: hardware cannot set/clear sleep " | 651 | pr_debug("clockdomain: hardware cannot set/clear sleep " |
688 | "dependency affecting %s from %s\n", clkdm1->name, | 652 | "dependency affecting %s from %s\n", clkdm1->name, |
689 | clkdm2->name); | 653 | clkdm2->name); |
690 | return PTR_ERR(cd); | 654 | return ret; |
691 | } | 655 | } |
692 | 656 | ||
693 | /* XXX It's faster to return the atomic sleepdep_usecount */ | 657 | /* XXX It's faster to return the atomic sleepdep_usecount */ |
694 | return omap2_prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs, | 658 | return arch_clkdm->clkdm_read_sleepdep(clkdm1, clkdm2); |
695 | OMAP3430_CM_SLEEPDEP, | ||
696 | (1 << clkdm2->dep_bit)); | ||
697 | } | 659 | } |
698 | 660 | ||
699 | /** | 661 | /** |
@@ -708,35 +670,17 @@ int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) | |||
708 | */ | 670 | */ |
709 | int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm) | 671 | int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm) |
710 | { | 672 | { |
711 | struct clkdm_dep *cd; | ||
712 | u32 mask = 0; | ||
713 | |||
714 | if (!cpu_is_omap34xx()) | ||
715 | return -EINVAL; | ||
716 | |||
717 | if (!clkdm) | 673 | if (!clkdm) |
718 | return -EINVAL; | 674 | return -EINVAL; |
719 | 675 | ||
720 | for (cd = clkdm->sleepdep_srcs; cd && cd->clkdm_name; cd++) { | 676 | if (!arch_clkdm || !arch_clkdm->clkdm_clear_all_sleepdeps) |
721 | if (!omap_chip_is(cd->omap_chip)) | 677 | return -EINVAL; |
722 | continue; | ||
723 | |||
724 | if (!cd->clkdm && cd->clkdm_name) | ||
725 | cd->clkdm = _clkdm_lookup(cd->clkdm_name); | ||
726 | |||
727 | /* PRM accesses are slow, so minimize them */ | ||
728 | mask |= 1 << cd->clkdm->dep_bit; | ||
729 | atomic_set(&cd->sleepdep_usecount, 0); | ||
730 | } | ||
731 | |||
732 | omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs, | ||
733 | OMAP3430_CM_SLEEPDEP); | ||
734 | 678 | ||
735 | return 0; | 679 | return arch_clkdm->clkdm_clear_all_sleepdeps(clkdm); |
736 | } | 680 | } |
737 | 681 | ||
738 | /** | 682 | /** |
739 | * omap2_clkdm_sleep - force clockdomain sleep transition | 683 | * clkdm_sleep - force clockdomain sleep transition |
740 | * @clkdm: struct clockdomain * | 684 | * @clkdm: struct clockdomain * |
741 | * | 685 | * |
742 | * Instruct the CM to force a sleep transition on the specified | 686 | * Instruct the CM to force a sleep transition on the specified |
@@ -744,7 +688,7 @@ int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm) | |||
744 | * clockdomain does not support software-initiated sleep; 0 upon | 688 | * clockdomain does not support software-initiated sleep; 0 upon |
745 | * success. | 689 | * success. |
746 | */ | 690 | */ |
747 | int omap2_clkdm_sleep(struct clockdomain *clkdm) | 691 | int clkdm_sleep(struct clockdomain *clkdm) |
748 | { | 692 | { |
749 | if (!clkdm) | 693 | if (!clkdm) |
750 | return -EINVAL; | 694 | return -EINVAL; |
@@ -755,33 +699,16 @@ int omap2_clkdm_sleep(struct clockdomain *clkdm) | |||
755 | return -EINVAL; | 699 | return -EINVAL; |
756 | } | 700 | } |
757 | 701 | ||
758 | pr_debug("clockdomain: forcing sleep on %s\n", clkdm->name); | 702 | if (!arch_clkdm || !arch_clkdm->clkdm_sleep) |
759 | 703 | return -EINVAL; | |
760 | if (cpu_is_omap24xx()) { | ||
761 | |||
762 | omap2_cm_set_mod_reg_bits(OMAP24XX_FORCESTATE_MASK, | ||
763 | clkdm->pwrdm.ptr->prcm_offs, OMAP2_PM_PWSTCTRL); | ||
764 | |||
765 | } else if (cpu_is_omap34xx()) { | ||
766 | |||
767 | omap3xxx_cm_clkdm_force_sleep(clkdm->pwrdm.ptr->prcm_offs, | ||
768 | clkdm->clktrctrl_mask); | ||
769 | |||
770 | } else if (cpu_is_omap44xx()) { | ||
771 | |||
772 | omap4_cminst_clkdm_force_sleep(clkdm->prcm_partition, | ||
773 | clkdm->cm_inst, | ||
774 | clkdm->clkdm_offs); | ||
775 | 704 | ||
776 | } else { | 705 | pr_debug("clockdomain: forcing sleep on %s\n", clkdm->name); |
777 | BUG(); | ||
778 | }; | ||
779 | 706 | ||
780 | return 0; | 707 | return arch_clkdm->clkdm_sleep(clkdm); |
781 | } | 708 | } |
782 | 709 | ||
783 | /** | 710 | /** |
784 | * omap2_clkdm_wakeup - force clockdomain wakeup transition | 711 | * clkdm_wakeup - force clockdomain wakeup transition |
785 | * @clkdm: struct clockdomain * | 712 | * @clkdm: struct clockdomain * |
786 | * | 713 | * |
787 | * Instruct the CM to force a wakeup transition on the specified | 714 | * Instruct the CM to force a wakeup transition on the specified |
@@ -789,7 +716,7 @@ int omap2_clkdm_sleep(struct clockdomain *clkdm) | |||
789 | * clockdomain does not support software-controlled wakeup; 0 upon | 716 | * clockdomain does not support software-controlled wakeup; 0 upon |
790 | * success. | 717 | * success. |
791 | */ | 718 | */ |
792 | int omap2_clkdm_wakeup(struct clockdomain *clkdm) | 719 | int clkdm_wakeup(struct clockdomain *clkdm) |
793 | { | 720 | { |
794 | if (!clkdm) | 721 | if (!clkdm) |
795 | return -EINVAL; | 722 | return -EINVAL; |
@@ -800,33 +727,16 @@ int omap2_clkdm_wakeup(struct clockdomain *clkdm) | |||
800 | return -EINVAL; | 727 | return -EINVAL; |
801 | } | 728 | } |
802 | 729 | ||
803 | pr_debug("clockdomain: forcing wakeup on %s\n", clkdm->name); | 730 | if (!arch_clkdm || !arch_clkdm->clkdm_wakeup) |
804 | 731 | return -EINVAL; | |
805 | if (cpu_is_omap24xx()) { | ||
806 | |||
807 | omap2_cm_clear_mod_reg_bits(OMAP24XX_FORCESTATE_MASK, | ||
808 | clkdm->pwrdm.ptr->prcm_offs, OMAP2_PM_PWSTCTRL); | ||
809 | |||
810 | } else if (cpu_is_omap34xx()) { | ||
811 | |||
812 | omap3xxx_cm_clkdm_force_wakeup(clkdm->pwrdm.ptr->prcm_offs, | ||
813 | clkdm->clktrctrl_mask); | ||
814 | |||
815 | } else if (cpu_is_omap44xx()) { | ||
816 | |||
817 | omap4_cminst_clkdm_force_wakeup(clkdm->prcm_partition, | ||
818 | clkdm->cm_inst, | ||
819 | clkdm->clkdm_offs); | ||
820 | 732 | ||
821 | } else { | 733 | pr_debug("clockdomain: forcing wakeup on %s\n", clkdm->name); |
822 | BUG(); | ||
823 | }; | ||
824 | 734 | ||
825 | return 0; | 735 | return arch_clkdm->clkdm_wakeup(clkdm); |
826 | } | 736 | } |
827 | 737 | ||
828 | /** | 738 | /** |
829 | * omap2_clkdm_allow_idle - enable hwsup idle transitions for clkdm | 739 | * clkdm_allow_idle - enable hwsup idle transitions for clkdm |
830 | * @clkdm: struct clockdomain * | 740 | * @clkdm: struct clockdomain * |
831 | * | 741 | * |
832 | * Allow the hardware to automatically switch the clockdomain @clkdm into | 742 | * Allow the hardware to automatically switch the clockdomain @clkdm into |
@@ -835,7 +745,7 @@ int omap2_clkdm_wakeup(struct clockdomain *clkdm) | |||
835 | * framework, wkdep/sleepdep autodependencies are added; this is so | 745 | * framework, wkdep/sleepdep autodependencies are added; this is so |
836 | * 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. |
837 | */ | 747 | */ |
838 | void omap2_clkdm_allow_idle(struct clockdomain *clkdm) | 748 | void clkdm_allow_idle(struct clockdomain *clkdm) |
839 | { | 749 | { |
840 | if (!clkdm) | 750 | if (!clkdm) |
841 | return; | 751 | return; |
@@ -846,27 +756,18 @@ void omap2_clkdm_allow_idle(struct clockdomain *clkdm) | |||
846 | return; | 756 | return; |
847 | } | 757 | } |
848 | 758 | ||
759 | if (!arch_clkdm || !arch_clkdm->clkdm_allow_idle) | ||
760 | return; | ||
761 | |||
849 | pr_debug("clockdomain: enabling automatic idle transitions for %s\n", | 762 | pr_debug("clockdomain: enabling automatic idle transitions for %s\n", |
850 | clkdm->name); | 763 | clkdm->name); |
851 | 764 | ||
852 | /* | 765 | arch_clkdm->clkdm_allow_idle(clkdm); |
853 | * XXX This should be removed once TI adds wakeup/sleep | ||
854 | * dependency code and data for OMAP4. | ||
855 | */ | ||
856 | if (cpu_is_omap44xx()) { | ||
857 | pr_err("clockdomain: %s: OMAP4 wakeup/sleep dependency support: not yet implemented\n", clkdm->name); | ||
858 | } else { | ||
859 | if (atomic_read(&clkdm->usecount) > 0) | ||
860 | _clkdm_add_autodeps(clkdm); | ||
861 | } | ||
862 | |||
863 | _enable_hwsup(clkdm); | ||
864 | |||
865 | pwrdm_clkdm_state_switch(clkdm); | 766 | pwrdm_clkdm_state_switch(clkdm); |
866 | } | 767 | } |
867 | 768 | ||
868 | /** | 769 | /** |
869 | * omap2_clkdm_deny_idle - disable hwsup idle transitions for clkdm | 770 | * clkdm_deny_idle - disable hwsup idle transitions for clkdm |
870 | * @clkdm: struct clockdomain * | 771 | * @clkdm: struct clockdomain * |
871 | * | 772 | * |
872 | * Prevent the hardware from automatically switching the clockdomain | 773 | * Prevent the hardware from automatically switching the clockdomain |
@@ -874,7 +775,7 @@ void omap2_clkdm_allow_idle(struct clockdomain *clkdm) | |||
874 | * downstream clocks enabled in the clock framework, wkdep/sleepdep | 775 | * downstream clocks enabled in the clock framework, wkdep/sleepdep |
875 | * autodependencies are removed. No return value. | 776 | * autodependencies are removed. No return value. |
876 | */ | 777 | */ |
877 | void omap2_clkdm_deny_idle(struct clockdomain *clkdm) | 778 | void clkdm_deny_idle(struct clockdomain *clkdm) |
878 | { | 779 | { |
879 | if (!clkdm) | 780 | if (!clkdm) |
880 | return; | 781 | return; |
@@ -885,28 +786,20 @@ void omap2_clkdm_deny_idle(struct clockdomain *clkdm) | |||
885 | return; | 786 | return; |
886 | } | 787 | } |
887 | 788 | ||
789 | if (!arch_clkdm || !arch_clkdm->clkdm_deny_idle) | ||
790 | return; | ||
791 | |||
888 | pr_debug("clockdomain: disabling automatic idle transitions for %s\n", | 792 | pr_debug("clockdomain: disabling automatic idle transitions for %s\n", |
889 | clkdm->name); | 793 | clkdm->name); |
890 | 794 | ||
891 | _disable_hwsup(clkdm); | 795 | arch_clkdm->clkdm_deny_idle(clkdm); |
892 | |||
893 | /* | ||
894 | * XXX This should be removed once TI adds wakeup/sleep | ||
895 | * dependency code and data for OMAP4. | ||
896 | */ | ||
897 | if (cpu_is_omap44xx()) { | ||
898 | pr_err("clockdomain: %s: OMAP4 wakeup/sleep dependency support: not yet implemented\n", clkdm->name); | ||
899 | } else { | ||
900 | if (atomic_read(&clkdm->usecount) > 0) | ||
901 | _clkdm_del_autodeps(clkdm); | ||
902 | } | ||
903 | } | 796 | } |
904 | 797 | ||
905 | 798 | ||
906 | /* Clockdomain-to-clock framework interface code */ | 799 | /* Clockdomain-to-clock framework interface code */ |
907 | 800 | ||
908 | /** | 801 | /** |
909 | * omap2_clkdm_clk_enable - add an enabled downstream clock to this clkdm | 802 | * clkdm_clk_enable - add an enabled downstream clock to this clkdm |
910 | * @clkdm: struct clockdomain * | 803 | * @clkdm: struct clockdomain * |
911 | * @clk: struct clk * of the enabled downstream clock | 804 | * @clk: struct clk * of the enabled downstream clock |
912 | * | 805 | * |
@@ -919,10 +812,8 @@ void omap2_clkdm_deny_idle(struct clockdomain *clkdm) | |||
919 | * by on-chip processors. Returns -EINVAL if passed null pointers; | 812 | * by on-chip processors. Returns -EINVAL if passed null pointers; |
920 | * 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. |
921 | */ | 814 | */ |
922 | int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk) | 815 | int clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk) |
923 | { | 816 | { |
924 | bool hwsup = false; | ||
925 | |||
926 | /* | 817 | /* |
927 | * XXX Rewrite this code to maintain a list of enabled | 818 | * XXX Rewrite this code to maintain a list of enabled |
928 | * downstream clocks for debugging purposes? | 819 | * downstream clocks for debugging purposes? |
@@ -931,6 +822,9 @@ int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk) | |||
931 | if (!clkdm || !clk) | 822 | if (!clkdm || !clk) |
932 | return -EINVAL; | 823 | return -EINVAL; |
933 | 824 | ||
825 | if (!arch_clkdm || !arch_clkdm->clkdm_clk_enable) | ||
826 | return -EINVAL; | ||
827 | |||
934 | if (atomic_inc_return(&clkdm->usecount) > 1) | 828 | if (atomic_inc_return(&clkdm->usecount) > 1) |
935 | return 0; | 829 | return 0; |
936 | 830 | ||
@@ -939,31 +833,7 @@ int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk) | |||
939 | 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, |
940 | clk->name); | 834 | clk->name); |
941 | 835 | ||
942 | if (cpu_is_omap24xx() || cpu_is_omap34xx()) { | 836 | arch_clkdm->clkdm_clk_enable(clkdm); |
943 | |||
944 | if (!clkdm->clktrctrl_mask) | ||
945 | return 0; | ||
946 | |||
947 | hwsup = omap2_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs, | ||
948 | clkdm->clktrctrl_mask); | ||
949 | |||
950 | } else if (cpu_is_omap44xx()) { | ||
951 | |||
952 | hwsup = omap4_cminst_is_clkdm_in_hwsup(clkdm->prcm_partition, | ||
953 | clkdm->cm_inst, | ||
954 | clkdm->clkdm_offs); | ||
955 | |||
956 | } | ||
957 | |||
958 | if (hwsup) { | ||
959 | /* Disable HW transitions when we are changing deps */ | ||
960 | _disable_hwsup(clkdm); | ||
961 | _clkdm_add_autodeps(clkdm); | ||
962 | _enable_hwsup(clkdm); | ||
963 | } else { | ||
964 | omap2_clkdm_wakeup(clkdm); | ||
965 | } | ||
966 | |||
967 | pwrdm_wait_transition(clkdm->pwrdm.ptr); | 837 | pwrdm_wait_transition(clkdm->pwrdm.ptr); |
968 | pwrdm_clkdm_state_switch(clkdm); | 838 | pwrdm_clkdm_state_switch(clkdm); |
969 | 839 | ||
@@ -971,7 +841,7 @@ int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk) | |||
971 | } | 841 | } |
972 | 842 | ||
973 | /** | 843 | /** |
974 | * omap2_clkdm_clk_disable - remove an enabled downstream clock from this clkdm | 844 | * clkdm_clk_disable - remove an enabled downstream clock from this clkdm |
975 | * @clkdm: struct clockdomain * | 845 | * @clkdm: struct clockdomain * |
976 | * @clk: struct clk * of the disabled downstream clock | 846 | * @clk: struct clk * of the disabled downstream clock |
977 | * | 847 | * |
@@ -984,10 +854,8 @@ int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk) | |||
984 | * 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 |
985 | * hwsup idle mode. | 855 | * hwsup idle mode. |
986 | */ | 856 | */ |
987 | int omap2_clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk) | 857 | int clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk) |
988 | { | 858 | { |
989 | bool hwsup = false; | ||
990 | |||
991 | /* | 859 | /* |
992 | * XXX Rewrite this code to maintain a list of enabled | 860 | * XXX Rewrite this code to maintain a list of enabled |
993 | * downstream clocks for debugging purposes? | 861 | * downstream clocks for debugging purposes? |
@@ -996,6 +864,9 @@ int omap2_clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk) | |||
996 | if (!clkdm || !clk) | 864 | if (!clkdm || !clk) |
997 | return -EINVAL; | 865 | return -EINVAL; |
998 | 866 | ||
867 | if (!arch_clkdm || !arch_clkdm->clkdm_clk_disable) | ||
868 | return -EINVAL; | ||
869 | |||
999 | #ifdef DEBUG | 870 | #ifdef DEBUG |
1000 | if (atomic_read(&clkdm->usecount) == 0) { | 871 | if (atomic_read(&clkdm->usecount) == 0) { |
1001 | WARN_ON(1); /* underflow */ | 872 | WARN_ON(1); /* underflow */ |
@@ -1011,31 +882,7 @@ int omap2_clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk) | |||
1011 | 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, |
1012 | clk->name); | 883 | clk->name); |
1013 | 884 | ||
1014 | if (cpu_is_omap24xx() || cpu_is_omap34xx()) { | 885 | arch_clkdm->clkdm_clk_disable(clkdm); |
1015 | |||
1016 | if (!clkdm->clktrctrl_mask) | ||
1017 | return 0; | ||
1018 | |||
1019 | hwsup = omap2_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs, | ||
1020 | clkdm->clktrctrl_mask); | ||
1021 | |||
1022 | } else if (cpu_is_omap44xx()) { | ||
1023 | |||
1024 | hwsup = omap4_cminst_is_clkdm_in_hwsup(clkdm->prcm_partition, | ||
1025 | clkdm->cm_inst, | ||
1026 | clkdm->clkdm_offs); | ||
1027 | |||
1028 | } | ||
1029 | |||
1030 | if (hwsup) { | ||
1031 | /* Disable HW transitions when we are changing deps */ | ||
1032 | _disable_hwsup(clkdm); | ||
1033 | _clkdm_del_autodeps(clkdm); | ||
1034 | _enable_hwsup(clkdm); | ||
1035 | } else { | ||
1036 | omap2_clkdm_sleep(clkdm); | ||
1037 | } | ||
1038 | |||
1039 | pwrdm_clkdm_state_switch(clkdm); | 886 | pwrdm_clkdm_state_switch(clkdm); |
1040 | 887 | ||
1041 | return 0; | 888 | return 0; |