dmaengine: dw-axi-dmac: PM cleanup and reset control support
Subsystems (2)
v2 cover dmaengine: dw-axi-dmac: PM cleanup and reset control support
This patch series improves the dw-axi-dmac driver in two areas:
Patch 1 simplifies the power management code by using modern kernel macros and removing redundant wrapper functions, making the code more maintainable and aligned with current kernel practices.
Patch 2 adds proper reset control support to ensure reliable initialization and power management, handling resets during probe, remove, and suspend/resume operations.
ChangeLog:
v1:
* https://lore.kernel.org/all/[email protected]/T/#t
v2:
* Remove has_resets flag and use reset_control_assert/deassert() unconditionally, as these functions handle NULL pointers internally
* Replace devm_reset_control_array_get_exclusive() with devm_reset_control_array_get_optional_exclusive() to handle platforms without reset controls gracefully
* Simplify error handling by removing redundant flag checks
* Remove has_resets field from struct axi_dma_chip as it's no longer needed
Artem Shimko (2):
dmaengine: dw-axi-dmac: simplify PM functions and use modern macros
dmaengine: dw-axi-dmac: add reset control support
.../dma/dw-axi-dmac/dw-axi-dmac-platform.c | 66 ++++++++----------- drivers/dma/dw-axi-dmac/dw-axi-dmac.h | 1 + 2 files changed, 30 insertions(+), 37 deletions(-)
Signature · 1 line
2.43.0
PATCH v2 1/2 dmaengine: dw-axi-dmac: simplify PM functions and use modern macros
Simplify the power management code by removing redundant wrapper functions and using modern kernel PM macros. This reduces code duplication and improves maintainability.
The changes convert the suspend/resume functions to take device pointer directly instead of the chip structure, allowing removal of the runtime PM wrapper functions. The manual PM ops definition is replaced with DEFINE_RUNTIME_DEV_PM_OPS() macro and pm_ptr() is used for the platform driver. Probe and remove functions are updated to call PM functions with device pointer.
--- .../dma/dw-axi-dmac/dw-axi-dmac-platform.c | 31 ++++++------------- 1 file changed, 9 insertions(+), 22 deletions(-)
drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +9 -22
@@ -1314,8 +1314,10 @@ static int dma_chan_resume(struct dma_chan *dchan)return 0 ; } -static int axi_dma_suspend (struct axi_dma_chip *chip) +static int axi_dma_suspend (struct device *dev) { +struct axi_dma_chip *chip =dev_get_drvdata (dev); +axi_dma_irq_disable (chip);axi_dma_disable (chip);
@@ -1325,9 +1327,10 @@ static int axi_dma_suspend(struct axi_dma_chip *chip)return 0 ; } -static int axi_dma_resume (struct axi_dma_chip *chip) +static int axi_dma_resume (struct device *dev) {int ret; +struct axi_dma_chip *chip =dev_get_drvdata (dev); ret =clk_prepare_enable (chip->cfgr_clk);if (ret <0 )
@@ -1343,20 +1346,6 @@ static int axi_dma_resume(struct axi_dma_chip *chip)return 0 ; } -static int __maybe_unused axi_dma_runtime_suspend (struct device *dev) -{ -struct axi_dma_chip *chip =dev_get_drvdata (dev); - -return axi_dma_suspend (chip); -} - -static int __maybe_unused axi_dma_runtime_resume (struct device *dev) -{ -struct axi_dma_chip *chip =dev_get_drvdata (dev); - -return axi_dma_resume (chip); -} -static struct dma_chan *dw_axi_dma_of_xlate (struct of_phandle_args *dma_spec,struct of_dma *ofdma) {
@@ -1590,7 +1579,7 @@ static int dw_probe(struct platform_device *pdev)* driver to work also without Runtime PM. */ pm_runtime_get_noresume (chip->dev); - ret =axi_dma_resume (chip); + ret =axi_dma_resume (chip->dev);if (ret <0 ) goto err_pm_disable;
@@ -1638,7 +1627,7 @@ static void dw_remove(struct platform_device *pdev)axi_dma_disable (chip);pm_runtime_disable (chip->dev); -axi_dma_suspend (chip); +axi_dma_suspend (chip->dev);for (i =0 ; i <DMAC_MAX_CHANNELS ; i++)if (chip->irq[i] >0 )
@@ -1653,9 +1642,7 @@ static void dw_remove(struct platform_device *pdev) } } -static const struct dev_pm_ops dw_axi_dma_pm_ops = { -SET_RUNTIME_PM_OPS (axi_dma_runtime_suspend, axi_dma_runtime_resume,NULL ) -}; +static DEFINE_RUNTIME_DEV_PM_OPS(dw_axi_dma_pm_ops, axi_dma_suspend, axi_dma_resume, NULL);static const struct of_device_id dw_dma_of_id_table[] = { {
@@ -1680,7 +1667,7 @@ static struct platform_driver dw_driver = { .driver = { .name = KBUILD_MODNAME, .of_match_table = dw_dma_of_id_table, - .pm = &dw_axi_dma_pm_ops, + .pm = pm_ptr(&dw_axi_dma_pm_ops), }, };module_platform_driver (dw_driver);
Signature · 1 line
2.43.0
PATCH v2 2/2 dmaengine: dw-axi-dmac: add reset control support
In reply to Artem ShimkoAdd proper reset control handling to the AXI DMA driver to ensure reliable initialization and power management. The driver now manages resets during probe, remove, and system suspend/resume operations.
The implementation stores reset control in the chip structure and adds reset assert/deassert calls at the appropriate points: resets are deasserted during probe after clock acquisition, asserted during remove and error cleanup, and properly managed during suspend/resume cycles. Additionally, proper error handling is implemented for reset control operations to ensure robust behavior.
This ensures the controller is properly reset during power transitions and prevents potential issues with incomplete initialization.
--- .../dma/dw-axi-dmac/dw-axi-dmac-platform.c | 35 +++++++++++-------- drivers/dma/dw-axi-dmac/dw-axi-dmac.h | 1 + 2 files changed, 21 insertions(+), 15 deletions(-)
drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +20 -15
@@ -1321,6 +1321,8 @@ static int axi_dma_suspend(struct device *dev)axi_dma_irq_disable (chip);axi_dma_disable (chip); +reset_control_assert (chip->resets); +clk_disable_unprepare (chip->core_clk);clk_disable_unprepare (chip->cfgr_clk);
@@ -1340,6 +1342,8 @@ static int axi_dma_resume(struct device *dev)if (ret <0 )return ret; +reset_control_deassert (chip->resets); +axi_dma_enable (chip);axi_dma_irq_enable (chip);
@@ -1455,7 +1459,6 @@ static int dw_probe(struct platform_device *pdev)struct axi_dma_chip *chip;struct dw_axi_dma *dw;struct dw_axi_dma_hcfg *hdata; -struct reset_control *resets;unsigned int flags;u32 i;int ret;
@@ -1487,16 +1490,6 @@ static int dw_probe(struct platform_device *pdev)return PTR_ERR (chip->apb_regs); } -if (flags &AXI_DMA_FLAG_HAS_RESETS ) { - resets =devm_reset_control_array_get_exclusive (&pdev->dev); -if (IS_ERR (resets)) -return PTR_ERR (resets); - - ret =reset_control_deassert (resets); -if (ret) -return ret; - } - chip->dw->hdata->use_cfg2 = !!(flags &AXI_DMA_FLAG_USE_CFG2 ); chip->core_clk =devm_clk_get (chip->dev,"core-clk" );
@@ -1507,18 +1500,28 @@ static int dw_probe(struct platform_device *pdev)if (IS_ERR (chip->cfgr_clk))return PTR_ERR (chip->cfgr_clk); + chip->resets =devm_reset_control_array_get_optional_exclusive (&pdev->dev); +if (IS_ERR (chip->resets)) +return PTR_ERR (chip->resets); + + ret =reset_control_deassert (chip->resets); +if (ret) +return dev_err_probe (&pdev->dev, ret,"Failed to deassert resets\n" ); + ret =parse_device_properties (chip);if (ret) -return ret; + goto err_exit; dw->chan =devm_kcalloc (chip->dev, hdata->nr_channels,sizeof (*dw->chan),GFP_KERNEL ); -if (!dw->chan) -return -ENOMEM ; +if (!dw->chan) { + ret = -ENOMEM ; + goto err_exit; + } ret =axi_req_irqs (pdev, chip);if (ret) -return ret; + goto err_exit;INIT_LIST_HEAD (&dw->dma.channels);for (i =0 ; i < hdata->nr_channels; i++) {
@@ -1605,6 +1608,8 @@ static int dw_probe(struct platform_device *pdev) err_pm_disable:pm_runtime_disable (chip->dev); +err_exit: +reset_control_assert (chip->resets);return ret; }
drivers/dma/dw-axi-dmac/dw-axi-dmac.h +1 -0
@@ -71,6 +71,7 @@ struct axi_dma_chip {struct clk *core_clk;struct clk *cfgr_clk;struct dw_axi_dma *dw; +struct reset_control *resets; };/* LLI == Linked List Item */
Signature · 1 line
2.43.0