The patch spi: lpspi: enable runtime pm for lpspi has been applied to the spi tree at https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted. You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed. If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced. Please add any relevant lists and maintainers to the CCs when replying to this mail. Thanks, Mark >From 944c01a889d97dc08e1b71f4ed868f4023fd6034 Mon Sep 17 00:00:00 2001 From: Han Xu <han.xu@xxxxxxx> Date: Wed, 6 Mar 2019 06:30:39 +0000 Subject: [PATCH] spi: lpspi: enable runtime pm for lpspi Enable the runtime power management for lpspi module. Do some adaptation work from kernel 4.9 to 4.14. Signed-off-by: Clark Wang <xiaoning.wang@xxxxxxx> Signed-off-by: Han Xu <han.xu@xxxxxxx> Reviewed-by: Frank Li <frank.li@xxxxxxx> Signed-off-by: Mark Brown <broonie@xxxxxxxxxx> --- drivers/spi/spi-fsl-lpspi.c | 117 ++++++++++++++++++++++++++++-------- 1 file changed, 92 insertions(+), 25 deletions(-) diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index f363c000d24a..84dcb9e176b8 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -16,7 +16,9 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/of_device.h> +#include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/slab.h> #include <linux/spi/spi.h> #include <linux/spi/spi_bitbang.h> @@ -24,6 +26,8 @@ #define DRIVER_NAME "fsl_lpspi" +#define FSL_LPSPI_RPM_TIMEOUT 50 /* 50ms */ + /* i.MX7ULP LPSPI registers */ #define IMX7ULP_VERID 0x0 #define IMX7ULP_PARAM 0x4 @@ -154,13 +158,9 @@ static int lpspi_prepare_xfer_hardware(struct spi_controller *controller) spi_controller_get_devdata(controller); int ret; - ret = clk_prepare_enable(fsl_lpspi->clk_ipg); - if (ret) - return ret; - - ret = clk_prepare_enable(fsl_lpspi->clk_per); - if (ret) { - clk_disable_unprepare(fsl_lpspi->clk_ipg); + ret = pm_runtime_get_sync(fsl_lpspi->dev); + if (ret < 0) { + dev_err(fsl_lpspi->dev, "failed to enable clock\n"); return ret; } @@ -172,8 +172,8 @@ static int lpspi_unprepare_xfer_hardware(struct spi_controller *controller) struct fsl_lpspi_data *fsl_lpspi = spi_controller_get_devdata(controller); - clk_disable_unprepare(fsl_lpspi->clk_ipg); - clk_disable_unprepare(fsl_lpspi->clk_per); + pm_runtime_mark_last_busy(fsl_lpspi->dev); + pm_runtime_put_autosuspend(fsl_lpspi->dev); return 0; } @@ -480,6 +480,45 @@ static irqreturn_t fsl_lpspi_isr(int irq, void *dev_id) return IRQ_NONE; } +int fsl_lpspi_runtime_resume(struct device *dev) +{ + struct fsl_lpspi_data *fsl_lpspi = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(fsl_lpspi->clk_per); + if (ret) + return ret; + + ret = clk_prepare_enable(fsl_lpspi->clk_ipg); + if (ret) { + clk_disable_unprepare(fsl_lpspi->clk_per); + return ret; + } + + return 0; +} + +int fsl_lpspi_runtime_suspend(struct device *dev) +{ + struct fsl_lpspi_data *fsl_lpspi = dev_get_drvdata(dev); + + clk_disable_unprepare(fsl_lpspi->clk_per); + clk_disable_unprepare(fsl_lpspi->clk_ipg); + + return 0; +} + +static int fsl_lpspi_init_rpm(struct fsl_lpspi_data *fsl_lpspi) +{ + struct device *dev = fsl_lpspi->dev; + + pm_runtime_enable(dev); + pm_runtime_set_autosuspend_delay(dev, FSL_LPSPI_RPM_TIMEOUT); + pm_runtime_use_autosuspend(dev); + + return 0; +} + static int fsl_lpspi_probe(struct platform_device *pdev) { struct fsl_lpspi_data *fsl_lpspi; @@ -505,6 +544,7 @@ static int fsl_lpspi_probe(struct platform_device *pdev) fsl_lpspi = spi_controller_get_devdata(controller); fsl_lpspi->dev = &pdev->dev; + dev_set_drvdata(&pdev->dev, fsl_lpspi); fsl_lpspi->is_slave = of_property_read_bool((&pdev->dev)->of_node, "spi-slave"); @@ -551,28 +591,21 @@ static int fsl_lpspi_probe(struct platform_device *pdev) goto out_controller_put; } - ret = clk_prepare_enable(fsl_lpspi->clk_ipg); - if (ret) { - dev_err(&pdev->dev, - "can't enable lpspi ipg clock, ret=%d\n", ret); + /* enable the clock */ + ret = fsl_lpspi_init_rpm(fsl_lpspi); + if (ret) goto out_controller_put; - } - ret = clk_prepare_enable(fsl_lpspi->clk_per); - if (ret) { - dev_err(&pdev->dev, - "can't enable lpspi per clock, ret=%d\n", ret); - clk_disable_unprepare(fsl_lpspi->clk_ipg); - goto out_controller_put; + ret = pm_runtime_get_sync(fsl_lpspi->dev); + if (ret < 0) { + dev_err(fsl_lpspi->dev, "failed to enable clock\n"); + return ret; } temp = readl(fsl_lpspi->base + IMX7ULP_PARAM); fsl_lpspi->txfifosize = 1 << (temp & 0x0f); fsl_lpspi->rxfifosize = 1 << ((temp >> 8) & 0x0f); - clk_disable_unprepare(fsl_lpspi->clk_per); - clk_disable_unprepare(fsl_lpspi->clk_ipg); - ret = devm_spi_register_controller(&pdev->dev, controller); if (ret < 0) { dev_err(&pdev->dev, "spi_register_controller error.\n"); @@ -593,16 +626,50 @@ static int fsl_lpspi_remove(struct platform_device *pdev) struct fsl_lpspi_data *fsl_lpspi = spi_controller_get_devdata(controller); - clk_disable_unprepare(fsl_lpspi->clk_per); - clk_disable_unprepare(fsl_lpspi->clk_ipg); + pm_runtime_disable(fsl_lpspi->dev); + + spi_master_put(controller); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int fsl_lpspi_suspend(struct device *dev) +{ + int ret; + + pinctrl_pm_select_sleep_state(dev); + ret = pm_runtime_force_suspend(dev); + return ret; +} + +static int fsl_lpspi_resume(struct device *dev) +{ + int ret; + + ret = pm_runtime_force_resume(dev); + if (ret) { + dev_err(dev, "Error in resume: %d\n", ret); + return ret; + } + + pinctrl_pm_select_default_state(dev); return 0; } +#endif /* CONFIG_PM_SLEEP */ + +static const struct dev_pm_ops fsl_lpspi_pm_ops = { + SET_RUNTIME_PM_OPS(fsl_lpspi_runtime_suspend, + fsl_lpspi_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(fsl_lpspi_suspend, fsl_lpspi_resume) +}; static struct platform_driver fsl_lpspi_driver = { .driver = { .name = DRIVER_NAME, .of_match_table = fsl_lpspi_dt_ids, + .pm = &fsl_lpspi_pm_ops, }, .probe = fsl_lpspi_probe, .remove = fsl_lpspi_remove, -- 2.20.1