diff options
-rw-r--r-- | arch/arm/mach-omap2/cminst44xx.c | 25 | ||||
-rw-r--r-- | arch/arm/mach-omap2/cminst44xx.h | 1 | ||||
-rw-r--r-- | arch/arm/mach-omap2/omap_hwmod.c | 40 |
3 files changed, 66 insertions, 0 deletions
diff --git a/arch/arm/mach-omap2/cminst44xx.c b/arch/arm/mach-omap2/cminst44xx.c index 9033dd4937c1..0fe3f147f262 100644 --- a/arch/arm/mach-omap2/cminst44xx.c +++ b/arch/arm/mach-omap2/cminst44xx.c | |||
@@ -284,3 +284,28 @@ int omap4_cminst_wait_module_ready(u8 part, u16 inst, s16 cdoffs, | |||
284 | return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY; | 284 | return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY; |
285 | } | 285 | } |
286 | 286 | ||
287 | /** | ||
288 | * omap4_cminst_wait_module_idle - wait for a module to be in 'disabled' | ||
289 | * state | ||
290 | * @part: PRCM partition ID that the CM_CLKCTRL register exists in | ||
291 | * @inst: CM instance register offset (*_INST macro) | ||
292 | * @cdoffs: Clockdomain register offset (*_CDOFFS macro) | ||
293 | * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) | ||
294 | * | ||
295 | * Wait for the module IDLEST to be disabled. Some PRCM transition, | ||
296 | * like reset assertion or parent clock de-activation must wait the | ||
297 | * module to be fully disabled. | ||
298 | */ | ||
299 | int omap4_cminst_wait_module_idle(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs) | ||
300 | { | ||
301 | int i = 0; | ||
302 | |||
303 | if (!clkctrl_offs) | ||
304 | return 0; | ||
305 | |||
306 | omap_test_timeout((_clkctrl_idlest(part, inst, cdoffs, clkctrl_offs) == | ||
307 | CLKCTRL_IDLEST_DISABLED), | ||
308 | MAX_MODULE_READY_TIME, i); | ||
309 | |||
310 | return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY; | ||
311 | } | ||
diff --git a/arch/arm/mach-omap2/cminst44xx.h b/arch/arm/mach-omap2/cminst44xx.h index 8eba2ae87ad4..a98540081f97 100644 --- a/arch/arm/mach-omap2/cminst44xx.h +++ b/arch/arm/mach-omap2/cminst44xx.h | |||
@@ -18,6 +18,7 @@ extern void omap4_cminst_clkdm_force_sleep(u8 part, s16 inst, u16 cdoffs); | |||
18 | extern void omap4_cminst_clkdm_force_wakeup(u8 part, s16 inst, u16 cdoffs); | 18 | extern void omap4_cminst_clkdm_force_wakeup(u8 part, s16 inst, u16 cdoffs); |
19 | 19 | ||
20 | extern int omap4_cminst_wait_module_ready(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs); | 20 | extern int omap4_cminst_wait_module_ready(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs); |
21 | extern int omap4_cminst_wait_module_idle(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs); | ||
21 | 22 | ||
22 | /* | 23 | /* |
23 | * In an ideal world, we would not export these low-level functions, | 24 | * In an ideal world, we would not export these low-level functions, |
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 00241ea5bf09..d21f49b87646 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c | |||
@@ -1102,6 +1102,36 @@ static int _wait_target_ready(struct omap_hwmod *oh) | |||
1102 | } | 1102 | } |
1103 | 1103 | ||
1104 | /** | 1104 | /** |
1105 | * _wait_target_disable - wait for a module to be disabled | ||
1106 | * @oh: struct omap_hwmod * | ||
1107 | * | ||
1108 | * Wait for a module @oh to enter slave idle. Returns 0 if the module | ||
1109 | * does not have an IDLEST bit or if the module successfully enters | ||
1110 | * slave idle; otherwise, pass along the return value of the | ||
1111 | * appropriate *_cm*_wait_module_idle() function. | ||
1112 | */ | ||
1113 | static int _wait_target_disable(struct omap_hwmod *oh) | ||
1114 | { | ||
1115 | /* TODO: For now just handle OMAP4+ */ | ||
1116 | if (cpu_is_omap24xx() || cpu_is_omap34xx()) | ||
1117 | return 0; | ||
1118 | |||
1119 | if (!oh) | ||
1120 | return -EINVAL; | ||
1121 | |||
1122 | if (oh->_int_flags & _HWMOD_NO_MPU_PORT) | ||
1123 | return 0; | ||
1124 | |||
1125 | if (oh->flags & HWMOD_NO_IDLEST) | ||
1126 | return 0; | ||
1127 | |||
1128 | return omap4_cminst_wait_module_idle(oh->clkdm->prcm_partition, | ||
1129 | oh->clkdm->cm_inst, | ||
1130 | oh->clkdm->clkdm_offs, | ||
1131 | oh->prcm.omap4.clkctrl_offs); | ||
1132 | } | ||
1133 | |||
1134 | /** | ||
1105 | * _lookup_hardreset - fill register bit info for this hwmod/reset line | 1135 | * _lookup_hardreset - fill register bit info for this hwmod/reset line |
1106 | * @oh: struct omap_hwmod * | 1136 | * @oh: struct omap_hwmod * |
1107 | * @name: name of the reset line in the context of this hwmod | 1137 | * @name: name of the reset line in the context of this hwmod |
@@ -1410,6 +1440,8 @@ static int _enable(struct omap_hwmod *oh) | |||
1410 | */ | 1440 | */ |
1411 | static int _idle(struct omap_hwmod *oh) | 1441 | static int _idle(struct omap_hwmod *oh) |
1412 | { | 1442 | { |
1443 | int ret; | ||
1444 | |||
1413 | pr_debug("omap_hwmod: %s: idling\n", oh->name); | 1445 | pr_debug("omap_hwmod: %s: idling\n", oh->name); |
1414 | 1446 | ||
1415 | if (oh->_state != _HWMOD_STATE_ENABLED) { | 1447 | if (oh->_state != _HWMOD_STATE_ENABLED) { |
@@ -1422,6 +1454,10 @@ static int _idle(struct omap_hwmod *oh) | |||
1422 | _idle_sysc(oh); | 1454 | _idle_sysc(oh); |
1423 | _del_initiator_dep(oh, mpu_oh); | 1455 | _del_initiator_dep(oh, mpu_oh); |
1424 | _disable_clocks(oh); | 1456 | _disable_clocks(oh); |
1457 | ret = _wait_target_disable(oh); | ||
1458 | if (ret) | ||
1459 | pr_warn("omap_hwmod: %s: _wait_target_disable failed\n", | ||
1460 | oh->name); | ||
1425 | 1461 | ||
1426 | /* Mux pins for device idle if populated */ | 1462 | /* Mux pins for device idle if populated */ |
1427 | if (oh->mux && oh->mux->pads_dynamic) | 1463 | if (oh->mux && oh->mux->pads_dynamic) |
@@ -1514,6 +1550,10 @@ static int _shutdown(struct omap_hwmod *oh) | |||
1514 | _del_initiator_dep(oh, mpu_oh); | 1550 | _del_initiator_dep(oh, mpu_oh); |
1515 | /* XXX what about the other system initiators here? dma, dsp */ | 1551 | /* XXX what about the other system initiators here? dma, dsp */ |
1516 | _disable_clocks(oh); | 1552 | _disable_clocks(oh); |
1553 | ret = _wait_target_disable(oh); | ||
1554 | if (ret) | ||
1555 | pr_warn("omap_hwmod: %s: _wait_target_disable failed\n", | ||
1556 | oh->name); | ||
1517 | } | 1557 | } |
1518 | /* XXX Should this code also force-disable the optional clocks? */ | 1558 | /* XXX Should this code also force-disable the optional clocks? */ |
1519 | 1559 | ||