#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <linux/spi/spi-mem.h>
/* QSPI register offsets */
if (op->addr.val + op->data.nbytes > aq->mmap_size)
return -ENOTSUPP;
+ err = pm_runtime_resume_and_get(&aq->pdev->dev);
+ if (err < 0)
+ return err;
+
err = atmel_qspi_set_cfg(aq, op, &offset);
if (err)
- return err;
+ goto pm_runtime_put;
/* Skip to the final steps if there is no data */
if (op->data.nbytes) {
/* Poll INSTRuction End status */
sr = atmel_qspi_read(aq, QSPI_SR);
if ((sr & QSPI_SR_CMD_COMPLETED) == QSPI_SR_CMD_COMPLETED)
- return err;
+ goto pm_runtime_put;
/* Wait for INSTRuction End interrupt */
reinit_completion(&aq->cmd_completion);
err = -ETIMEDOUT;
atmel_qspi_write(QSPI_SR_CMD_COMPLETED, aq, QSPI_IDR);
+pm_runtime_put:
+ pm_runtime_mark_last_busy(&aq->pdev->dev);
+ pm_runtime_put_autosuspend(&aq->pdev->dev);
return err;
}
struct atmel_qspi *aq = spi_controller_get_devdata(ctrl);
unsigned long src_rate;
u32 scbr;
+ int ret;
if (ctrl->busy)
return -EBUSY;
if (scbr > 0)
scbr--;
+ ret = pm_runtime_resume_and_get(ctrl->dev.parent);
+ if (ret < 0)
+ return ret;
+
aq->scr = QSPI_SCR_SCBR(scbr);
atmel_qspi_write(aq->scr, aq, QSPI_SCR);
+ pm_runtime_mark_last_busy(ctrl->dev.parent);
+ pm_runtime_put_autosuspend(ctrl->dev.parent);
+
return 0;
}
if (err)
goto disable_qspick;
+ pm_runtime_set_autosuspend_delay(&pdev->dev, 500);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_get_noresume(&pdev->dev);
+
atmel_qspi_init(aq);
err = spi_register_controller(ctrl);
- if (err)
+ if (err) {
+ pm_runtime_put_noidle(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
goto disable_qspick;
+ }
+ pm_runtime_mark_last_busy(&pdev->dev);
+ pm_runtime_put_autosuspend(&pdev->dev);
return 0;
{
struct spi_controller *ctrl = platform_get_drvdata(pdev);
struct atmel_qspi *aq = spi_controller_get_devdata(ctrl);
+ int ret;
+
+ ret = pm_runtime_resume_and_get(&pdev->dev);
+ if (ret < 0)
+ return ret;
spi_unregister_controller(ctrl);
atmel_qspi_write(QSPI_CR_QSPIDIS, aq, QSPI_CR);
+
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_put_noidle(&pdev->dev);
+
clk_disable_unprepare(aq->qspick);
clk_disable_unprepare(aq->pclk);
return 0;
{
struct spi_controller *ctrl = dev_get_drvdata(dev);
struct atmel_qspi *aq = spi_controller_get_devdata(ctrl);
+ int ret;
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
+ return ret;
atmel_qspi_write(QSPI_CR_QSPIDIS, aq, QSPI_CR);
- clk_disable_unprepare(aq->qspick);
- clk_disable_unprepare(aq->pclk);
+
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_force_suspend(dev);
+
+ clk_unprepare(aq->qspick);
+ clk_unprepare(aq->pclk);
return 0;
}
{
struct spi_controller *ctrl = dev_get_drvdata(dev);
struct atmel_qspi *aq = spi_controller_get_devdata(ctrl);
+ int ret;
- clk_prepare_enable(aq->pclk);
- clk_prepare_enable(aq->qspick);
+ clk_prepare(aq->pclk);
+ clk_prepare(aq->qspick);
+
+ ret = pm_runtime_force_resume(dev);
+ if (ret < 0)
+ return ret;
atmel_qspi_init(aq);
atmel_qspi_write(aq->scr, aq, QSPI_SCR);
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+
+ return 0;
+}
+
+static int __maybe_unused atmel_qspi_runtime_suspend(struct device *dev)
+{
+ struct spi_controller *ctrl = dev_get_drvdata(dev);
+ struct atmel_qspi *aq = spi_controller_get_devdata(ctrl);
+
+ clk_disable(aq->qspick);
+ clk_disable(aq->pclk);
+
return 0;
}
-static SIMPLE_DEV_PM_OPS(atmel_qspi_pm_ops, atmel_qspi_suspend,
- atmel_qspi_resume);
+static int __maybe_unused atmel_qspi_runtime_resume(struct device *dev)
+{
+ struct spi_controller *ctrl = dev_get_drvdata(dev);
+ struct atmel_qspi *aq = spi_controller_get_devdata(ctrl);
+ int ret;
+
+ ret = clk_enable(aq->pclk);
+ if (ret)
+ return ret;
+
+ return clk_enable(aq->qspick);
+}
+
+static const struct dev_pm_ops __maybe_unused atmel_qspi_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(atmel_qspi_suspend, atmel_qspi_resume)
+ SET_RUNTIME_PM_OPS(atmel_qspi_runtime_suspend,
+ atmel_qspi_runtime_resume, NULL)
+};
static const struct atmel_qspi_caps atmel_sama5d2_qspi_caps = {};