[tip: irq/drivers] irqchip/imx-irqsteer: Let devres own the clock
From: tip-bot2 for Zhipeng Wang
Date: Sun Nov 08 2026 - 16:50:38 EST
The following commit has been merged into the irq/drivers branch of tip:
Commit-ID: 54ac29cd11115edd9f72f17aa4551658735f919d
Gitweb: https://git.kernel.org/tip/54ac29cd11115edd9f72f17aa4551658735f919d
Author: Zhipeng Wang <zhipeng.wang_1@xxxxxxx>
AuthorDate: Wed, 04 Nov 2026 16:37:54 +09:00
Committer: Thomas Gleixner <tglx@xxxxxxxxxx>
CommitterDate: Sun, 08 Nov 2026 22:43:44 +01:00
irqchip/imx-irqsteer: Let devres own the clock
Let the driver core own the clock lifetime so that the probe() error
path and remove() do not have to hand-balance it:
- acquire the clock with devm_clk_get_enabled() instead of a bare
devm_clk_get() followed by a manual clk_prepare_enable(), so it is
prepared/enabled for the device lifetime and released on unbind;
- keep only clk_enable()/clk_disable() in the runtime PM callbacks,
since prepare/unprepare is now handled once by devres.
Signed-off-by: Zhipeng Wang <zhipeng.wang_1@xxxxxxx>
Signed-off-by: Thomas Gleixner <tglx@xxxxxxxxxx>
Reviewed-by: Frank Li <Frank.Li@xxxxxxx>
Link: https://patch.msgid.link/20261104073759.386777-7-Zhipeng.wang_1@xxxxxxxxxxx
---
drivers/irqchip/irq-imx-irqsteer.c | 32 ++++++++++++++++-------------
1 file changed, 18 insertions(+), 14 deletions(-)
diff --git a/drivers/irqchip/irq-imx-irqsteer.c b/drivers/irqchip/irq-imx-irqsteer.c
index 7451c15..5c0c5a5 100644
--- a/drivers/irqchip/irq-imx-irqsteer.c
+++ b/drivers/irqchip/irq-imx-irqsteer.c
@@ -194,7 +194,7 @@ static int imx_irqsteer_probe(struct platform_device *pdev)
return PTR_ERR(data->regs);
}
- data->ipg_clk = devm_clk_get(&pdev->dev, "ipg");
+ data->ipg_clk = devm_clk_get_enabled(&pdev->dev, "ipg");
if (IS_ERR(data->ipg_clk))
return dev_err_probe(&pdev->dev, PTR_ERR(data->ipg_clk),
"failed to get ipg clk\n");
@@ -229,12 +229,6 @@ static int imx_irqsteer_probe(struct platform_device *pdev)
return -ENOMEM;
}
- ret = clk_prepare_enable(data->ipg_clk);
- if (ret) {
- dev_err(&pdev->dev, "failed to enable ipg clk: %d\n", ret);
- return ret;
- }
-
/* steer all IRQs into configured channel */
if (irqsteer_has_chanctrl(data->devtype_data))
writel_relaxed(BIT(data->channel), data->regs + CHANCTRL);
@@ -251,14 +245,13 @@ static int imx_irqsteer_probe(struct platform_device *pdev)
ret = devm_pm_runtime_set_active_enabled(&pdev->dev);
if (ret)
- goto out;
+ return ret;
data->domain = irq_domain_create_linear(dev_fwnode(&pdev->dev), data->reg_num * 32,
&imx_irqsteer_domain_ops, data);
if (!data->domain) {
dev_err(&pdev->dev, "failed to create IRQ domain\n");
- ret = -ENOMEM;
- goto out;
+ return -ENOMEM;
}
irq_domain_set_pm_device(data->domain, &pdev->dev);
@@ -282,6 +275,17 @@ static void imx_irqsteer_remove(struct platform_device *pdev)
{
struct irqsteer_data *irqsteer_data = platform_get_drvdata(pdev);
+ /*
+ * The device may be runtime-suspended here, in which case the runtime
+ * suspend callback has already dropped the clock enable count. Resume
+ * it so the devres clk_disable_unprepare(), which runs after remove(),
+ * finds the clock enabled and stays balanced. On success drop the
+ * usage count again with pm_runtime_put_noidle(): it must not trigger a
+ * suspend (which would re-disable the clock) and must not leak to the
+ * next probe of this persistent device.
+ */
+ int ret = pm_runtime_resume_and_get(&pdev->dev);
+
for (int i = 0; i < irqsteer_data->irq_count; i++) {
if (!irqsteer_data->irq[i])
break;
@@ -292,8 +296,8 @@ static void imx_irqsteer_remove(struct platform_device *pdev)
irq_domain_remove(irqsteer_data->domain);
- if (!pm_runtime_status_suspended(&pdev->dev))
- clk_disable_unprepare(irqsteer_data->ipg_clk);
+ if (ret >= 0)
+ pm_runtime_put_noidle(&pdev->dev);
}
#ifdef CONFIG_PM
@@ -323,7 +327,7 @@ static int imx_irqsteer_suspend(struct device *dev)
struct irqsteer_data *irqsteer_data = dev_get_drvdata(dev);
imx_irqsteer_save_regs(irqsteer_data);
- clk_disable_unprepare(irqsteer_data->ipg_clk);
+ clk_disable(irqsteer_data->ipg_clk);
return 0;
}
@@ -333,7 +337,7 @@ static int imx_irqsteer_resume(struct device *dev)
struct irqsteer_data *irqsteer_data = dev_get_drvdata(dev);
int ret;
- ret = clk_prepare_enable(irqsteer_data->ipg_clk);
+ ret = clk_enable(irqsteer_data->ipg_clk);
if (ret) {
dev_err(dev, "failed to enable ipg clk: %d\n", ret);
return ret;