From patchwork Wed Apr 25 14:08:44 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tony Lindgren X-Patchwork-Id: 10363295 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 63EC1601D3 for ; Wed, 25 Apr 2018 14:08:54 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 545E0289F2 for ; Wed, 25 Apr 2018 14:08:54 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 48E1528A03; Wed, 25 Apr 2018 14:08:54 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00, MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CD408289F2 for ; Wed, 25 Apr 2018 14:08:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754131AbeDYOIx (ORCPT ); Wed, 25 Apr 2018 10:08:53 -0400 Received: from muru.com ([72.249.23.125]:38790 "EHLO muru.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753508AbeDYOIv (ORCPT ); Wed, 25 Apr 2018 10:08:51 -0400 Received: from hillo.muru.com (localhost [127.0.0.1]) by muru.com (Postfix) with ESMTP id 0D32A80B8; Wed, 25 Apr 2018 14:10:37 +0000 (UTC) From: Tony Lindgren To: Mark Brown Cc: linux-spi@vger.kernel.org, linux-omap@vger.kernel.org Subject: [PATCH 2/2] spi: omap2-mcspi: Idle hardware during suspend and resume Date: Wed, 25 Apr 2018 07:08:44 -0700 Message-Id: <20180425140844.127279-3-tony@atomide.com> X-Mailer: git-send-email 2.17.0 In-Reply-To: <20180425140844.127279-1-tony@atomide.com> References: <20180425140844.127279-1-tony@atomide.com> Sender: linux-spi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-spi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP We currently are calling mcspi suspend and resume without considering that mcspi might provide resources for other device driver such as regulators. This means resume can fail and will produce -EACCES if errors if anything calls mcspi functions between device_prepare() and device_complete(). To fix the issue, let's do the following changes: 1. Let's add checking for return values for pm_runtime_get calls, and call pm_runtime_put_noidle() on errors. Things still fail after this change, but at least we see something is wrong as we now see -EACCES errors on resume. 2. Let's use noirq level for suspend and resume as other drivers can still call SPI related functions on suspend and resume. This still won't fix the -EACCES issue, but gets us to something a bit saner. 3. Finally, let's modify suspend and resume to call to make sure the device is idled properly on suspend. We have device_prepare() call pm_runtime_get_noresume() that won't get released until in device_complete() when it calls pm_runtime_put(). So if SPI is still active on entering suspend, it will never get idled unless we add calls to pm_runtime_force_suspend() and resume. This also fixes the -EACCES errors on resume together with changes 1 and 2 above. And since we're already rewriting suspend resume functions, let's arrange the order of suspend and resume functions to be like they usually are with suspend first. Signed-off-by: Tony Lindgren --- drivers/spi/spi-omap2-mcspi.c | 54 +++++++++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -255,6 +255,7 @@ static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable) if (spi->controller_state) { int err = pm_runtime_get_sync(mcspi->dev); if (err < 0) { + pm_runtime_put_noidle(mcspi->dev); dev_err(mcspi->dev, "failed to get sync: %d\n", err); return; } @@ -1051,8 +1052,11 @@ static int omap2_mcspi_setup(struct spi_device *spi) } ret = pm_runtime_get_sync(mcspi->dev); - if (ret < 0) + if (ret < 0) { + pm_runtime_put_noidle(mcspi->dev); + return ret; + } ret = omap2_mcspi_setup_transfer(spi, NULL); pm_runtime_mark_last_busy(mcspi->dev); @@ -1270,8 +1274,11 @@ static int omap2_mcspi_master_setup(struct omap2_mcspi *mcspi) int ret = 0; ret = pm_runtime_get_sync(mcspi->dev); - if (ret < 0) + if (ret < 0) { + pm_runtime_put_noidle(mcspi->dev); + return ret; + } mcspi_write_reg(master, OMAP2_MCSPI_WAKEUPENABLE, OMAP2_MCSPI_WAKEUPENABLE_WKEN); @@ -1458,14 +1465,45 @@ static int omap2_mcspi_remove(struct platform_device *pdev) MODULE_ALIAS("platform:omap2_mcspi"); #ifdef CONFIG_SUSPEND -static int omap2_mcspi_resume(struct device *dev) +static int omap2_mcspi_suspend_noirq(struct device *dev) { - return pinctrl_pm_select_default_state(dev); + int error; + + /* + * Make sure device gets idled if other drivers call SPI + * functions between device_prepare() and device_complete() + */ + error = pm_runtime_force_suspend(dev); + if (error < 0) { + dev_err(dev, "%s: force suspend failed: %i\n", + __func__, error); + + return error; + } + + return pinctrl_pm_select_sleep_state(dev); } -static int omap2_mcspi_suspend(struct device *dev) +static int omap2_mcspi_resume_noirq(struct device *dev) { - return pinctrl_pm_select_sleep_state(dev); + struct spi_master *master = dev_get_drvdata(dev); + struct omap2_mcspi *mcspi = spi_master_get_devdata(master); + int error; + + error = pinctrl_pm_select_default_state(dev); + if (error) + dev_warn(mcspi->dev, "%s: failed to set pins: %i\n", + __func__, error); + + error = pm_runtime_force_resume(mcspi->dev); + if (error < 0) { + dev_warn(mcspi->dev, "%s: force resume failed: %i\n", + __func__, error); + + return error; + } + + return 0; } #else @@ -1474,8 +1512,8 @@ static int omap2_mcspi_suspend(struct device *dev) #endif static const struct dev_pm_ops omap2_mcspi_pm_ops = { - .resume = omap2_mcspi_resume, - .suspend = omap2_mcspi_suspend, + .suspend_noirq = omap2_mcspi_suspend_noirq, + .resume_noirq = omap2_mcspi_resume_noirq, .runtime_resume = omap_mcspi_runtime_resume, };