From patchwork Wed Sep 27 15:39:22 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= X-Patchwork-Id: 9974313 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 88E75602D6 for ; Wed, 27 Sep 2017 15:39:27 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7987C2921F for ; Wed, 27 Sep 2017 15:39:27 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 6E5A129229; Wed, 27 Sep 2017 15:39:27 +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=-6.9 required=2.0 tests=BAYES_00,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 B7CEC2921F for ; Wed, 27 Sep 2017 15:39:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752187AbdI0Pj0 (ORCPT ); Wed, 27 Sep 2017 11:39:26 -0400 Received: from metis.ext.4.pengutronix.de ([92.198.50.35]:36915 "EHLO metis.ext.4.pengutronix.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752188AbdI0PjZ (ORCPT ); Wed, 27 Sep 2017 11:39:25 -0400 Received: from dude.hi.pengutronix.de ([2001:67c:670:100:1d::7]) by metis.ext.pengutronix.de with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.84_2) (envelope-from ) id 1dxEQm-00012m-AG; Wed, 27 Sep 2017 17:39:24 +0200 Received: from ukl by dude.hi.pengutronix.de with local (Exim 4.89) (envelope-from ) id 1dxEQl-00045t-Vr; Wed, 27 Sep 2017 17:39:23 +0200 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= To: Mark Brown Cc: kernel@pengutronix.de, linux-spi@vger.kernel.org Subject: [PATCH v2] spi: mxs: implement runtime pm Date: Wed, 27 Sep 2017 17:39:22 +0200 Message-Id: <20170927153922.15321-1-u.kleine-koenig@pengutronix.de> X-Mailer: git-send-email 2.11.0 MIME-Version: 1.0 X-SA-Exim-Connect-IP: 2001:67c:670:100:1d::7 X-SA-Exim-Mail-From: ukl@pengutronix.de X-SA-Exim-Scanned: No (on metis.ext.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: linux-spi@vger.kernel.org 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 This is a straight forward addition of runtime and system sleep pm operations that handle clk and pinctrl (for runtime pm) and spi_master_{suspend,resume} (for system sleep). Signed-off-by: Uwe Kleine-König --- Changes since v1 (Message-Id: 20170426201028.19217-1-u.kleine-koenig@pengutronix.de): - Make use of auto_runtime_pm - drop a stray dev_info() drivers/spi/spi-mxs.c | 120 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 110 insertions(+), 10 deletions(-) diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c index 5b0e9a3e83f6..3d216b950b41 100644 --- a/drivers/spi/spi-mxs.c +++ b/drivers/spi/spi-mxs.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -442,6 +443,85 @@ static int mxs_spi_transfer_one(struct spi_master *master, return status; } +static int mxs_spi_runtime_suspend(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + struct mxs_spi *spi = spi_master_get_devdata(master); + struct mxs_ssp *ssp = &spi->ssp; + int ret; + + clk_disable_unprepare(ssp->clk); + + ret = pinctrl_pm_select_idle_state(dev); + if (ret) { + int ret2 = clk_prepare_enable(ssp->clk); + + if (ret2) + dev_warn(dev, "Failed to reenable clock after failing pinctrl request (pinctrl: %d, clk: %d)\n", + ret, ret2); + } + + return ret; +} + +static int mxs_spi_runtime_resume(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + struct mxs_spi *spi = spi_master_get_devdata(master); + struct mxs_ssp *ssp = &spi->ssp; + int ret; + + ret = pinctrl_pm_select_default_state(dev); + if (ret) + return ret; + + ret = clk_prepare_enable(ssp->clk); + if (ret) + pinctrl_pm_select_idle_state(dev); + + return ret; +} + +static int __maybe_unused mxs_spi_suspend(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + int ret; + + ret = spi_master_suspend(master); + if (ret) + return ret; + + if (!pm_runtime_suspended(dev)) + return mxs_spi_runtime_suspend(dev); + else + return 0; +} + +static int __maybe_unused mxs_spi_resume(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + int ret; + + if (!pm_runtime_suspended(dev)) + ret = mxs_spi_runtime_resume(dev); + else + ret = 0; + if (ret) + return ret; + + ret = spi_master_resume(master); + if (ret < 0 && !pm_runtime_suspended(dev)) + mxs_spi_runtime_suspend(dev); + + return ret; +} + +static const struct dev_pm_ops mxs_spi_pm = { + SET_RUNTIME_PM_OPS(mxs_spi_runtime_suspend, + mxs_spi_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(mxs_spi_suspend, mxs_spi_resume) +}; + static const struct of_device_id mxs_spi_dt_ids[] = { { .compatible = "fsl,imx23-spi", .data = (void *) IMX23_SSP, }, { .compatible = "fsl,imx28-spi", .data = (void *) IMX28_SSP, }, @@ -493,12 +573,15 @@ static int mxs_spi_probe(struct platform_device *pdev) if (!master) return -ENOMEM; + platform_set_drvdata(pdev, master); + master->transfer_one_message = mxs_spi_transfer_one; master->bits_per_word_mask = SPI_BPW_MASK(8); master->mode_bits = SPI_CPOL | SPI_CPHA; master->num_chipselect = 3; master->dev.of_node = np; master->flags = SPI_MASTER_HALF_DUPLEX; + master->auto_runtime_pm = true; spi = spi_master_get_devdata(master); ssp = &spi->ssp; @@ -521,28 +604,41 @@ static int mxs_spi_probe(struct platform_device *pdev) goto out_master_free; } - ret = clk_prepare_enable(ssp->clk); - if (ret) - goto out_dma_release; + pm_runtime_enable(ssp->dev); + if (!pm_runtime_enabled(ssp->dev)) { + ret = mxs_spi_runtime_resume(ssp->dev); + if (ret < 0) { + dev_err(ssp->dev, "runtime resume failed\n"); + goto out_dma_release; + } + } + + ret = pm_runtime_get_sync(ssp->dev); + if (ret < 0) { + dev_err(ssp->dev, "runtime_get_sync failed\n"); + goto out_pm_runtime_disable; + } clk_set_rate(ssp->clk, clk_freq); ret = stmp_reset_block(ssp->base); if (ret) - goto out_disable_clk; - - platform_set_drvdata(pdev, master); + goto out_pm_runtime_put; ret = devm_spi_register_master(&pdev->dev, master); if (ret) { dev_err(&pdev->dev, "Cannot register SPI master, %d\n", ret); - goto out_disable_clk; + goto out_pm_runtime_put; } + pm_runtime_put(ssp->dev); + return 0; -out_disable_clk: - clk_disable_unprepare(ssp->clk); +out_pm_runtime_put: + pm_runtime_put(ssp->dev); +out_pm_runtime_disable: + pm_runtime_disable(ssp->dev); out_dma_release: dma_release_channel(ssp->dmach); out_master_free: @@ -560,7 +656,10 @@ static int mxs_spi_remove(struct platform_device *pdev) spi = spi_master_get_devdata(master); ssp = &spi->ssp; - clk_disable_unprepare(ssp->clk); + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + mxs_spi_runtime_suspend(&pdev->dev); + dma_release_channel(ssp->dmach); return 0; @@ -572,6 +671,7 @@ static struct platform_driver mxs_spi_driver = { .driver = { .name = DRIVER_NAME, .of_match_table = mxs_spi_dt_ids, + .pm = &mxs_spi_pm, }, };