From patchwork Wed Oct 17 15:34:01 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Felipe Balbi X-Patchwork-Id: 1697901 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork1.kernel.org (Postfix) with ESMTP id E39243FCA5 for ; Mon, 5 Nov 2012 14:26:19 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1TVNZs-0002gG-WC; Mon, 05 Nov 2012 14:23:02 +0000 Received: from bear.ext.ti.com ([192.94.94.41]) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1TOVii-0007l4-6o for linux-arm-kernel@lists.infradead.org; Wed, 17 Oct 2012 15:39:46 +0000 Received: from dlelxv30.itg.ti.com ([172.17.2.17]) by bear.ext.ti.com (8.13.7/8.13.7) with ESMTP id q9HFdgoT004856; Wed, 17 Oct 2012 10:39:42 -0500 Received: from DFLE72.ent.ti.com (dfle72.ent.ti.com [128.247.5.109]) by dlelxv30.itg.ti.com (8.13.8/8.13.8) with ESMTP id q9HFdgwh001393; Wed, 17 Oct 2012 10:39:42 -0500 Received: from dlelxv22.itg.ti.com (172.17.1.197) by dfle72.ent.ti.com (128.247.5.109) with Microsoft SMTP Server id 14.1.323.3; Wed, 17 Oct 2012 10:39:41 -0500 Received: from localhost (h68-7.vpn.ti.com [172.24.68.7]) by dlelxv22.itg.ti.com (8.13.8/8.13.8) with ESMTP id q9HFdf5V021544; Wed, 17 Oct 2012 10:39:41 -0500 From: Felipe Balbi To: Tony Lindgren Subject: [RFC/NOT FOR MERGING 3/5] arm: omap: introduce other PM methods Date: Wed, 17 Oct 2012 18:34:01 +0300 Message-ID: <1350488043-5053-4-git-send-email-balbi@ti.com> X-Mailer: git-send-email 1.8.0.rc0 In-Reply-To: <1350488043-5053-1-git-send-email-balbi@ti.com> References: <1350488043-5053-1-git-send-email-balbi@ti.com> MIME-Version: 1.0 X-Bad-Reply: References and In-Reply-To but no 'Re:' in Subject. X-Spam-Note: CRM114 invocation failed X-Spam-Score: -7.3 (-------) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-7.3 points) pts rule name description ---- ---------------------- -------------------------------------------------- -5.0 RCVD_IN_DNSWL_HI RBL: Sender listed at http://www.dnswl.org/, high trust [192.94.94.41 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record -0.4 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] X-Mailman-Approved-At: Mon, 05 Nov 2012 09:14:22 -0500 Cc: Kevin Hilman , Paul Walmsley , Felipe Balbi , Santosh Shilimkar , Linux OMAP Mailing List , Linux ARM Kernel Mailing List X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org current omap_device PM implementation defines omap-specific *_noirq methods but uses the generic versions for all other PM methods. As it turns out, if a device decides to implement non-runtime PM callbacks, we might fall into a situation where the hwmod is still idled which will generate an abort exception when we try to access device's address space while clocks are still gated. In order to solve that, we implement all other methods taking into account that devices might not implement those, in which case we return early. Signed-off-by: Felipe Balbi --- notice here that it would be far better to avoid the code duplication and have another function (e.g. _od_generic_suspend/resume) which would receive pm_message_t and omap_device as arguments so it can decide what to do. That can be done on a later version, though. arch/arm/plat-omap/omap_device.c | 145 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 144 insertions(+), 1 deletion(-) diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c index cd84eac..60ce750 100644 --- a/arch/arm/plat-omap/omap_device.c +++ b/arch/arm/plat-omap/omap_device.c @@ -843,16 +843,159 @@ static int _od_resume_noirq(struct device *dev) return pm_generic_resume_noirq(dev); } + +static int _od_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct omap_device *od = to_omap_device(pdev); + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + int ret; + + if (!pm || !pm->suspend) + return 0; + + /* Don't attempt suspend on a driver that is not bound */ + if (od->_driver_status != BUS_NOTIFY_BOUND_DRIVER) + return 0; + + ret = pm_generic_suspend(dev); + if (ret) + return ret; + + if (!(od->flags & OMAP_DEVICE_NO_IDLE_ON_SUSPEND)) + omap_device_idle(pdev); + od->flags |= OMAP_DEVICE_SUSPENDED; + + return 0; +} + +static int _od_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct omap_device *od = to_omap_device(pdev); + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + if (!pm || !pm->resume) + return 0; + + if (od->flags & OMAP_DEVICE_SUSPENDED) { + od->flags &= ~OMAP_DEVICE_SUSPENDED; + + if (!(od->flags & OMAP_DEVICE_NO_IDLE_ON_SUSPEND)) + omap_device_enable(pdev); + } + + return pm_generic_resume(dev); +} + +static int _od_freeze(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct omap_device *od = to_omap_device(pdev); + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + int ret; + + if (!pm || !pm->freeze) + return 0; + + /* Don't attempt late suspend on a driver that is not bound */ + if (od->_driver_status != BUS_NOTIFY_BOUND_DRIVER) + return 0; + + ret = pm_generic_freeze(dev); + if (ret) + return ret; + + if (!(od->flags & OMAP_DEVICE_NO_IDLE_ON_SUSPEND)) + omap_device_idle(pdev); + od->flags |= OMAP_DEVICE_SUSPENDED; + + return 0; +} + +static int _od_thaw(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct omap_device *od = to_omap_device(pdev); + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + if (!pm || !pm->thaw) + return 0; + + if (od->flags & OMAP_DEVICE_SUSPENDED) { + od->flags &= ~OMAP_DEVICE_SUSPENDED; + + if (!(od->flags & OMAP_DEVICE_NO_IDLE_ON_SUSPEND)) + omap_device_enable(pdev); + } + + return pm_generic_thaw(dev); +} + +static int _od_poweroff(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct omap_device *od = to_omap_device(pdev); + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + int ret; + + if (!pm || !pm->poweroff) + return 0; + + /* Don't attempt late suspend on a driver that is not bound */ + if (od->_driver_status != BUS_NOTIFY_BOUND_DRIVER) + return 0; + + ret = pm_generic_poweroff(dev); + if (ret) + return ret; + + if (!(od->flags & OMAP_DEVICE_NO_IDLE_ON_SUSPEND)) + omap_device_idle(pdev); + od->flags |= OMAP_DEVICE_SUSPENDED; + + return 0; +} + +static int _od_restore(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct omap_device *od = to_omap_device(pdev); + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + if (!pm || !pm->restore) + return 0; + + if (od->flags & OMAP_DEVICE_SUSPENDED) { + od->flags &= ~OMAP_DEVICE_SUSPENDED; + + if (!(od->flags & OMAP_DEVICE_NO_IDLE_ON_SUSPEND)) + omap_device_enable(pdev); + } + + return pm_generic_restore(dev); +} #else #define _od_suspend_noirq NULL #define _od_resume_noirq NULL +#define _od_suspend NULL +#define _od_resume NULL +#define _od_freeze NULL +#define _od_thaw NULL +#define _od_poweroff NULL +#define _od_restore NULL #endif struct dev_pm_domain omap_device_pm_domain = { .ops = { SET_RUNTIME_PM_OPS(_od_runtime_suspend, _od_runtime_resume, _od_runtime_idle) - USE_PLATFORM_PM_SLEEP_OPS + .suspend = _od_suspend, + .resume = _od_resume, + .freeze = _od_freeze, + .thaw = _od_thaw, + .poweroff = _od_poweroff, + .restore = _od_restore, .suspend_noirq = _od_suspend_noirq, .resume_noirq = _od_resume_noirq, }