Enable runtime power management in the rz-dmac driver by adding suspend and resume callbacks. This ensures the driver can correctly assert and deassert the reset control and manage power state transitions during suspend and resume. Adding runtime PM support allows the DMA controller to reduce power consumption when idle and maintain correct operation across system sleep states, addressing the previous lack of dynamic power management in the driver. Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@xxxxxxxxxxxxxx> --- v1->v2: - No chanes drivers/dma/sh/rz-dmac.c | 57 +++++++++++++++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/drivers/dma/sh/rz-dmac.c b/drivers/dma/sh/rz-dmac.c index 1f687b08d6b86..2f06bdb7ce3be 100644 --- a/drivers/dma/sh/rz-dmac.c +++ b/drivers/dma/sh/rz-dmac.c @@ -437,6 +437,17 @@ static int rz_dmac_xfer_desc(struct rz_dmac_chan *chan) * DMA engine operations */ +static void rz_dmac_chan_init_all(struct rz_dmac *dmac) +{ + unsigned int i; + + rz_dmac_writel(dmac, DCTRL_DEFAULT, CHANNEL_0_7_COMMON_BASE + DCTRL); + rz_dmac_writel(dmac, DCTRL_DEFAULT, CHANNEL_8_15_COMMON_BASE + DCTRL); + + for (i = 0; i < dmac->n_channels; i++) + rz_dmac_ch_writel(&dmac->channels[i], CHCTRL_DEFAULT, CHCTRL, 1); +} + static int rz_dmac_alloc_chan_resources(struct dma_chan *chan) { struct rz_dmac_chan *channel = to_rz_dmac_chan(chan); @@ -970,10 +981,6 @@ static int rz_dmac_probe(struct platform_device *pdev) goto err_pm_disable; } - ret = reset_control_deassert(dmac->rstc); - if (ret) - goto err_pm_runtime_put; - for (i = 0; i < dmac->n_channels; i++) { ret = rz_dmac_chan_probe(dmac, &dmac->channels[i], i); if (ret < 0) @@ -1028,8 +1035,6 @@ static int rz_dmac_probe(struct platform_device *pdev) channel->lmdesc.base_dma); } - reset_control_assert(dmac->rstc); -err_pm_runtime_put: pm_runtime_put(&pdev->dev); err_pm_disable: pm_runtime_disable(&pdev->dev); @@ -1052,13 +1057,50 @@ static void rz_dmac_remove(struct platform_device *pdev) channel->lmdesc.base, channel->lmdesc.base_dma); } - reset_control_assert(dmac->rstc); pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); platform_device_put(dmac->icu.pdev); } +static int rz_dmac_runtime_suspend(struct device *dev) +{ + struct rz_dmac *dmac = dev_get_drvdata(dev); + + return reset_control_assert(dmac->rstc); +} + +static int rz_dmac_runtime_resume(struct device *dev) +{ + struct rz_dmac *dmac = dev_get_drvdata(dev); + + return reset_control_deassert(dmac->rstc); +} + +static int rz_dmac_resume(struct device *dev) +{ + struct rz_dmac *dmac = dev_get_drvdata(dev); + int ret; + + ret = pm_runtime_force_resume(dev); + if (ret) + return ret; + + rz_dmac_chan_init_all(dmac); + + return 0; +} + +static const struct dev_pm_ops rz_dmac_pm_ops = { + /* + * TODO for system sleep/resume: + * - Wait for the current transfer to complete and stop the device, + * - Resume transfers, if any. + */ + NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, rz_dmac_resume) + RUNTIME_PM_OPS(rz_dmac_runtime_suspend, rz_dmac_runtime_resume, NULL) +}; + static const struct of_device_id of_rz_dmac_match[] = { { .compatible = "renesas,r9a09g057-dmac", }, { .compatible = "renesas,rz-dmac", }, @@ -1068,6 +1110,7 @@ MODULE_DEVICE_TABLE(of, of_rz_dmac_match); static struct platform_driver rz_dmac_driver = { .driver = { + .pm = pm_ptr(&rz_dmac_pm_ops), .name = "rz-dmac", .of_match_table = of_rz_dmac_match, }, -- 2.43.0