From patchwork Sun Jul 24 16:52:37 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nishanth Menon X-Patchwork-Id: 1003102 Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by demeter2.kernel.org (8.14.4/8.14.4) with ESMTP id p6OGrJPf012502 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Sun, 24 Jul 2011 16:53:41 GMT Received: from canuck.infradead.org ([2001:4978:20e::1]) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1Ql1vM-0007d2-QY; Sun, 24 Jul 2011 16:53:05 +0000 Received: from localhost ([127.0.0.1] helo=canuck.infradead.org) by canuck.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1Ql1vM-0003XS-Ei; Sun, 24 Jul 2011 16:53:04 +0000 Received: from na3sys009aog120.obsmtp.com ([74.125.149.140]) by canuck.infradead.org with smtps (Exim 4.76 #1 (Red Hat Linux)) id 1Ql1vI-0003X9-8Q for linux-arm-kernel@lists.infradead.org; Sun, 24 Jul 2011 16:53:01 +0000 Received: from mail-gy0-f172.google.com ([209.85.160.172]) (using TLSv1) by na3sys009aob120.postini.com ([74.125.148.12]) with SMTP ID DSNKTixN6Kgv+JhTC8eiGHxFJXnC35HEcoct@postini.com; Sun, 24 Jul 2011 09:53:00 PDT Received: by mail-gy0-f172.google.com with SMTP id 5so2179706gyd.31 for ; Sun, 24 Jul 2011 09:52:56 -0700 (PDT) Received: by 10.236.181.134 with SMTP id l6mr5180351yhm.273.1311526376312; Sun, 24 Jul 2011 09:52:56 -0700 (PDT) Received: from localhost (cpe-76-184-231-243.tx.res.rr.com [76.184.231.243]) by mx.google.com with ESMTPS id j9sm1746707yhn.25.2011.07.24.09.52.50 (version=TLSv1/SSLv3 cipher=OTHER); Sun, 24 Jul 2011 09:52:54 -0700 (PDT) From: Nishanth Menon To: Kevin Subject: [PATCH 2/2 V2] OMAP3+: PM: SR: add suspend/resume handlers Date: Sun, 24 Jul 2011 11:52:37 -0500 Message-Id: <1311526357-7578-1-git-send-email-nm@ti.com> X-Mailer: git-send-email 1.7.4.1 In-Reply-To: <[PATCH 2/2] OMAP2+: PM: SR: add suspend/resume handlers> References: <[PATCH 2/2] OMAP2+: PM: SR: add suspend/resume handlers> X-CRM114-Version: 20090807-BlameThorstenAndJenny ( TRE 0.7.6 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20110724_125300_605785_15FB450E X-CRM114-Status: GOOD ( 16.62 ) X-Spam-Score: -2.3 (--) X-Spam-Report: SpamAssassin version 3.3.1 on canuck.infradead.org summary: Content analysis details: (-2.3 points) pts rule name description ---- ---------------------- -------------------------------------------------- -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at http://www.dnswl.org/, medium trust [74.125.149.140 listed in list.dnswl.org] Cc: Nishanth Menon , l-o , felipe , l-a , Colin X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter2.kernel.org [140.211.167.43]); Sun, 24 Jul 2011 16:53:41 +0000 (UTC) SmartReflex should be disabled while entering low power mode due to the following reasons: a) SmartReflex values are not defined for retention voltage. b) With SmartReflex enabled, if the CPU enters low power state, FSM will try to bump the voltage to current OPP's voltage for which it has entered low power state, causing power loss and potential unknown states for the SoC. Since we are sure to attempt entering the lowest possible power state during suspend operation, SmartReflex needs to be disabled for the voltage domains in suspend path before achieving auto retention voltage on the device. Traditionally, this has been done with interrupts disabled as part of the common code which handles the idle sequence. Instead, by using the fact that we have to disable SmartReflex for sure during suspend operations, we can opportunistically disable SmartReflex in device standard pm ops, instead of disabling it as part of the code which executes with interrupts disabled and slave CPU{s} shutdown. This allows the system to do other parallel activities(such as suspending other devices in the system using slave CPU{s}) and save the time required to achieve suspend and resume from suspended state as a sequential activity. However, by being opportunistic as described above, we also increase the likelihood of SmartReflex library access functions being invoked in parallel contexts *after* SmartReflex driver's suspend handler (during suspend operation) or *before* resume handler (during resume operation) have been invoked (Example: DVFS for dependent devices, cpufreq for MPU etc.). We prevent this by using a flag to reject the callers in the duration where SmartReflex has been disabled. Signed-off-by: Nishanth Menon --- V2: more verbose changelog :) and SIMPLE_DEV_PM_OPS V1: https://patchwork.kernel.org/patch/998312/ arch/arm/mach-omap2/smartreflex.c | 87 +++++++++++++++++++++++++++++++++++++ 1 files changed, 87 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c index 33a027f..8699682 100644 --- a/arch/arm/mach-omap2/smartreflex.c +++ b/arch/arm/mach-omap2/smartreflex.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -39,6 +40,7 @@ struct omap_sr { int ip_type; int nvalue_count; bool autocomp_active; + bool is_suspended; u32 clk_length; u32 err_weight; u32 err_minlimit; @@ -684,6 +686,11 @@ void omap_sr_enable(struct voltagedomain *voltdm) if (!sr->autocomp_active) return; + if (sr->is_suspended) { + dev_dbg(&sr->pdev->dev, "%s: in suspended state\n", __func__); + return; + } + if (!sr_class || !(sr_class->enable) || !(sr_class->configure)) { dev_warn(&sr->pdev->dev, "%s: smartreflex class driver not" "registered\n", __func__); @@ -717,6 +724,11 @@ void omap_sr_disable(struct voltagedomain *voltdm) if (!sr->autocomp_active) return; + if (sr->is_suspended) { + dev_dbg(&sr->pdev->dev, "%s: in suspended state\n", __func__); + return; + } + if (!sr_class || !(sr_class->disable)) { dev_warn(&sr->pdev->dev, "%s: smartreflex class driver not" "registered\n", __func__); @@ -750,6 +762,11 @@ void omap_sr_disable_reset_volt(struct voltagedomain *voltdm) if (!sr->autocomp_active) return; + if (sr->is_suspended) { + dev_dbg(&sr->pdev->dev, "%s: in suspended state\n", __func__); + return; + } + if (!sr_class || !(sr_class->disable)) { dev_warn(&sr->pdev->dev, "%s: smartreflex class driver not" "registered\n", __func__); @@ -808,6 +825,11 @@ static int omap_sr_autocomp_store(void *data, u64 val) return -EINVAL; } + if (sr_info->is_suspended) { + pr_warning("%s: in suspended state\n", __func__); + return -EBUSY; + } + if (!val) sr_stop_vddautocomp(sr_info); else @@ -998,10 +1020,75 @@ static int __devexit omap_sr_remove(struct platform_device *pdev) return 0; } +static int omap_sr_suspend(struct device *dev) +{ + struct omap_sr_data *pdata; + struct omap_sr *sr_info; + + pdata = dev_get_platdata(dev); + if (!pdata) { + dev_err(dev, "%s: platform data missing\n", __func__); + return -EINVAL; + } + + sr_info = _sr_lookup(pdata->voltdm); + if (IS_ERR(sr_info)) { + dev_warn(dev, "%s: omap_sr struct not found\n", __func__); + return -EINVAL; + } + + if (!sr_info->autocomp_active) + return 0; + + if (sr_info->is_suspended) + return 0; + + omap_sr_disable_reset_volt(pdata->voltdm); + sr_info->is_suspended = true; + /* Flag the same info to the other CPUs */ + smp_wmb(); + + return 0; +} + +static int omap_sr_resume(struct device *dev) +{ + struct omap_sr_data *pdata; + struct omap_sr *sr_info; + + pdata = dev_get_platdata(dev); + if (!pdata) { + dev_err(dev, "%s: platform data missing\n", __func__); + return -EINVAL; + } + + sr_info = _sr_lookup(pdata->voltdm); + if (IS_ERR(sr_info)) { + dev_warn(dev, "%s: omap_sr struct not found\n", __func__); + return -EINVAL; + } + + if (!sr_info->autocomp_active) + return 0; + + if (!sr_info->is_suspended) + return 0; + + sr_info->is_suspended = false; + /* Flag the same info to the other CPUs */ + smp_wmb(); + omap_sr_enable(pdata->voltdm); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(omap_sr_dev_pm_ops, omap_sr_suspend, omap_sr_resume); + static struct platform_driver smartreflex_driver = { .remove = omap_sr_remove, .driver = { .name = "smartreflex", + .pm = &omap_sr_dev_pm_ops, }, };