[tip: irq/drivers] irqchip/imx-irqsteer: Let devres own the clock
From: tip-bot2 for Zhipeng Wang
Date: Mon Nov 09 2026 - 04:10:56 EST
The following commit has been merged into the irq/drivers branch of tip:
Commit-ID: a5e56178ae7bd67d0d549ff6e033e3225c9788f8
Gitweb: https://git.kernel.org/tip/a5e56178ae7bd67d0d549ff6e033e3225c9788f8
Author: Zhipeng Wang <zhipeng.wang_1@xxxxxxx>
AuthorDate: Wed, 04 Nov 2026 16:37:54 +09:00
Committer: Thomas Gleixner <tglx@xxxxxxxxxx>
CommitterDate: Mon, 09 Nov 2026 10:01:08 +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 | 35 ++++++++++++++---------------
1 file changed, 18 insertions(+), 17 deletions(-)
diff --git a/drivers/irqchip/irq-imx-irqsteer.c b/drivers/irqchip/irq-imx-irqsteer.c
index 7451c15..6e1f77d 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);
@@ -273,15 +266,23 @@ static int imx_irqsteer_probe(struct platform_device *pdev)
}
return 0;
-out:
- clk_disable_unprepare(data->ipg_clk);
- return ret;
}
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 +293,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 +324,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 +334,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;