aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/omap_device.c
diff options
context:
space:
mode:
authorNishanth Menon <nm@ti.com>2013-11-14 12:05:16 -0500
committerTony Lindgren <tony@atomide.com>2013-11-15 10:38:14 -0500
commit3522bf7bfa248b99eafa2f4872190699a808c7d9 (patch)
tree70b5fd1efe5d602d69be6d85ec8c59eaa73161f7 /arch/arm/mach-omap2/omap_device.c
parent31844434239e30cc7419510921929194be41e637 (diff)
ARM: OMAP2+: omap_device: maintain sane runtime pm status around suspend/resume
OMAP device hooks around suspend|resume_noirq ensures that hwmod devices are forced to idle using omap_device_idle/enable as part of the last stage of suspend activity. For a device such as i2c who uses autosuspend, it is possible to enter the suspend path with dev->power.runtime_status = RPM_ACTIVE. As part of the suspend flow, the generic runtime logic would increment it's dev->power.disable_depth to 1. This should prevent further pm_runtime_get_sync from succeeding once the runtime_status has been set to RPM_SUSPENDED. Now, as part of the suspend_noirq handler in omap_device, we force the following: if the device status is !suspended, we force the device to idle using omap_device_idle (clocks are cut etc..). This ensures that from a hardware perspective, the device is "suspended". However, runtime_status is left to be active. *if* an operation is attempted after this point to pm_runtime_get_sync, runtime framework depends on runtime_status to indicate accurately the device status, and since it sees it to be ACTIVE, it assumes the module is functional and returns a non-error value. As a result the user will see pm_runtime_get succeed, however a register access will crash due to the lack of clocks. To prevent this from happening, we should ensure that runtime_status exactly indicates the device status. As a result of this change any further calls to pm_runtime_get* would return -EACCES (since disable_depth is 1). On resume, we restore the clocks and runtime status exactly as we suspended with. These operations are not expected to fail as we update the states after the core runtime framework has suspended itself and restore before the core runtime framework has resumed. Cc: stable@vger.kernel.org # v3.4+ Reported-by: J Keerthy <j-keerthy@ti.com> Signed-off-by: Nishanth Menon <nm@ti.com> Acked-by: Rajendra Nayak <rnayak@ti.com> Acked-by: Kevin Hilman <khilman@linaro.org> Reviewed-by: Felipe Balbi <balbi@ti.com> Signed-off-by: Tony Lindgren <tony@atomide.com>
Diffstat (limited to 'arch/arm/mach-omap2/omap_device.c')
-rw-r--r--arch/arm/mach-omap2/omap_device.c13
1 files changed, 11 insertions, 2 deletions
diff --git a/arch/arm/mach-omap2/omap_device.c b/arch/arm/mach-omap2/omap_device.c
index b69dd9abb50a..53f0735817bb 100644
--- a/arch/arm/mach-omap2/omap_device.c
+++ b/arch/arm/mach-omap2/omap_device.c
@@ -621,6 +621,7 @@ static int _od_suspend_noirq(struct device *dev)
621 621
622 if (!ret && !pm_runtime_status_suspended(dev)) { 622 if (!ret && !pm_runtime_status_suspended(dev)) {
623 if (pm_generic_runtime_suspend(dev) == 0) { 623 if (pm_generic_runtime_suspend(dev) == 0) {
624 pm_runtime_set_suspended(dev);
624 omap_device_idle(pdev); 625 omap_device_idle(pdev);
625 od->flags |= OMAP_DEVICE_SUSPENDED; 626 od->flags |= OMAP_DEVICE_SUSPENDED;
626 } 627 }
@@ -634,10 +635,18 @@ static int _od_resume_noirq(struct device *dev)
634 struct platform_device *pdev = to_platform_device(dev); 635 struct platform_device *pdev = to_platform_device(dev);
635 struct omap_device *od = to_omap_device(pdev); 636 struct omap_device *od = to_omap_device(pdev);
636 637
637 if ((od->flags & OMAP_DEVICE_SUSPENDED) && 638 if (od->flags & OMAP_DEVICE_SUSPENDED) {
638 !pm_runtime_status_suspended(dev)) {
639 od->flags &= ~OMAP_DEVICE_SUSPENDED; 639 od->flags &= ~OMAP_DEVICE_SUSPENDED;
640 omap_device_enable(pdev); 640 omap_device_enable(pdev);
641 /*
642 * XXX: we run before core runtime pm has resumed itself. At
643 * this point in time, we just restore the runtime pm state and
644 * considering symmetric operations in resume, we donot expect
645 * to fail. If we failed, something changed in core runtime_pm
646 * framework OR some device driver messed things up, hence, WARN
647 */
648 WARN(pm_runtime_set_active(dev),
649 "Could not set %s runtime state active\n", dev_name(dev));
641 pm_generic_runtime_resume(dev); 650 pm_generic_runtime_resume(dev);
642 } 651 }
643 652