diff options
author | Patrice Chotard <patrice.chotard@st.com> | 2020-04-17 14:12:41 +0200 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2020-04-17 14:21:00 +0100 |
commit | 9d282c17b023a97516a63255ce7f7ee65c39bec1 (patch) | |
tree | 7b15947fda91acb0c7a11e28e7dc6da41f8a2789 | |
parent | 5ba8e3e75361c68c1120080d7ffe8839bf11c06d (diff) | |
download | lwn-9d282c17b023a97516a63255ce7f7ee65c39bec1.tar.gz lwn-9d282c17b023a97516a63255ce7f7ee65c39bec1.zip |
spi: stm32-qspi: Add pm_runtime support
By default, STM32_AUTOSUSPEND_DELAY is set to -1 which has for
effect to prevent runtime suspends.
Runtime suspends can be activated by setting autosuspend_delay_ms using
sysfs entry :
echo {delay_in_ms} > /sys/devices/platform/soc/58003000.spi/power/autosusp
end_delay_ms)
Signed-off-by: Christophe Kerello <christophe.kerello@st.com>
Signed-off-by: Patrice Chotard <patrice.chotard@st.com>
Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
Link: https://lore.kernel.org/r/20200417121241.6473-1-patrice.chotard@st.com
Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r-- | drivers/spi/spi-stm32-qspi.c | 57 |
1 files changed, 53 insertions, 4 deletions
diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c index d066f5144c3e..2f2ea2c42d6e 100644 --- a/drivers/spi/spi-stm32-qspi.c +++ b/drivers/spi/spi-stm32-qspi.c @@ -16,6 +16,7 @@ #include <linux/of.h> #include <linux/of_device.h> #include <linux/pinctrl/consumer.h> +#include <linux/pm_runtime.h> #include <linux/platform_device.h> #include <linux/reset.h> #include <linux/sizes.h> @@ -87,6 +88,7 @@ #define STM32_BUSY_TIMEOUT_US 100000 #define STM32_ABT_TIMEOUT_US 100000 #define STM32_COMP_TIMEOUT_MS 1000 +#define STM32_AUTOSUSPEND_DELAY -1 struct stm32_qspi_flash { struct stm32_qspi *qspi; @@ -431,10 +433,17 @@ static int stm32_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) struct stm32_qspi *qspi = spi_controller_get_devdata(mem->spi->master); int ret; + ret = pm_runtime_get_sync(qspi->dev); + if (ret < 0) + return ret; + mutex_lock(&qspi->lock); ret = stm32_qspi_send(mem, op); mutex_unlock(&qspi->lock); + pm_runtime_mark_last_busy(qspi->dev); + pm_runtime_put_autosuspend(qspi->dev); + return ret; } @@ -444,6 +453,7 @@ static int stm32_qspi_setup(struct spi_device *spi) struct stm32_qspi *qspi = spi_controller_get_devdata(ctrl); struct stm32_qspi_flash *flash; u32 presc; + int ret; if (ctrl->busy) return -EBUSY; @@ -451,6 +461,10 @@ static int stm32_qspi_setup(struct spi_device *spi) if (!spi->max_speed_hz) return -EINVAL; + ret = pm_runtime_get_sync(qspi->dev); + if (ret < 0) + return ret; + presc = DIV_ROUND_UP(qspi->clk_rate, spi->max_speed_hz) - 1; flash = &qspi->flash[spi->chip_select]; @@ -467,6 +481,9 @@ static int stm32_qspi_setup(struct spi_device *spi) writel_relaxed(qspi->dcr_reg, qspi->io_base + QSPI_DCR); mutex_unlock(&qspi->lock); + pm_runtime_mark_last_busy(qspi->dev); + pm_runtime_put_autosuspend(qspi->dev); + return 0; } @@ -643,9 +660,20 @@ static int stm32_qspi_probe(struct platform_device *pdev) ctrl->num_chipselect = STM32_QSPI_MAX_NORCHIP; ctrl->dev.of_node = dev->of_node; + pm_runtime_set_autosuspend_delay(dev, STM32_AUTOSUSPEND_DELAY); + pm_runtime_use_autosuspend(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + pm_runtime_get_noresume(dev); + ret = devm_spi_register_master(dev, ctrl); - if (!ret) - return 0; + if (ret) + goto err_qspi_release; + + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + + return 0; err_qspi_release: stm32_qspi_release(qspi); @@ -660,14 +688,28 @@ static int stm32_qspi_remove(struct platform_device *pdev) struct stm32_qspi *qspi = platform_get_drvdata(pdev); stm32_qspi_release(qspi); + return 0; } -static int __maybe_unused stm32_qspi_suspend(struct device *dev) +static int __maybe_unused stm32_qspi_runtime_suspend(struct device *dev) { struct stm32_qspi *qspi = dev_get_drvdata(dev); clk_disable_unprepare(qspi->clk); + + return 0; +} + +static int __maybe_unused stm32_qspi_runtime_resume(struct device *dev) +{ + struct stm32_qspi *qspi = dev_get_drvdata(dev); + + return clk_prepare_enable(qspi->clk); +} + +static int __maybe_unused stm32_qspi_suspend(struct device *dev) +{ pinctrl_pm_select_sleep_state(dev); return 0; @@ -683,10 +725,17 @@ static int __maybe_unused stm32_qspi_resume(struct device *dev) writel_relaxed(qspi->cr_reg, qspi->io_base + QSPI_CR); writel_relaxed(qspi->dcr_reg, qspi->io_base + QSPI_DCR); + pm_runtime_mark_last_busy(qspi->dev); + pm_runtime_put_autosuspend(qspi->dev); + return 0; } -static SIMPLE_DEV_PM_OPS(stm32_qspi_pm_ops, stm32_qspi_suspend, stm32_qspi_resume); +static const struct dev_pm_ops stm32_qspi_pm_ops = { + SET_RUNTIME_PM_OPS(stm32_qspi_runtime_suspend, + stm32_qspi_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(stm32_qspi_suspend, stm32_qspi_resume) +}; static const struct of_device_id stm32_qspi_match[] = { {.compatible = "st,stm32f469-qspi"}, |