* [PATCH v3 1/4] irqchip/imx-irqsteer: Fix error handling path in probe()
2026-08-07 7:23 [PATCH v3 0/4] irqchip/imx-irqsteer: Allow building as module Zhipeng.wang_1
@ 2026-08-07 7:23 ` Zhipeng.wang_1
2026-08-07 19:01 ` Frank Li
2026-08-07 7:23 ` [PATCH v3 2/4] irqchip/imx-irqsteer: Dispose of IRQ mappings in remove() Zhipeng.wang_1
` (2 subsequent siblings)
3 siblings, 1 reply; 8+ messages in thread
From: Zhipeng.wang_1 @ 2026-08-07 7:23 UTC (permalink / raw)
To: Thomas Gleixner, Marc Zyngier, Frank Li
Cc: Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam, Jindong Yue,
xuegang.liu, linux-kernel, imx, linux-arm-kernel
From: Zhipeng Wang <zhipeng.wang_1@nxp.com>
If the fsl,num-irqs sanity check rejects the value after the IRQ domain
has already been created, probe() jumps to a single label that only calls
clk_disable_unprepare(), leaving the freshly created IRQ domain leaked.
The domain-creation failure path shares the same label, which is correct
only because the domain is NULL there.
Split the error path so that a failure after the domain has been created
removes it before disabling the clock, and a failure before that goes
straight to the clock cleanup.
Fixes: 28528fca4908 ("irqchip/imx-irqsteer: Add multi output interrupts support")
Signed-off-by: Zhipeng Wang <zhipeng.wang_1@nxp.com>
---
Changes in v3:
- New patch, split out of the single v2 patch. Fixes the irq_domain
leak on the probe() error path reported by Sashiko AI on v2.
drivers/irqchip/irq-imx-irqsteer.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/drivers/irqchip/irq-imx-irqsteer.c b/drivers/irqchip/irq-imx-irqsteer.c
index 87b07f517be3..a2f0629b22a3 100644
--- a/drivers/irqchip/irq-imx-irqsteer.c
+++ b/drivers/irqchip/irq-imx-irqsteer.c
@@ -241,13 +241,13 @@ static int imx_irqsteer_probe(struct platform_device *pdev)
if (!data->domain) {
dev_err(&pdev->dev, "failed to create IRQ domain\n");
ret = -ENOMEM;
- goto out;
+ goto err_clk;
}
irq_domain_set_pm_device(data->domain, &pdev->dev);
if (!data->irq_count || data->irq_count > CHAN_MAX_OUTPUT_INT) {
ret = -EINVAL;
- goto out;
+ goto err_domain;
}
for (i = 0; i < data->irq_count; i++) {
@@ -266,7 +266,10 @@ static int imx_irqsteer_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
return 0;
-out:
+
+err_domain:
+ irq_domain_remove(data->domain);
+err_clk:
clk_disable_unprepare(data->ipg_clk);
return ret;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: [PATCH v3 1/4] irqchip/imx-irqsteer: Fix error handling path in probe()
2026-08-07 7:23 ` [PATCH v3 1/4] irqchip/imx-irqsteer: Fix error handling path in probe() Zhipeng.wang_1
@ 2026-08-07 19:01 ` Frank Li
0 siblings, 0 replies; 8+ messages in thread
From: Frank Li @ 2026-08-07 19:01 UTC (permalink / raw)
To: Zhipeng.wang_1
Cc: Thomas Gleixner, Marc Zyngier, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Jindong Yue, xuegang.liu,
linux-kernel, imx, linux-arm-kernel
On Fri, Aug 07, 2026 at 04:23:43PM +0900, Zhipeng.wang_1@oss.nxp.com wrote:
> From: Zhipeng Wang <zhipeng.wang_1@nxp.com>
>
> If the fsl,num-irqs sanity check rejects the value after the IRQ domain
> has already been created, probe() jumps to a single label that only calls
> clk_disable_unprepare(), leaving the freshly created IRQ domain leaked.
> The domain-creation failure path shares the same label, which is correct
> only because the domain is NULL there.
>
> Split the error path so that a failure after the domain has been created
> removes it before disabling the clock, and a failure before that goes
> straight to the clock cleanup.
>
> Fixes: 28528fca4908 ("irqchip/imx-irqsteer: Add multi output interrupts support")
> Signed-off-by: Zhipeng Wang <zhipeng.wang_1@nxp.com>
> ---
> Changes in v3:
> - New patch, split out of the single v2 patch. Fixes the irq_domain
> leak on the probe() error path reported by Sashiko AI on v2.
>
> drivers/irqchip/irq-imx-irqsteer.c | 9 ++++++---
> 1 file changed, 6 insertions(+), 3 deletions(-)
I suggest create helper devm_irq_domain_create_leaner()
static inline struct irq_domain *
devm_irq_domain_create_linear(struct fwnode_handle *fwnode,
unsigned int size,
const struct irq_domain_ops *ops,
void *host_data)
{
const struct irq_domain_info info = {
.fwnode = fwnode,
.size = size,
.hwirq_max = size,
.ops = ops,
.host_data = host_data,
};
struct irq_domain *d = devm_irq_domain_instantiate(&info);
return IS_ERR(d) ? NULL : d;
}
Then imx-irqsteer this devm version. So other drivers can get beneafit also
Frank
>
> diff --git a/drivers/irqchip/irq-imx-irqsteer.c b/drivers/irqchip/irq-imx-irqsteer.c
> index 87b07f517be3..a2f0629b22a3 100644
> --- a/drivers/irqchip/irq-imx-irqsteer.c
> +++ b/drivers/irqchip/irq-imx-irqsteer.c
> @@ -241,13 +241,13 @@ static int imx_irqsteer_probe(struct platform_device *pdev)
> if (!data->domain) {
> dev_err(&pdev->dev, "failed to create IRQ domain\n");
> ret = -ENOMEM;
> - goto out;
> + goto err_clk;
> }
> irq_domain_set_pm_device(data->domain, &pdev->dev);
>
> if (!data->irq_count || data->irq_count > CHAN_MAX_OUTPUT_INT) {
> ret = -EINVAL;
> - goto out;
> + goto err_domain;
> }
>
> for (i = 0; i < data->irq_count; i++) {
> @@ -266,7 +266,10 @@ static int imx_irqsteer_probe(struct platform_device *pdev)
> pm_runtime_enable(&pdev->dev);
>
> return 0;
> -out:
> +
> +err_domain:
> + irq_domain_remove(data->domain);
> +err_clk:
> clk_disable_unprepare(data->ipg_clk);
> return ret;
> }
> --
> 2.34.1
>
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v3 2/4] irqchip/imx-irqsteer: Dispose of IRQ mappings in remove()
2026-08-07 7:23 [PATCH v3 0/4] irqchip/imx-irqsteer: Allow building as module Zhipeng.wang_1
2026-08-07 7:23 ` [PATCH v3 1/4] irqchip/imx-irqsteer: Fix error handling path in probe() Zhipeng.wang_1
@ 2026-08-07 7:23 ` Zhipeng.wang_1
2026-08-07 19:11 ` Frank Li
2026-08-07 7:23 ` [PATCH v3 3/4] irqchip/imx-irqsteer: Mask all interrupts in probe() and remove() Zhipeng.wang_1
2026-08-07 7:23 ` [PATCH v3 4/4] irqchip/imx-irqsteer: Allow building as module Zhipeng.wang_1
3 siblings, 1 reply; 8+ messages in thread
From: Zhipeng.wang_1 @ 2026-08-07 7:23 UTC (permalink / raw)
To: Thomas Gleixner, Marc Zyngier, Frank Li
Cc: Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam, Jindong Yue,
xuegang.liu, linux-kernel, imx, linux-arm-kernel
From: Zhipeng Wang <zhipeng.wang_1@nxp.com>
remove() tears down the chained handlers and the IRQ domain but never
disposes of the IRQ mappings it created. The parent mappings from
irq_of_parse_and_map() and the child mappings handed out by the domain
are leaked, and the child irq_descs are left pointing at the driver's
irq_chip past irq_domain_remove().
Dispose of the parent mappings alongside the chained handler teardown,
and dispose of the child mappings before removing the domain.
Fixes: 0136afa08967 ("irqchip: Add driver for imx-irqsteer controller")
Signed-off-by: Zhipeng Wang <zhipeng.wang_1@nxp.com>
---
Changes in v3:
- Split out of the single v2 patch. In v2 this was folded into the
module-conversion patch; no functional change.
drivers/irqchip/irq-imx-irqsteer.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/irqchip/irq-imx-irqsteer.c b/drivers/irqchip/irq-imx-irqsteer.c
index a2f0629b22a3..4a2fe8ba97f5 100644
--- a/drivers/irqchip/irq-imx-irqsteer.c
+++ b/drivers/irqchip/irq-imx-irqsteer.c
@@ -277,7 +277,7 @@ static int imx_irqsteer_probe(struct platform_device *pdev)
static void imx_irqsteer_remove(struct platform_device *pdev)
{
struct irqsteer_data *irqsteer_data = platform_get_drvdata(pdev);
- int i;
+ int hwirq, i;
for (i = 0; i < irqsteer_data->irq_count; i++) {
if (!irqsteer_data->irq[i])
@@ -285,8 +285,13 @@ static void imx_irqsteer_remove(struct platform_device *pdev)
irq_set_chained_handler_and_data(irqsteer_data->irq[i],
NULL, NULL);
+ irq_dispose_mapping(irqsteer_data->irq[i]);
}
+ for (hwirq = 0; hwirq < irqsteer_data->reg_num * 32; hwirq++)
+ irq_dispose_mapping(irq_find_mapping(irqsteer_data->domain,
+ hwirq));
+
irq_domain_remove(irqsteer_data->domain);
clk_disable_unprepare(irqsteer_data->ipg_clk);
--
2.34.1
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: [PATCH v3 2/4] irqchip/imx-irqsteer: Dispose of IRQ mappings in remove()
2026-08-07 7:23 ` [PATCH v3 2/4] irqchip/imx-irqsteer: Dispose of IRQ mappings in remove() Zhipeng.wang_1
@ 2026-08-07 19:11 ` Frank Li
0 siblings, 0 replies; 8+ messages in thread
From: Frank Li @ 2026-08-07 19:11 UTC (permalink / raw)
To: Zhipeng.wang_1
Cc: Thomas Gleixner, Marc Zyngier, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Jindong Yue, xuegang.liu,
linux-kernel, imx, linux-arm-kernel
On Fri, Aug 07, 2026 at 04:23:44PM +0900, Zhipeng.wang_1@oss.nxp.com wrote:
> From: Zhipeng Wang <zhipeng.wang_1@nxp.com>
>
> remove() tears down the chained handlers and the IRQ domain but never
> disposes of the IRQ mappings it created. The parent mappings from
> irq_of_parse_and_map() and the child mappings handed out by the domain
> are leaked, and the child irq_descs are left pointing at the driver's
> irq_chip past irq_domain_remove().
>
> Dispose of the parent mappings alongside the chained handler teardown,
> and dispose of the child mappings before removing the domain.
>
> Fixes: 0136afa08967 ("irqchip: Add driver for imx-irqsteer controller")
> Signed-off-by: Zhipeng Wang <zhipeng.wang_1@nxp.com>
> ---
> Changes in v3:
> - Split out of the single v2 patch. In v2 this was folded into the
> module-conversion patch; no functional change.
>
> drivers/irqchip/irq-imx-irqsteer.c | 7 ++++++-
> 1 file changed, 6 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/irqchip/irq-imx-irqsteer.c b/drivers/irqchip/irq-imx-irqsteer.c
> index a2f0629b22a3..4a2fe8ba97f5 100644
> --- a/drivers/irqchip/irq-imx-irqsteer.c
> +++ b/drivers/irqchip/irq-imx-irqsteer.c
> @@ -277,7 +277,7 @@ static int imx_irqsteer_probe(struct platform_device *pdev)
> static void imx_irqsteer_remove(struct platform_device *pdev)
> {
> struct irqsteer_data *irqsteer_data = platform_get_drvdata(pdev);
> - int i;
> + int hwirq, i;
>
> for (i = 0; i < irqsteer_data->irq_count; i++) {
> if (!irqsteer_data->irq[i])
> @@ -285,8 +285,13 @@ static void imx_irqsteer_remove(struct platform_device *pdev)
>
> irq_set_chained_handler_and_data(irqsteer_data->irq[i],
> NULL, NULL);
> + irq_dispose_mapping(irqsteer_data->irq[i]);
> }
>
> + for (hwirq = 0; hwirq < irqsteer_data->reg_num * 32; hwirq++)
> + irq_dispose_mapping(irq_find_mapping(irqsteer_data->domain,
> + hwirq));
> +
only call once irq_of_parse_and_map(), why need irq_dispose_mapping() twice?
Frank
> irq_domain_remove(irqsteer_data->domain);
>
> clk_disable_unprepare(irqsteer_data->ipg_clk);
> --
> 2.34.1
>
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v3 3/4] irqchip/imx-irqsteer: Mask all interrupts in probe() and remove()
2026-08-07 7:23 [PATCH v3 0/4] irqchip/imx-irqsteer: Allow building as module Zhipeng.wang_1
2026-08-07 7:23 ` [PATCH v3 1/4] irqchip/imx-irqsteer: Fix error handling path in probe() Zhipeng.wang_1
2026-08-07 7:23 ` [PATCH v3 2/4] irqchip/imx-irqsteer: Dispose of IRQ mappings in remove() Zhipeng.wang_1
@ 2026-08-07 7:23 ` Zhipeng.wang_1
2026-08-07 19:14 ` Frank Li
2026-08-07 7:23 ` [PATCH v3 4/4] irqchip/imx-irqsteer: Allow building as module Zhipeng.wang_1
3 siblings, 1 reply; 8+ messages in thread
From: Zhipeng.wang_1 @ 2026-08-07 7:23 UTC (permalink / raw)
To: Thomas Gleixner, Marc Zyngier, Frank Li
Cc: Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam, Jindong Yue,
xuegang.liu, linux-kernel, imx, linux-arm-kernel
From: Zhipeng Wang <zhipeng.wang_1@nxp.com>
probe() sets up the chained handlers without first masking the input
interrupts, and remove() leaves the CHANMASK registers untouched. For a
built-in driver this happened to be harmless because CHANMASK resets to
all-masked, but once the driver can be unloaded and reloaded a child
interrupt left unmasked at unload time survives in hardware. On the next
probe() the parent interrupts are re-mapped and unmasked before the new
domain is ready, so a still-asserted line immediately storms the parent
with no handler to service it.
Mask all interrupts in probe() before wiring up the chained handlers, and
again in remove() so the hardware is left quiesced for the next probe().
Note CHANMASK uses inverted polarity (a set bit enables the interrupt), so
masking means writing zero. This mirrors the sibling NXP chained mux
irq-imx-intmux.c, which has masked all sources in both probe() and remove()
since commit 2fbb13961e74 ("irqchip: Add NXP INTMUX interrupt multiplexer
support").
Signed-off-by: Zhipeng Wang <zhipeng.wang_1@nxp.com>
---
Changes in v3:
- New patch. Masks all CHANMASK interrupts in probe() and remove() to
prevent the interrupt storm on module reload reported by Sashiko AI
on v2.
drivers/irqchip/irq-imx-irqsteer.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/drivers/irqchip/irq-imx-irqsteer.c b/drivers/irqchip/irq-imx-irqsteer.c
index 4a2fe8ba97f5..0c9c99f1141a 100644
--- a/drivers/irqchip/irq-imx-irqsteer.c
+++ b/drivers/irqchip/irq-imx-irqsteer.c
@@ -236,6 +236,10 @@ static int imx_irqsteer_probe(struct platform_device *pdev)
if (irqsteer_has_chanctrl(data->devtype_data))
writel_relaxed(BIT(data->channel), data->regs + CHANCTRL);
+ /* mask all interrupts before setting up the chained handlers */
+ for (i = 0; i < data->reg_num; i++)
+ writel_relaxed(0, data->regs + CHANMASK(i, data->reg_num));
+
data->domain = irq_domain_create_linear(dev_fwnode(&pdev->dev), data->reg_num * 32,
&imx_irqsteer_domain_ops, data);
if (!data->domain) {
@@ -279,6 +283,11 @@ static void imx_irqsteer_remove(struct platform_device *pdev)
struct irqsteer_data *irqsteer_data = platform_get_drvdata(pdev);
int hwirq, i;
+ /* mask all interrupts so a stale line cannot storm on the next probe */
+ for (i = 0; i < irqsteer_data->reg_num; i++)
+ writel_relaxed(0, irqsteer_data->regs +
+ CHANMASK(i, irqsteer_data->reg_num));
+
for (i = 0; i < irqsteer_data->irq_count; i++) {
if (!irqsteer_data->irq[i])
break;
--
2.34.1
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: [PATCH v3 3/4] irqchip/imx-irqsteer: Mask all interrupts in probe() and remove()
2026-08-07 7:23 ` [PATCH v3 3/4] irqchip/imx-irqsteer: Mask all interrupts in probe() and remove() Zhipeng.wang_1
@ 2026-08-07 19:14 ` Frank Li
0 siblings, 0 replies; 8+ messages in thread
From: Frank Li @ 2026-08-07 19:14 UTC (permalink / raw)
To: Zhipeng.wang_1
Cc: Thomas Gleixner, Marc Zyngier, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Jindong Yue, xuegang.liu,
linux-kernel, imx, linux-arm-kernel
On Fri, Aug 07, 2026 at 04:23:45PM +0900, Zhipeng.wang_1@oss.nxp.com wrote:
> From: Zhipeng Wang <zhipeng.wang_1@nxp.com>
>
> probe() sets up the chained handlers without first masking the input
> interrupts, and remove() leaves the CHANMASK registers untouched. For a
> built-in driver this happened to be harmless because CHANMASK resets to
> all-masked, but once the driver can be unloaded and reloaded a child
> interrupt left unmasked at unload time survives in hardware. On the next
> probe() the parent interrupts are re-mapped and unmasked before the new
> domain is ready, so a still-asserted line immediately storms the parent
> with no handler to service it.
>
> Mask all interrupts in probe() before wiring up the chained handlers, and
> again in remove() so the hardware is left quiesced for the next probe().
> Note CHANMASK uses inverted polarity (a set bit enables the interrupt), so
> masking means writing zero. This mirrors the sibling NXP chained mux
> irq-imx-intmux.c, which has masked all sources in both probe() and remove()
> since commit 2fbb13961e74 ("irqchip: Add NXP INTMUX interrupt multiplexer
> support").
>
> Signed-off-by: Zhipeng Wang <zhipeng.wang_1@nxp.com>
> ---
> Changes in v3:
> - New patch. Masks all CHANMASK interrupts in probe() and remove() to
> prevent the interrupt storm on module reload reported by Sashiko AI
> on v2.
>
> drivers/irqchip/irq-imx-irqsteer.c | 9 +++++++++
> 1 file changed, 9 insertions(+)
>
> diff --git a/drivers/irqchip/irq-imx-irqsteer.c b/drivers/irqchip/irq-imx-irqsteer.c
> index 4a2fe8ba97f5..0c9c99f1141a 100644
> --- a/drivers/irqchip/irq-imx-irqsteer.c
> +++ b/drivers/irqchip/irq-imx-irqsteer.c
> @@ -236,6 +236,10 @@ static int imx_irqsteer_probe(struct platform_device *pdev)
> if (irqsteer_has_chanctrl(data->devtype_data))
> writel_relaxed(BIT(data->channel), data->regs + CHANCTRL);
>
> + /* mask all interrupts before setting up the chained handlers */
> + for (i = 0; i < data->reg_num; i++)
> + writel_relaxed(0, data->regs + CHANMASK(i, data->reg_num));
> +
> data->domain = irq_domain_create_linear(dev_fwnode(&pdev->dev), data->reg_num * 32,
> &imx_irqsteer_domain_ops, data);
> if (!data->domain) {
> @@ -279,6 +283,11 @@ static void imx_irqsteer_remove(struct platform_device *pdev)
> struct irqsteer_data *irqsteer_data = platform_get_drvdata(pdev);
> int hwirq, i;
>
> + /* mask all interrupts so a stale line cannot storm on the next probe */
> + for (i = 0; i < irqsteer_data->reg_num; i++)
> + writel_relaxed(0, irqsteer_data->regs +
> + CHANMASK(i, irqsteer_data->reg_num));
> +
You access register here, do you need call runtime pm get to enable clock
first?
Frank
> for (i = 0; i < irqsteer_data->irq_count; i++) {
> if (!irqsteer_data->irq[i])
> break;
> --
> 2.34.1
>
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v3 4/4] irqchip/imx-irqsteer: Allow building as module
2026-08-07 7:23 [PATCH v3 0/4] irqchip/imx-irqsteer: Allow building as module Zhipeng.wang_1
` (2 preceding siblings ...)
2026-08-07 7:23 ` [PATCH v3 3/4] irqchip/imx-irqsteer: Mask all interrupts in probe() and remove() Zhipeng.wang_1
@ 2026-08-07 7:23 ` Zhipeng.wang_1
3 siblings, 0 replies; 8+ messages in thread
From: Zhipeng.wang_1 @ 2026-08-07 7:23 UTC (permalink / raw)
To: Thomas Gleixner, Marc Zyngier, Frank Li
Cc: Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam, Jindong Yue,
xuegang.liu, linux-kernel, imx, linux-arm-kernel
From: Jindong Yue <jindong.yue@nxp.com>
Make the driver buildable as a module by turning the Kconfig symbol into
a tristate and using module_platform_driver() instead of
builtin_platform_driver().
Now that the driver can be unloaded and reloaded, let the driver core
own the clock and runtime PM lifetime so that remove() does not have to
hand-balance them:
- 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;
- enable runtime PM with devm_pm_runtime_set_active_enabled(), which
marks the device active (matching the enabled clock) and disables
runtime PM on unbind.
With the clock and runtime PM owned by devres, the probe() error path
and remove() only need to tear down the IRQ mappings and the domain.
Signed-off-by: Jindong Yue <jindong.yue@nxp.com>
Signed-off-by: Zhipeng Wang <zhipeng.wang_1@nxp.com>
---
Changes in v3:
- Let devres own the clock and runtime PM: acquire the clock with
devm_clk_get_enabled() and enable runtime PM with
devm_pm_runtime_set_active_enabled(), dropping the manual
pm_runtime_get_sync()/pm_runtime_disable()/clk_disable_unprepare()
balancing that v2 open-coded in remove() (Frank Li).
- The IRQ mapping disposal and the CHANMASK masking that v2 folded into
this patch are now separate patches (2/4 and 3/4).
drivers/irqchip/Kconfig | 2 +-
drivers/irqchip/irq-imx-irqsteer.c | 39 ++++++++++++++++--------------
2 files changed, 22 insertions(+), 19 deletions(-)
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 42f2278a702d..07db3b678f94 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -560,7 +560,7 @@ config CSKY_APB_INTC
the controller's register.
config IMX_IRQSTEER
- bool "i.MX IRQSTEER support"
+ tristate "i.MX IRQSTEER support"
depends on ARCH_MXC || ARCH_S32 || COMPILE_TEST
default y if ARCH_MXC || ARCH_S32
select IRQ_DOMAIN
diff --git a/drivers/irqchip/irq-imx-irqsteer.c b/drivers/irqchip/irq-imx-irqsteer.c
index 0c9c99f1141a..e62862617b8d 100644
--- a/drivers/irqchip/irq-imx-irqsteer.c
+++ b/drivers/irqchip/irq-imx-irqsteer.c
@@ -10,6 +10,7 @@
#include <linux/irqchip/chained_irq.h>
#include <linux/irqdomain.h>
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
@@ -193,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");
@@ -226,12 +227,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);
@@ -244,8 +239,7 @@ static int imx_irqsteer_probe(struct platform_device *pdev)
&imx_irqsteer_domain_ops, data);
if (!data->domain) {
dev_err(&pdev->dev, "failed to create IRQ domain\n");
- ret = -ENOMEM;
- goto err_clk;
+ return -ENOMEM;
}
irq_domain_set_pm_device(data->domain, &pdev->dev);
@@ -266,15 +260,22 @@ static int imx_irqsteer_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, data);
- pm_runtime_set_active(&pdev->dev);
- pm_runtime_enable(&pdev->dev);
+ ret = devm_pm_runtime_set_active_enabled(&pdev->dev);
+ if (ret)
+ goto err_irq;
return 0;
+err_irq:
+ for (i = 0; i < data->irq_count; i++) {
+ if (!data->irq[i])
+ break;
+
+ irq_set_chained_handler_and_data(data->irq[i], NULL, NULL);
+ irq_dispose_mapping(data->irq[i]);
+ }
err_domain:
irq_domain_remove(data->domain);
-err_clk:
- clk_disable_unprepare(data->ipg_clk);
return ret;
}
@@ -302,8 +303,6 @@ static void imx_irqsteer_remove(struct platform_device *pdev)
hwirq));
irq_domain_remove(irqsteer_data->domain);
-
- clk_disable_unprepare(irqsteer_data->ipg_clk);
}
#ifdef CONFIG_PM
@@ -333,7 +332,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;
}
@@ -343,7 +342,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;
@@ -366,6 +365,7 @@ static const struct of_device_id imx_irqsteer_dt_ids[] = {
{ .compatible = "nxp,s32n79-irqsteer", .data = &s32n79_data },
{},
};
+MODULE_DEVICE_TABLE(of, imx_irqsteer_dt_ids);
static struct platform_driver imx_irqsteer_driver = {
.driver = {
@@ -376,4 +376,7 @@ static struct platform_driver imx_irqsteer_driver = {
.probe = imx_irqsteer_probe,
.remove = imx_irqsteer_remove,
};
-builtin_platform_driver(imx_irqsteer_driver);
+module_platform_driver(imx_irqsteer_driver);
+
+MODULE_DESCRIPTION("i.MX IRQSTEER interrupt multiplexer/remapper driver");
+MODULE_LICENSE("GPL");
--
2.34.1
^ permalink raw reply related [flat|nested] 8+ messages in thread