mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 0/9] gpio: mxc: bug fixes and probe cleanup
@ 2026-10-03 12:06 Peng Fan (OSS)
  2026-10-03 12:06 ` [PATCH 1/9] gpio: mxc: fix race between chained IRQ handler install and probe completion Peng Fan (OSS)
                   ` (8 more replies)
  0 siblings, 9 replies; 20+ messages in thread
From: Peng Fan (OSS) @ 2026-10-03 12:06 UTC (permalink / raw)
  To: Linus Walleij, Bartosz Golaszewski, Frank Li, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, Shenwei Wang,
	Andy Shevchenko
  Cc: linux-gpio, imx, linux-arm-kernel, linux-kernel, Peng Fan

Two bug fixes and follows up with probe modernization and bitops cleanup.

We not receive bug report and met issues during our test, so patch 1&2
are not critial for now.

Patches 1-2 are bug fixes:

  1. Fix a race where the chained IRQ handler is installed before the
     IRQ domain, generic IRQ chip, and port list entry are ready.
     Also fixes a latent use-after-free on probe failure paths that
     never unregistered the handler.

  2. Fix wakeup_pads being typed as u32 while accessed through
     set_bit/clear_bit (unsigned long *), causing adjacent field
     corruption on 64-bit platforms. Switch to atomic bitops for
     concurrency safety and fix the disable path to preserve the
     wakeup_pads bit on disable_irq_wake() failure.

Patches 3-9 are cleanups, each building on the previous:

  3. Cache of_device_is_compatible() results at probe into struct
     fields, avoiding repeated DT string comparisons in suspend/resume.

  4. Use devm_add_action_or_reset() for irq_domain_remove(), removing
     manual cleanup in error paths.

  5. Switch to devm-managed PM runtime and dev_err_probe(), eliminating
     the remaining goto error labels entirely.

  6. Introduce a local 'dev' variable and migrate to
     device_is_compatible() for firmware-agnostic matching.

  7. Introduce MXC_ICR_REG/MXC_ICR_MASK macros and use
     field_prep()/field_get() for ICR register access, replacing
     duplicated magic-number arithmetic in gpio_set_irq_type() and
     mxc_flip_edge().

  8. Replace open-coded '1 << n' with BIT() throughout the driver.

  9. Simplify gpio_set_wake_irq() using irq_set_irq_wake() and
     assign_bit().

Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
Peng Fan (9):
      gpio: mxc: fix race between chained IRQ handler install and probe completion
      gpio: mxc: fix wakeup_pads bit operations for correctness
      gpio: mxc: cache compatible checks at probe time
      gpio: mxc: use devm action for irq_domain cleanup
      gpio: mxc: use devres-managed PM runtime and dev_err_probe
      gpio: mxc: use local dev variable and device_is_compatible()
      gpio: mxc: introduce MXC_ICR macros and use field_prep/field_get
      gpio: mxc: use BIT() macro for single-bit operations
      gpio: mxc: simplify gpio_set_wake_irq() with irq_set_irq_wake and assign_bit

 drivers/gpio/gpio-mxc.c | 158 ++++++++++++++++++++++++------------------------
 1 file changed, 79 insertions(+), 79 deletions(-)
---
base-commit: f0406245cb9855e6318335a8a223551354291a46
change-id: 20261003-gpio-mxc-cleanup-e49cc626c51e

Best regards,
--  
Peng Fan <peng.fan@nxp.com>


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 1/9] gpio: mxc: fix race between chained IRQ handler install and probe completion
  2026-10-03 12:06 [PATCH 0/9] gpio: mxc: bug fixes and probe cleanup Peng Fan (OSS)
@ 2026-10-03 12:06 ` Peng Fan (OSS)
  2026-10-03 17:35   ` Andy Shevchenko
  2026-10-03 12:06 ` [PATCH 2/9] gpio: mxc: fix wakeup_pads bit operations for correctness Peng Fan (OSS)
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 20+ messages in thread
From: Peng Fan (OSS) @ 2026-10-03 12:06 UTC (permalink / raw)
  To: Linus Walleij, Bartosz Golaszewski, Frank Li, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, Shenwei Wang,
	Andy Shevchenko
  Cc: linux-gpio, imx, linux-arm-kernel, linux-kernel, Peng Fan

From: Peng Fan <peng.fan@nxp.com>

mxc_update_irq_chained_handler() is called before the IRQ domain, the
generic IRQ chip, and the port list entry are set up. If an interrupt
arrives in that window:

 - mx3_gpio_irq_handler() calls generic_handle_domain_irq() with
   port->domain still NULL.
 - mx2_gpio_irq_handler() walks mxc_gpio_ports, but the port has not
   been added to the list yet.

Additionally, if any of the subsequent probe steps (gpio_generic_chip_init,
devm_gpiochip_add_data, irq_domain_create_legacy, or mxc_gpio_init_gc)
fail, the error paths never unregister the chained handler, leaving a
dangling handler that points at freed memory.

Move the handler installation after all its dependencies are ready and
after list_add_tail(), so the handler is never live while the data
structures it touches are incomplete, and is never installed if probe
fails.

Fixes: 5f6d1998adeb ("gpio: mxc: release the parent IRQ in runtime suspend")
Assisted-by: LLM
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
 drivers/gpio/gpio-mxc.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c
index 7e2690d92df6..e05f276a50e8 100644
--- a/drivers/gpio/gpio-mxc.c
+++ b/drivers/gpio/gpio-mxc.c
@@ -474,8 +474,6 @@ static int mxc_gpio_probe(struct platform_device *pdev)
 	} else
 		port->mx_irq_handler = mx3_gpio_irq_handler;
 
-	mxc_update_irq_chained_handler(port, true);
-
 	config.dev = &pdev->dev;
 	config.sz = 4;
 	config.dat = port->base + GPIO_PSR;
@@ -525,6 +523,8 @@ static int mxc_gpio_probe(struct platform_device *pdev)
 
 	list_add_tail(&port->node, &mxc_gpio_ports);
 
+	mxc_update_irq_chained_handler(port, true);
+
 	platform_set_drvdata(pdev, port);
 	pm_runtime_put_autosuspend(&pdev->dev);
 

-- 
2.51.0


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 2/9] gpio: mxc: fix wakeup_pads bit operations for correctness
  2026-10-03 12:06 [PATCH 0/9] gpio: mxc: bug fixes and probe cleanup Peng Fan (OSS)
  2026-10-03 12:06 ` [PATCH 1/9] gpio: mxc: fix race between chained IRQ handler install and probe completion Peng Fan (OSS)
@ 2026-10-03 12:06 ` Peng Fan (OSS)
  2026-10-03 17:41   ` Andy Shevchenko
  2026-10-03 12:06 ` [PATCH 3/9] gpio: mxc: cache compatible checks at probe time Peng Fan (OSS)
                   ` (6 subsequent siblings)
  8 siblings, 1 reply; 20+ messages in thread
From: Peng Fan (OSS) @ 2026-10-03 12:06 UTC (permalink / raw)
  To: Linus Walleij, Bartosz Golaszewski, Frank Li, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, Shenwei Wang,
	Andy Shevchenko
  Cc: linux-gpio, imx, linux-arm-kernel, linux-kernel, Peng Fan

From: Peng Fan <peng.fan@nxp.com>

Replace the open-coded BIT() / mask operations with the atomic
set_bit() / clear_bit() / test_bit() API. Atomic variants are required
because gpio_set_wake_irq() can be called concurrently for different
pins on the same port - irq_set_irq_wake() only holds the per-IRQ
descriptor lock, not a per-port lock, so concurrent modification of
different bits in wakeup_pads is possible.

However wakeup_pads field is typed as u32 but accessed via set_bit() /
clear_bit() / test_bit() which operate on unsigned long pointers. On
64-bit platforms this causes an 8-byte read-modify-write on a 4-byte
field, corrupting the adjacent is_pad_wakeup field.

Change wakeup_pads from u32 to unsigned long to match the bitops API
width requirements.

Also fix the disable path to only clear the wakeup_pads bit when
disable_irq_wake() succeeds, matching the enable path which already
checks the return value. Previously, a failed disable_irq_wake() would
still clear the bit, causing the driver to lose track of the wakeup
source.

Also fix a latent signed-shift bug: the old (1 << i) expression in
mxc_gpio_set_pad_wakeup() has implementation-defined behavior when
i == 31, since 1 is a signed int.

Fixes: f60c9eac54af ("gpio: mxc: enable pad wakeup on i.MX8x platforms")
Assisted-by: LLM
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
 drivers/gpio/gpio-mxc.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c
index e05f276a50e8..8a755ac1af83 100644
--- a/drivers/gpio/gpio-mxc.c
+++ b/drivers/gpio/gpio-mxc.c
@@ -71,7 +71,7 @@ struct mxc_gpio_port {
 	u32 both_edges;
 	struct mxc_gpio_reg_saved gpio_saved_reg;
 	bool power_off;
-	u32 wakeup_pads;
+	unsigned long wakeup_pads;
 	bool is_pad_wakeup;
 	u32 pad_type[32];
 	const struct mxc_gpio_hwdata *hwdata;
@@ -330,13 +330,15 @@ static int gpio_set_wake_irq(struct irq_data *d, u32 enable)
 			ret = enable_irq_wake(port->irq_high);
 		else
 			ret = enable_irq_wake(port->irq);
-		port->wakeup_pads |= BIT(gpio_idx);
+		if (!ret)
+			set_bit(gpio_idx, &port->wakeup_pads);
 	} else {
 		if (port->irq_high && (gpio_idx >= 16))
 			ret = disable_irq_wake(port->irq_high);
 		else
 			ret = disable_irq_wake(port->irq);
-		port->wakeup_pads &= ~BIT(gpio_idx);
+		if (!ret)
+			clear_bit(gpio_idx, &port->wakeup_pads);
 	}
 
 	return ret;
@@ -599,7 +601,7 @@ static bool mxc_gpio_set_pad_wakeup(struct mxc_gpio_port *port, bool enable)
 	};
 
 	for (i = 0; i < 32; i++) {
-		if ((port->wakeup_pads & (1 << i))) {
+		if (test_bit(i, &port->wakeup_pads)) {
 			type = port->pad_type[i];
 			if (enable)
 				config = pad_type_map[type];

-- 
2.51.0


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 3/9] gpio: mxc: cache compatible checks at probe time
  2026-10-03 12:06 [PATCH 0/9] gpio: mxc: bug fixes and probe cleanup Peng Fan (OSS)
  2026-10-03 12:06 ` [PATCH 1/9] gpio: mxc: fix race between chained IRQ handler install and probe completion Peng Fan (OSS)
  2026-10-03 12:06 ` [PATCH 2/9] gpio: mxc: fix wakeup_pads bit operations for correctness Peng Fan (OSS)
@ 2026-10-03 12:06 ` Peng Fan (OSS)
  2026-10-03 17:45   ` Andy Shevchenko
  2026-10-04  3:06   ` Frank Li
  2026-10-03 12:06 ` [PATCH 4/9] gpio: mxc: use devm action for irq_domain cleanup Peng Fan (OSS)
                   ` (5 subsequent siblings)
  8 siblings, 2 replies; 20+ messages in thread
From: Peng Fan (OSS) @ 2026-10-03 12:06 UTC (permalink / raw)
  To: Linus Walleij, Bartosz Golaszewski, Frank Li, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, Shenwei Wang,
	Andy Shevchenko
  Cc: linux-gpio, imx, linux-arm-kernel, linux-kernel, Peng Fan

From: Peng Fan <peng.fan@nxp.com>

mxc_gpio_generic_config() and mxc_gpio_set_pad_wakeup() call
of_device_is_compatible() on every invocation to determine pad wakeup
capability and i.MX8QM-specific behavior. These properties are
invariant for the lifetime of the device.

Cache them as bool fields (has_pad_wakeup, is_imx8qm) in mxc_gpio_port
during probe, eliminating repeated device tree string comparisons in
the suspend/resume hot path.

Assisted-by: LLM
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
 drivers/gpio/gpio-mxc.c | 24 ++++++++++++++----------
 1 file changed, 14 insertions(+), 10 deletions(-)

diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c
index 8a755ac1af83..1c27232f6a80 100644
--- a/drivers/gpio/gpio-mxc.c
+++ b/drivers/gpio/gpio-mxc.c
@@ -73,6 +73,8 @@ struct mxc_gpio_port {
 	bool power_off;
 	unsigned long wakeup_pads;
 	bool is_pad_wakeup;
+	bool has_pad_wakeup;
+	bool is_imx8qm;
 	u32 pad_type[32];
 	const struct mxc_gpio_hwdata *hwdata;
 };
@@ -457,6 +459,14 @@ static int mxc_gpio_probe(struct platform_device *pdev)
 	if (of_device_is_compatible(np, "fsl,imx7d-gpio"))
 		port->power_off = true;
 
+	if (of_device_is_compatible(np, "fsl,imx8dxl-gpio") ||
+	    of_device_is_compatible(np, "fsl,imx8qxp-gpio") ||
+	    of_device_is_compatible(np, "fsl,imx8qm-gpio"))
+		port->has_pad_wakeup = true;
+
+	if (of_device_is_compatible(np, "fsl,imx8qm-gpio"))
+		port->is_imx8qm = true;
+
 	pm_runtime_get_noresume(&pdev->dev);
 	pm_runtime_set_active(&pdev->dev);
 	pm_runtime_enable(&pdev->dev);
@@ -570,15 +580,10 @@ static void mxc_gpio_restore_regs(struct mxc_gpio_port *port)
 static bool mxc_gpio_generic_config(struct mxc_gpio_port *port,
 		unsigned int offset, unsigned long conf)
 {
-	struct device_node *np = port->dev->of_node;
-
-	if (of_device_is_compatible(np, "fsl,imx8dxl-gpio") ||
-	    of_device_is_compatible(np, "fsl,imx8qxp-gpio") ||
-	    of_device_is_compatible(np, "fsl,imx8qm-gpio"))
-		return (gpiochip_generic_config(&port->gen_gc.gc,
-						offset, conf) == 0);
+	if (!port->has_pad_wakeup)
+		return false;
 
-	return false;
+	return (gpiochip_generic_config(&port->gen_gc.gc, offset, conf) == 0);
 }
 
 static bool mxc_gpio_set_pad_wakeup(struct mxc_gpio_port *port, bool enable)
@@ -586,7 +591,6 @@ static bool mxc_gpio_set_pad_wakeup(struct mxc_gpio_port *port, bool enable)
 	unsigned long config;
 	bool ret = false;
 	int i, type;
-	bool is_imx8qm = of_device_is_compatible(port->dev->of_node, "fsl,imx8qm-gpio");
 
 	static const u32 pad_type_map[] = {
 		IMX_SCU_WAKEUP_OFF,		/* 0 */
@@ -608,7 +612,7 @@ static bool mxc_gpio_set_pad_wakeup(struct mxc_gpio_port *port, bool enable)
 			else
 				config = IMX_SCU_WAKEUP_OFF;
 
-			if (is_imx8qm && config == IMX_SCU_WAKEUP_FALL_EDGE) {
+			if (port->is_imx8qm && config == IMX_SCU_WAKEUP_FALL_EDGE) {
 				dev_warn_once(port->dev,
 					      "No falling-edge support for wakeup on i.MX8QM\n");
 				config = IMX_SCU_WAKEUP_OFF;

-- 
2.51.0


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 4/9] gpio: mxc: use devm action for irq_domain cleanup
  2026-10-03 12:06 [PATCH 0/9] gpio: mxc: bug fixes and probe cleanup Peng Fan (OSS)
                   ` (2 preceding siblings ...)
  2026-10-03 12:06 ` [PATCH 3/9] gpio: mxc: cache compatible checks at probe time Peng Fan (OSS)
@ 2026-10-03 12:06 ` Peng Fan (OSS)
  2026-10-03 17:48   ` Andy Shevchenko
  2026-10-04  3:32   ` Frank Li
  2026-10-03 12:06 ` [PATCH 5/9] gpio: mxc: use devres-managed PM runtime and dev_err_probe Peng Fan (OSS)
                   ` (4 subsequent siblings)
  8 siblings, 2 replies; 20+ messages in thread
From: Peng Fan (OSS) @ 2026-10-03 12:06 UTC (permalink / raw)
  To: Linus Walleij, Bartosz Golaszewski, Frank Li, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, Shenwei Wang,
	Andy Shevchenko
  Cc: linux-gpio, imx, linux-arm-kernel, linux-kernel, Peng Fan

From: Peng Fan <peng.fan@nxp.com>

Replace the manual irq_domain_remove() error path with
devm_add_action_or_reset(), so the IRQ domain is cleaned up
automatically on both probe failure to eliminate the
out_irqdomain_remove goto label.

Assisted-by: LLM
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
 drivers/gpio/gpio-mxc.c | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c
index 1c27232f6a80..3c395c82d7d4 100644
--- a/drivers/gpio/gpio-mxc.c
+++ b/drivers/gpio/gpio-mxc.c
@@ -417,6 +417,13 @@ static void mxc_update_irq_chained_handler(struct mxc_gpio_port *port, bool enab
 	}
 }
 
+static void mxc_gpio_irq_domain_remove(void *data)
+{
+	struct irq_domain *domain = data;
+
+	irq_domain_remove(domain);
+}
+
 static int mxc_gpio_probe(struct platform_device *pdev)
 {
 	struct gpio_generic_chip_config config = { };
@@ -526,12 +533,16 @@ static int mxc_gpio_probe(struct platform_device *pdev)
 		goto out_bgio;
 	}
 
+	err = devm_add_action_or_reset(&pdev->dev, mxc_gpio_irq_domain_remove, port->domain);
+	if (err)
+		goto out_bgio;
+
 	irq_domain_set_pm_device(port->domain, &pdev->dev);
 
 	/* gpio-mxc can be a generic irq chip */
 	err = mxc_gpio_init_gc(port, irq_base);
 	if (err < 0)
-		goto out_irqdomain_remove;
+		goto out_bgio;
 
 	list_add_tail(&port->node, &mxc_gpio_ports);
 
@@ -542,8 +553,6 @@ static int mxc_gpio_probe(struct platform_device *pdev)
 
 	return 0;
 
-out_irqdomain_remove:
-	irq_domain_remove(port->domain);
 out_bgio:
 	pm_runtime_disable(&pdev->dev);
 	pm_runtime_put_noidle(&pdev->dev);

-- 
2.51.0


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 5/9] gpio: mxc: use devres-managed PM runtime and dev_err_probe
  2026-10-03 12:06 [PATCH 0/9] gpio: mxc: bug fixes and probe cleanup Peng Fan (OSS)
                   ` (3 preceding siblings ...)
  2026-10-03 12:06 ` [PATCH 4/9] gpio: mxc: use devm action for irq_domain cleanup Peng Fan (OSS)
@ 2026-10-03 12:06 ` Peng Fan (OSS)
  2026-10-03 17:52   ` Andy Shevchenko
  2026-10-04  3:00   ` Frank Li
  2026-10-03 12:06 ` [PATCH 6/9] gpio: mxc: use local dev variable and device_is_compatible() Peng Fan (OSS)
                   ` (3 subsequent siblings)
  8 siblings, 2 replies; 20+ messages in thread
From: Peng Fan (OSS) @ 2026-10-03 12:06 UTC (permalink / raw)
  To: Linus Walleij, Bartosz Golaszewski, Frank Li, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, Shenwei Wang,
	Andy Shevchenko
  Cc: linux-gpio, imx, linux-arm-kernel, linux-kernel, Peng Fan

From: Peng Fan <peng.fan@nxp.com>

Switch pm_runtime_get_noresume() and pm_runtime_enable() to their
devm-managed variants so that pm_runtime_put_noidle() and
pm_runtime_disable() are handled automatically by devres on both
probe failure and device unbind.

Remove the out_bgio goto label and replacing all error paths with
direct returns using dev_err_probe(), which provides better
diagnostic output and handles -EPROBE_DEFER.

Assisted-by: LLM
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
 drivers/gpio/gpio-mxc.c | 30 ++++++++++--------------------
 1 file changed, 10 insertions(+), 20 deletions(-)

diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c
index 3c395c82d7d4..73e19d2bf235 100644
--- a/drivers/gpio/gpio-mxc.c
+++ b/drivers/gpio/gpio-mxc.c
@@ -474,9 +474,9 @@ static int mxc_gpio_probe(struct platform_device *pdev)
 	if (of_device_is_compatible(np, "fsl,imx8qm-gpio"))
 		port->is_imx8qm = true;
 
-	pm_runtime_get_noresume(&pdev->dev);
+	devm_pm_runtime_get_noresume(&pdev->dev);
 	pm_runtime_set_active(&pdev->dev);
-	pm_runtime_enable(&pdev->dev);
+	devm_pm_runtime_enable(&pdev->dev);
 
 	/* disable the interrupt and clear the status */
 	writel(0, port->base + GPIO_IMR);
@@ -502,7 +502,7 @@ static int mxc_gpio_probe(struct platform_device *pdev)
 
 	err = gpio_generic_chip_init(&port->gen_gc, &config);
 	if (err)
-		goto out_bgio;
+		return dev_err_probe(&pdev->dev, err, "Failed to init gpio chip\n");
 
 	port->gen_gc.gc.request = mxc_gpio_request;
 	port->gen_gc.gc.free = mxc_gpio_free;
@@ -518,31 +518,27 @@ static int mxc_gpio_probe(struct platform_device *pdev)
 
 	err = devm_gpiochip_add_data(&pdev->dev, &port->gen_gc.gc, port);
 	if (err)
-		goto out_bgio;
+		return dev_err_probe(&pdev->dev, err, "Failed to add gpiochip data\n");
 
 	irq_base = devm_irq_alloc_descs(&pdev->dev, -1, 0, 32, numa_node_id());
-	if (irq_base < 0) {
-		err = irq_base;
-		goto out_bgio;
-	}
+	if (irq_base < 0)
+		return dev_err_probe(&pdev->dev, irq_base, "Failed to alloc irq desc\n");
 
 	port->domain = irq_domain_create_legacy(dev_fwnode(&pdev->dev), 32, irq_base, 0,
 						&irq_domain_simple_ops, NULL);
-	if (!port->domain) {
-		err = -ENODEV;
-		goto out_bgio;
-	}
+	if (!port->domain)
+		return dev_err_probe(&pdev->dev, -ENODEV, "Failed to create irq domain\n");
 
 	err = devm_add_action_or_reset(&pdev->dev, mxc_gpio_irq_domain_remove, port->domain);
 	if (err)
-		goto out_bgio;
+		return dev_err_probe(&pdev->dev, err, "Failed to add irq_domain_remove\n");
 
 	irq_domain_set_pm_device(port->domain, &pdev->dev);
 
 	/* gpio-mxc can be a generic irq chip */
 	err = mxc_gpio_init_gc(port, irq_base);
 	if (err < 0)
-		goto out_bgio;
+		return dev_err_probe(&pdev->dev, err, "Failed mxc_gpio_init_gc\n");
 
 	list_add_tail(&port->node, &mxc_gpio_ports);
 
@@ -552,12 +548,6 @@ static int mxc_gpio_probe(struct platform_device *pdev)
 	pm_runtime_put_autosuspend(&pdev->dev);
 
 	return 0;
-
-out_bgio:
-	pm_runtime_disable(&pdev->dev);
-	pm_runtime_put_noidle(&pdev->dev);
-	dev_info(&pdev->dev, "%s failed with errno %d\n", __func__, err);
-	return err;
 }
 
 static void mxc_gpio_save_regs(struct mxc_gpio_port *port)

-- 
2.51.0


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 6/9] gpio: mxc: use local dev variable and device_is_compatible()
  2026-10-03 12:06 [PATCH 0/9] gpio: mxc: bug fixes and probe cleanup Peng Fan (OSS)
                   ` (4 preceding siblings ...)
  2026-10-03 12:06 ` [PATCH 5/9] gpio: mxc: use devres-managed PM runtime and dev_err_probe Peng Fan (OSS)
@ 2026-10-03 12:06 ` Peng Fan (OSS)
  2026-10-03 17:54   ` Andy Shevchenko
  2026-10-03 12:06 ` [PATCH 7/9] gpio: mxc: introduce MXC_ICR macros and use field_prep/field_get Peng Fan (OSS)
                   ` (2 subsequent siblings)
  8 siblings, 1 reply; 20+ messages in thread
From: Peng Fan (OSS) @ 2026-10-03 12:06 UTC (permalink / raw)
  To: Linus Walleij, Bartosz Golaszewski, Frank Li, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, Shenwei Wang,
	Andy Shevchenko
  Cc: linux-gpio, imx, linux-arm-kernel, linux-kernel, Peng Fan

From: Peng Fan <peng.fan@nxp.com>

Introduce a local 'struct device *dev' variable to replace repeated
'&pdev->dev' dereferences throughout mxc_gpio_probe(), improving
readability.

Switch from of_device_is_compatible(np, ...) to the device-model
device_is_compatible(dev, ...) API which works with both DT and ACPI
firmware backends. The 'np' variable is retained for
of_alias_get_id() which has no device-model equivalent.

No functional change.

Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
 drivers/gpio/gpio-mxc.c | 53 +++++++++++++++++++++++++------------------------
 1 file changed, 27 insertions(+), 26 deletions(-)

diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c
index 73e19d2bf235..a3274be7126a 100644
--- a/drivers/gpio/gpio-mxc.c
+++ b/drivers/gpio/gpio-mxc.c
@@ -428,17 +428,18 @@ static int mxc_gpio_probe(struct platform_device *pdev)
 {
 	struct gpio_generic_chip_config config = { };
 	struct device_node *np = pdev->dev.of_node;
+	struct device *dev = &pdev->dev;
 	struct mxc_gpio_port *port;
 	int irq_count;
 	int irq_base;
 	int err;
 
-	port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL);
+	port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
 	if (!port)
 		return -ENOMEM;
 
-	port->dev = &pdev->dev;
-	port->hwdata = device_get_match_data(&pdev->dev);
+	port->dev = dev;
+	port->hwdata = device_get_match_data(dev);
 
 	port->base = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(port->base))
@@ -459,30 +460,30 @@ static int mxc_gpio_probe(struct platform_device *pdev)
 		return port->irq;
 
 	/* the controller clock is optional */
-	port->clk = devm_clk_get_optional_enabled(&pdev->dev, NULL);
+	port->clk = devm_clk_get_optional_enabled(dev, NULL);
 	if (IS_ERR(port->clk))
 		return PTR_ERR(port->clk);
 
-	if (of_device_is_compatible(np, "fsl,imx7d-gpio"))
+	if (device_is_compatible(dev, "fsl,imx7d-gpio"))
 		port->power_off = true;
 
-	if (of_device_is_compatible(np, "fsl,imx8dxl-gpio") ||
-	    of_device_is_compatible(np, "fsl,imx8qxp-gpio") ||
-	    of_device_is_compatible(np, "fsl,imx8qm-gpio"))
+	if (device_is_compatible(dev, "fsl,imx8dxl-gpio") ||
+	    device_is_compatible(dev, "fsl,imx8qxp-gpio") ||
+	    device_is_compatible(dev, "fsl,imx8qm-gpio"))
 		port->has_pad_wakeup = true;
 
-	if (of_device_is_compatible(np, "fsl,imx8qm-gpio"))
+	if (device_is_compatible(dev, "fsl,imx8qm-gpio"))
 		port->is_imx8qm = true;
 
-	devm_pm_runtime_get_noresume(&pdev->dev);
-	pm_runtime_set_active(&pdev->dev);
-	devm_pm_runtime_enable(&pdev->dev);
+	devm_pm_runtime_get_noresume(dev);
+	pm_runtime_set_active(dev);
+	devm_pm_runtime_enable(dev);
 
 	/* disable the interrupt and clear the status */
 	writel(0, port->base + GPIO_IMR);
 	writel(~0, port->base + GPIO_ISR);
 
-	if (of_device_is_compatible(np, "fsl,imx21-gpio")) {
+	if (device_is_compatible(dev, "fsl,imx21-gpio")) {
 		/*
 		 * Setup one handler for all GPIO interrupts. Actually setting
 		 * the handler is needed only once, but doing it for every port
@@ -493,7 +494,7 @@ static int mxc_gpio_probe(struct platform_device *pdev)
 	} else
 		port->mx_irq_handler = mx3_gpio_irq_handler;
 
-	config.dev = &pdev->dev;
+	config.dev = dev;
 	config.sz = 4;
 	config.dat = port->base + GPIO_PSR;
 	config.set = port->base + GPIO_DR;
@@ -502,7 +503,7 @@ static int mxc_gpio_probe(struct platform_device *pdev)
 
 	err = gpio_generic_chip_init(&port->gen_gc, &config);
 	if (err)
-		return dev_err_probe(&pdev->dev, err, "Failed to init gpio chip\n");
+		return dev_err_probe(dev, err, "Failed to init gpio chip\n");
 
 	port->gen_gc.gc.request = mxc_gpio_request;
 	port->gen_gc.gc.free = mxc_gpio_free;
@@ -516,36 +517,36 @@ static int mxc_gpio_probe(struct platform_device *pdev)
 	else /* silence boot time warning */
 		port->gen_gc.gc.base = -1;
 
-	err = devm_gpiochip_add_data(&pdev->dev, &port->gen_gc.gc, port);
+	err = devm_gpiochip_add_data(dev, &port->gen_gc.gc, port);
 	if (err)
-		return dev_err_probe(&pdev->dev, err, "Failed to add gpiochip data\n");
+		return dev_err_probe(dev, err, "Failed to add gpiochip data\n");
 
-	irq_base = devm_irq_alloc_descs(&pdev->dev, -1, 0, 32, numa_node_id());
+	irq_base = devm_irq_alloc_descs(dev, -1, 0, 32, numa_node_id());
 	if (irq_base < 0)
-		return dev_err_probe(&pdev->dev, irq_base, "Failed to alloc irq desc\n");
+		return dev_err_probe(dev, irq_base, "Failed to alloc irq desc\n");
 
-	port->domain = irq_domain_create_legacy(dev_fwnode(&pdev->dev), 32, irq_base, 0,
+	port->domain = irq_domain_create_legacy(dev_fwnode(dev), 32, irq_base, 0,
 						&irq_domain_simple_ops, NULL);
 	if (!port->domain)
-		return dev_err_probe(&pdev->dev, -ENODEV, "Failed to create irq domain\n");
+		return dev_err_probe(dev, -ENODEV, "Failed to create irq domain\n");
 
-	err = devm_add_action_or_reset(&pdev->dev, mxc_gpio_irq_domain_remove, port->domain);
+	err = devm_add_action_or_reset(dev, mxc_gpio_irq_domain_remove, port->domain);
 	if (err)
-		return dev_err_probe(&pdev->dev, err, "Failed to add irq_domain_remove\n");
+		return dev_err_probe(dev, err, "Failed to add irq_domain_remove\n");
 
-	irq_domain_set_pm_device(port->domain, &pdev->dev);
+	irq_domain_set_pm_device(port->domain, dev);
 
 	/* gpio-mxc can be a generic irq chip */
 	err = mxc_gpio_init_gc(port, irq_base);
 	if (err < 0)
-		return dev_err_probe(&pdev->dev, err, "Failed mxc_gpio_init_gc\n");
+		return dev_err_probe(dev, err, "Failed mxc_gpio_init_gc\n");
 
 	list_add_tail(&port->node, &mxc_gpio_ports);
 
 	mxc_update_irq_chained_handler(port, true);
 
 	platform_set_drvdata(pdev, port);
-	pm_runtime_put_autosuspend(&pdev->dev);
+	pm_runtime_put_autosuspend(dev);
 
 	return 0;
 }

-- 
2.51.0


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 7/9] gpio: mxc: introduce MXC_ICR macros and use field_prep/field_get
  2026-10-03 12:06 [PATCH 0/9] gpio: mxc: bug fixes and probe cleanup Peng Fan (OSS)
                   ` (5 preceding siblings ...)
  2026-10-03 12:06 ` [PATCH 6/9] gpio: mxc: use local dev variable and device_is_compatible() Peng Fan (OSS)
@ 2026-10-03 12:06 ` Peng Fan (OSS)
  2026-10-03 12:06 ` [PATCH 8/9] gpio: mxc: use BIT() macro for single-bit operations Peng Fan (OSS)
  2026-10-03 12:06 ` [PATCH 9/9] gpio: mxc: simplify gpio_set_wake_irq() with irq_set_irq_wake and assign_bit Peng Fan (OSS)
  8 siblings, 0 replies; 20+ messages in thread
From: Peng Fan (OSS) @ 2026-10-03 12:06 UTC (permalink / raw)
  To: Linus Walleij, Bartosz Golaszewski, Frank Li, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, Shenwei Wang,
	Andy Shevchenko
  Cc: linux-gpio, imx, linux-arm-kernel, linux-kernel, Peng Fan

From: Peng Fan <peng.fan@nxp.com>

Both gpio_set_irq_type() and mxc_flip_edge() open-code the same ICR
register selection and 2-bit field shift/mask arithmetic with magic
numbers (0x10, 0xf, 0x3).

Introduce two macros:
  - MXC_ICR_REG(gpio):  selects ICR1 (pins 0-15) or ICR2 (pins 16-31)
  - MXC_ICR_MASK(gpio): 2-bit mask at the correct position

Use field_prep() and field_get() from linux/bitfield.h for the
shift/extract operations instead of open-coded shifts. The lowercase
variants accept runtime-computed masks.

Eliminate the intermediate 'bit' variable from both functions and
makes the register access pattern self-documenting.

No functional change.

Assisted-by: LLM
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
 drivers/gpio/gpio-mxc.c | 24 +++++++++++++-----------
 1 file changed, 13 insertions(+), 11 deletions(-)

diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c
index a3274be7126a..18ff33a0abfb 100644
--- a/drivers/gpio/gpio-mxc.c
+++ b/drivers/gpio/gpio-mxc.c
@@ -7,6 +7,7 @@
 // Authors: Daniel Mack, Juergen Beisert.
 // Copyright (C) 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved.
 
+#include <linux/bitfield.h>
 #include <linux/cleanup.h>
 #include <linux/clk.h>
 #include <linux/err.h>
@@ -139,6 +140,9 @@ static struct mxc_gpio_hwdata imx35_gpio_hwdata = {
 #define GPIO_INT_FALL_EDGE	(port->hwdata->fall_edge)
 #define GPIO_INT_BOTH_EDGES	0x4
 
+#define MXC_ICR_REG(gpio)	(GPIO_ICR1 + (((gpio) & 0x10) >> 2))
+#define MXC_ICR_MASK(gpio)	(0x3 << (((gpio) & 0xf) << 1))
+
 static const struct of_device_id mxc_gpio_dt_ids[] = {
 	{ .compatible = "fsl,imx1-gpio", .data =  &imx1_imx21_gpio_hwdata },
 	{ .compatible = "fsl,imx21-gpio", .data = &imx1_imx21_gpio_hwdata },
@@ -165,7 +169,7 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type)
 {
 	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
 	struct mxc_gpio_port *port = gc->private;
-	u32 bit, val;
+	u32 val;
 	u32 gpio_idx = d->hwirq;
 	int edge;
 	void __iomem *reg = port->base;
@@ -215,10 +219,9 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type)
 		}
 
 		if (edge != GPIO_INT_BOTH_EDGES) {
-			reg += GPIO_ICR1 + ((gpio_idx & 0x10) >> 2); /* lower or upper register */
-			bit = gpio_idx & 0xf;
-			val = readl(reg) & ~(0x3 << (bit << 1));
-			writel(val | (edge << (bit << 1)), reg);
+			reg += MXC_ICR_REG(gpio_idx);
+			val = readl(reg) & ~MXC_ICR_MASK(gpio_idx);
+			writel(val | field_prep(MXC_ICR_MASK(gpio_idx), edge), reg);
 		}
 
 		writel(1 << gpio_idx, port->base + GPIO_ISR);
@@ -231,16 +234,15 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type)
 static void mxc_flip_edge(struct mxc_gpio_port *port, u32 gpio)
 {
 	void __iomem *reg = port->base;
-	u32 bit, val;
+	u32 val;
 	int edge;
 
 	guard(gpio_generic_lock_irqsave)(&port->gen_gc);
 
-	reg += GPIO_ICR1 + ((gpio & 0x10) >> 2); /* lower or upper register */
-	bit = gpio & 0xf;
+	reg += MXC_ICR_REG(gpio);
 	val = readl(reg);
-	edge = (val >> (bit << 1)) & 3;
-	val &= ~(0x3 << (bit << 1));
+	edge = field_get(MXC_ICR_MASK(gpio), val);
+	val &= ~MXC_ICR_MASK(gpio);
 	if (edge == GPIO_INT_HIGH_LEV) {
 		edge = GPIO_INT_LOW_LEV;
 		pr_debug("mxc: switch GPIO %d to low trigger\n", gpio);
@@ -252,7 +254,7 @@ static void mxc_flip_edge(struct mxc_gpio_port *port, u32 gpio)
 		       gpio, edge);
 		return;
 	}
-	writel(val | (edge << (bit << 1)), reg);
+	writel(val | field_prep(MXC_ICR_MASK(gpio), edge), reg);
 }
 
 /* handle 32 interrupts in one status register */

-- 
2.51.0


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 8/9] gpio: mxc: use BIT() macro for single-bit operations
  2026-10-03 12:06 [PATCH 0/9] gpio: mxc: bug fixes and probe cleanup Peng Fan (OSS)
                   ` (6 preceding siblings ...)
  2026-10-03 12:06 ` [PATCH 7/9] gpio: mxc: introduce MXC_ICR macros and use field_prep/field_get Peng Fan (OSS)
@ 2026-10-03 12:06 ` Peng Fan (OSS)
  2026-10-03 12:06 ` [PATCH 9/9] gpio: mxc: simplify gpio_set_wake_irq() with irq_set_irq_wake and assign_bit Peng Fan (OSS)
  8 siblings, 0 replies; 20+ messages in thread
From: Peng Fan (OSS) @ 2026-10-03 12:06 UTC (permalink / raw)
  To: Linus Walleij, Bartosz Golaszewski, Frank Li, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, Shenwei Wang,
	Andy Shevchenko
  Cc: linux-gpio, imx, linux-arm-kernel, linux-kernel, Peng Fan

From: Peng Fan <peng.fan@nxp.com>

Replace open-coded '1 << n' shifts with the BIT() macro throughout
the driver for consistency and to avoid potential signed-shift issues
when the bit index is 31 (1 << 31 is implementation-defined for
signed int).

No functional change.

Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
 drivers/gpio/gpio-mxc.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c
index 18ff33a0abfb..bf1207f30460 100644
--- a/drivers/gpio/gpio-mxc.c
+++ b/drivers/gpio/gpio-mxc.c
@@ -174,7 +174,7 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type)
 	int edge;
 	void __iomem *reg = port->base;
 
-	port->both_edges &= ~(1 << gpio_idx);
+	port->both_edges &= ~BIT(gpio_idx);
 	switch (type) {
 	case IRQ_TYPE_EDGE_RISING:
 		edge = GPIO_INT_RISE_EDGE;
@@ -194,7 +194,7 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type)
 				edge = GPIO_INT_HIGH_LEV;
 				pr_debug("mxc: set GPIO %d to high trigger\n", gpio_idx);
 			}
-			port->both_edges |= 1 << gpio_idx;
+			port->both_edges |= BIT(gpio_idx);
 		}
 		break;
 	case IRQ_TYPE_LEVEL_LOW:
@@ -211,10 +211,10 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type)
 		if (GPIO_EDGE_SEL >= 0) {
 			val = readl(port->base + GPIO_EDGE_SEL);
 			if (edge == GPIO_INT_BOTH_EDGES)
-				writel(val | (1 << gpio_idx),
+				writel(val | BIT(gpio_idx),
 				       port->base + GPIO_EDGE_SEL);
 			else
-				writel(val & ~(1 << gpio_idx),
+				writel(val & ~BIT(gpio_idx),
 				       port->base + GPIO_EDGE_SEL);
 		}
 
@@ -224,7 +224,7 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type)
 			writel(val | field_prep(MXC_ICR_MASK(gpio_idx), edge), reg);
 		}
 
-		writel(1 << gpio_idx, port->base + GPIO_ISR);
+		writel(BIT(gpio_idx), port->base + GPIO_ISR);
 		port->pad_type[gpio_idx] = type;
 	}
 
@@ -263,12 +263,12 @@ static void mxc_gpio_irq_handler(struct mxc_gpio_port *port, u32 irq_stat)
 	while (irq_stat != 0) {
 		int irqoffset = fls(irq_stat) - 1;
 
-		if (port->both_edges & (1 << irqoffset))
+		if (port->both_edges & BIT(irqoffset))
 			mxc_flip_edge(port, irqoffset);
 
 		generic_handle_domain_irq(port->domain, irqoffset);
 
-		irq_stat &= ~(1 << irqoffset);
+		irq_stat &= ~BIT(irqoffset);
 	}
 }
 

-- 
2.51.0


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 9/9] gpio: mxc: simplify gpio_set_wake_irq() with irq_set_irq_wake and assign_bit
  2026-10-03 12:06 [PATCH 0/9] gpio: mxc: bug fixes and probe cleanup Peng Fan (OSS)
                   ` (7 preceding siblings ...)
  2026-10-03 12:06 ` [PATCH 8/9] gpio: mxc: use BIT() macro for single-bit operations Peng Fan (OSS)
@ 2026-10-03 12:06 ` Peng Fan (OSS)
  2026-10-03 17:59   ` Andy Shevchenko
  8 siblings, 1 reply; 20+ messages in thread
From: Peng Fan (OSS) @ 2026-10-03 12:06 UTC (permalink / raw)
  To: Linus Walleij, Bartosz Golaszewski, Frank Li, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, Shenwei Wang,
	Andy Shevchenko
  Cc: linux-gpio, imx, linux-arm-kernel, linux-kernel, Peng Fan

From: Peng Fan <peng.fan@nxp.com>

To simplify gpio_set_wake_irq():
 - Replace the enable/disable_irq_wake() if/else branches with a single
   irq_set_irq_wake() call which handles both directions internally.
 - Replace the separate set_bit()/clear_bit() calls with assign_bit()
   which sets or clears the bit based on the enable parameter.

Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
 drivers/gpio/gpio-mxc.c | 22 +++++++---------------
 1 file changed, 7 insertions(+), 15 deletions(-)

diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c
index bf1207f30460..546a46857e1d 100644
--- a/drivers/gpio/gpio-mxc.c
+++ b/drivers/gpio/gpio-mxc.c
@@ -329,21 +329,13 @@ static int gpio_set_wake_irq(struct irq_data *d, u32 enable)
 	u32 gpio_idx = d->hwirq;
 	int ret;
 
-	if (enable) {
-		if (port->irq_high && (gpio_idx >= 16))
-			ret = enable_irq_wake(port->irq_high);
-		else
-			ret = enable_irq_wake(port->irq);
-		if (!ret)
-			set_bit(gpio_idx, &port->wakeup_pads);
-	} else {
-		if (port->irq_high && (gpio_idx >= 16))
-			ret = disable_irq_wake(port->irq_high);
-		else
-			ret = disable_irq_wake(port->irq);
-		if (!ret)
-			clear_bit(gpio_idx, &port->wakeup_pads);
-	}
+	if (port->irq_high && (gpio_idx >= 16))
+		ret = irq_set_irq_wake(port->irq_high, enable);
+	else
+		ret = irq_set_irq_wake(port->irq, enable);
+
+	if (!ret)
+		assign_bit(gpio_idx, &port->wakeup_pads, enable);
 
 	return ret;
 }

-- 
2.51.0


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 1/9] gpio: mxc: fix race between chained IRQ handler install and probe completion
  2026-10-03 12:06 ` [PATCH 1/9] gpio: mxc: fix race between chained IRQ handler install and probe completion Peng Fan (OSS)
@ 2026-10-03 17:35   ` Andy Shevchenko
  0 siblings, 0 replies; 20+ messages in thread
From: Andy Shevchenko @ 2026-10-03 17:35 UTC (permalink / raw)
  To: Peng Fan (OSS)
  Cc: Linus Walleij, Bartosz Golaszewski, Frank Li, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, Shenwei Wang, linux-gpio,
	imx, linux-arm-kernel, linux-kernel, Peng Fan

On Sat, Oct 3, 2026 at 3:09 PM Peng Fan (OSS) <peng.fan@oss.nxp.com> wrote:

> mxc_update_irq_chained_handler() is called before the IRQ domain, the
> generic IRQ chip, and the port list entry are set up. If an interrupt
> arrives in that window:
>
>  - mx3_gpio_irq_handler() calls generic_handle_domain_irq() with
>    port->domain still NULL.
>  - mx2_gpio_irq_handler() walks mxc_gpio_ports, but the port has not
>    been added to the list yet.
>
> Additionally, if any of the subsequent probe steps (gpio_generic_chip_init,
> devm_gpiochip_add_data, irq_domain_create_legacy, or mxc_gpio_init_gc)

We refer to the functions as func(), like you have done above, but here...
(No need to resend just for this.)

> fail, the error paths never unregister the chained handler, leaving a
> dangling handler that points at freed memory.
>
> Move the handler installation after all its dependencies are ready and
> after list_add_tail(), so the handler is never live while the data
> structures it touches are incomplete, and is never installed if probe
> fails.

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 2/9] gpio: mxc: fix wakeup_pads bit operations for correctness
  2026-10-03 12:06 ` [PATCH 2/9] gpio: mxc: fix wakeup_pads bit operations for correctness Peng Fan (OSS)
@ 2026-10-03 17:41   ` Andy Shevchenko
  0 siblings, 0 replies; 20+ messages in thread
From: Andy Shevchenko @ 2026-10-03 17:41 UTC (permalink / raw)
  To: Peng Fan (OSS)
  Cc: Linus Walleij, Bartosz Golaszewski, Frank Li, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, Shenwei Wang, linux-gpio,
	imx, linux-arm-kernel, linux-kernel, Peng Fan

On Sat, Oct 3, 2026 at 3:09 PM Peng Fan (OSS) <peng.fan@oss.nxp.com> wrote:

> Replace the open-coded BIT() / mask operations with the atomic
> set_bit() / clear_bit() / test_bit() API. Atomic variants are required
> because gpio_set_wake_irq() can be called concurrently for different
> pins on the same port - irq_set_irq_wake() only holds the per-IRQ
> descriptor lock, not a per-port lock, so concurrent modification of
> different bits in wakeup_pads is possible.
>
> However wakeup_pads field is typed as u32 but accessed via set_bit() /
> clear_bit() / test_bit() which operate on unsigned long pointers. On
> 64-bit platforms this causes an 8-byte read-modify-write on a 4-byte
> field, corrupting the adjacent is_pad_wakeup field.
>
> Change wakeup_pads from u32 to unsigned long to match the bitops API
> width requirements.
>
> Also fix the disable path to only clear the wakeup_pads bit when
> disable_irq_wake() succeeds, matching the enable path which already
> checks the return value. Previously, a failed disable_irq_wake() would
> still clear the bit, causing the driver to lose track of the wakeup
> source.

The above is too verbose, try to squeeze it to the point.

> Also fix a latent signed-shift bug: the old (1 << i) expression in
> mxc_gpio_set_pad_wakeup() has implementation-defined behavior when
> i == 31, since 1 is a signed int.

Too many words for a simple (non-critical) update.

...

>  struct mxc_gpio_port {
>         u32 both_edges;
>         struct mxc_gpio_reg_saved gpio_saved_reg;
>         bool power_off;
> -       u32 wakeup_pads;
> +       unsigned long wakeup_pads;
>         bool is_pad_wakeup;
>         u32 pad_type[32];
>         const struct mxc_gpio_hwdata *hwdata;

While at it, run `pahole` and update the arrangement (of the members
you touched here) accordingly.

...

> static int gpio_set_wake_irq(struct irq_data *d, u32 enable)

>                         ret = enable_irq_wake(port->irq_high);
>                 else
>                         ret = enable_irq_wake(port->irq);
> -               port->wakeup_pads |= BIT(gpio_idx);
> +               if (!ret)
> +                       set_bit(gpio_idx, &port->wakeup_pads);
>         } else {
>                 if (port->irq_high && (gpio_idx >= 16))
>                         ret = disable_irq_wake(port->irq_high);
>                 else
>                         ret = disable_irq_wake(port->irq);
> -               port->wakeup_pads &= ~BIT(gpio_idx);
> +               if (!ret)
> +                       clear_bit(gpio_idx, &port->wakeup_pads);
>         }
>
>         return ret;

Instead do the following after the if (enable) {} else {} block, namely

  if (ret)
    return ret;

  assign_bit(..., enable)
  return 0;

...

>  static bool mxc_gpio_set_pad_wakeup(struct mxc_gpio_port *port, bool enable)

>         for (i = 0; i < 32; i++) {
> -               if ((port->wakeup_pads & (1 << i))) {
> +               if (test_bit(i, &port->wakeup_pads)) {

Instead just start using for_each_set_bits() from bitops.h.

>                         type = port->pad_type[i];
>                         if (enable)
>                                 config = pad_type_map[type];

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 3/9] gpio: mxc: cache compatible checks at probe time
  2026-10-03 12:06 ` [PATCH 3/9] gpio: mxc: cache compatible checks at probe time Peng Fan (OSS)
@ 2026-10-03 17:45   ` Andy Shevchenko
  2026-10-04  3:06   ` Frank Li
  1 sibling, 0 replies; 20+ messages in thread
From: Andy Shevchenko @ 2026-10-03 17:45 UTC (permalink / raw)
  To: Peng Fan (OSS)
  Cc: Linus Walleij, Bartosz Golaszewski, Frank Li, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, Shenwei Wang, linux-gpio,
	imx, linux-arm-kernel, linux-kernel, Peng Fan

On Sat, Oct 3, 2026 at 3:09 PM Peng Fan (OSS) <peng.fan@oss.nxp.com> wrote:

> mxc_gpio_generic_config() and mxc_gpio_set_pad_wakeup() call
> of_device_is_compatible() on every invocation to determine pad wakeup
> capability and i.MX8QM-specific behavior. These properties are
> invariant for the lifetime of the device.
>
> Cache them as bool fields (has_pad_wakeup, is_imx8qm) in mxc_gpio_port
> during probe, eliminating repeated device tree string comparisons in
> the suspend/resume hot path.

...

>  {
> -       struct device_node *np = port->dev->of_node;
> -
> -       if (of_device_is_compatible(np, "fsl,imx8dxl-gpio") ||
> -           of_device_is_compatible(np, "fsl,imx8qxp-gpio") ||
> -           of_device_is_compatible(np, "fsl,imx8qm-gpio"))
> -               return (gpiochip_generic_config(&port->gen_gc.gc,
> -                                               offset, conf) == 0);
> +       if (!port->has_pad_wakeup)
> +               return false;
>
> -       return false;
> +       return (gpiochip_generic_config(&port->gen_gc.gc, offset, conf) == 0);

Too many parentheses, also the semantic of 0 is not obvious. Better,
for example, this one

  int ret;
  ...
  ret = gpiochip_generic_config(...);
  if (ret)
    return false;

  return true;

>  }

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 4/9] gpio: mxc: use devm action for irq_domain cleanup
  2026-10-03 12:06 ` [PATCH 4/9] gpio: mxc: use devm action for irq_domain cleanup Peng Fan (OSS)
@ 2026-10-03 17:48   ` Andy Shevchenko
  2026-10-04  3:32   ` Frank Li
  1 sibling, 0 replies; 20+ messages in thread
From: Andy Shevchenko @ 2026-10-03 17:48 UTC (permalink / raw)
  To: Peng Fan (OSS)
  Cc: Linus Walleij, Bartosz Golaszewski, Frank Li, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, Shenwei Wang, linux-gpio,
	imx, linux-arm-kernel, linux-kernel, Peng Fan

On Sat, Oct 3, 2026 at 3:09 PM Peng Fan (OSS) <peng.fan@oss.nxp.com> wrote:

> Replace the manual irq_domain_remove() error path with
> devm_add_action_or_reset(), so the IRQ domain is cleaned up
> automatically on both probe failure to eliminate the
> out_irqdomain_remove goto label.

...

> +       err = devm_add_action_or_reset(&pdev->dev, mxc_gpio_irq_domain_remove, port->domain);
> +       if (err)
> +               goto out_bgio;
> +

We have devm_irq_domain_instantiate() and the respective wrappers.

...

>         /* gpio-mxc can be a generic irq chip */
>         err = mxc_gpio_init_gc(port, irq_base);
>         if (err < 0)
> -               goto out_irqdomain_remove;
> +               goto out_bgio;

This is simply wrong. No devm_*() call should be followed by goto.

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 5/9] gpio: mxc: use devres-managed PM runtime and dev_err_probe
  2026-10-03 12:06 ` [PATCH 5/9] gpio: mxc: use devres-managed PM runtime and dev_err_probe Peng Fan (OSS)
@ 2026-10-03 17:52   ` Andy Shevchenko
  2026-10-04  3:00   ` Frank Li
  1 sibling, 0 replies; 20+ messages in thread
From: Andy Shevchenko @ 2026-10-03 17:52 UTC (permalink / raw)
  To: Peng Fan (OSS)
  Cc: Linus Walleij, Bartosz Golaszewski, Frank Li, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, Shenwei Wang, linux-gpio,
	imx, linux-arm-kernel, linux-kernel, Peng Fan

On Sat, Oct 3, 2026 at 3:09 PM Peng Fan (OSS) <peng.fan@oss.nxp.com> wrote:

> Switch pm_runtime_get_noresume() and pm_runtime_enable() to their
> devm-managed variants so that pm_runtime_put_noidle() and
> pm_runtime_disable() are handled automatically by devres on both
> probe failure and device unbind.
>
> Remove the out_bgio goto label and replacing all error paths with

replace

> direct returns using dev_err_probe(), which provides better
> diagnostic output and handles -EPROBE_DEFER.

...

> -       pm_runtime_get_noresume(&pdev->dev);
> +       devm_pm_runtime_get_noresume(&pdev->dev);
>         pm_runtime_set_active(&pdev->dev);
> -       pm_runtime_enable(&pdev->dev);
> +       devm_pm_runtime_enable(&pdev->dev);

Definitely not.  There is little point to using devm_*() if you don't
check the return value.

...

>         err = gpio_generic_chip_init(&port->gen_gc, &config);
>         if (err)
> -               goto out_bgio;
> +               return dev_err_probe(&pdev->dev, err, "Failed to init gpio chip\n");

>         err = devm_gpiochip_add_data(&pdev->dev, &port->gen_gc.gc, port);
>         if (err)
> -               goto out_bgio;
> +               return dev_err_probe(&pdev->dev, err, "Failed to add gpiochip data\n");

These (and more) don't belong to the change — split it to the
logically isolated ones.
One patch for dev_err_probe() and another for PM calls.

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 6/9] gpio: mxc: use local dev variable and device_is_compatible()
  2026-10-03 12:06 ` [PATCH 6/9] gpio: mxc: use local dev variable and device_is_compatible() Peng Fan (OSS)
@ 2026-10-03 17:54   ` Andy Shevchenko
  0 siblings, 0 replies; 20+ messages in thread
From: Andy Shevchenko @ 2026-10-03 17:54 UTC (permalink / raw)
  To: Peng Fan (OSS)
  Cc: Linus Walleij, Bartosz Golaszewski, Frank Li, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, Shenwei Wang, linux-gpio,
	imx, linux-arm-kernel, linux-kernel, Peng Fan

On Sat, Oct 3, 2026 at 3:10 PM Peng Fan (OSS) <peng.fan@oss.nxp.com> wrote:
>
> From: Peng Fan <peng.fan@nxp.com>
>
> Introduce a local 'struct device *dev' variable to replace repeated
> '&pdev->dev' dereferences throughout mxc_gpio_probe(), improving
> readability.
>
> Switch from of_device_is_compatible(np, ...) to the device-model
> device_is_compatible(dev, ...) API which works with both DT and ACPI
> firmware backends. The 'np' variable is retained for
> of_alias_get_id() which has no device-model equivalent.
>
> No functional change.

> --- a/drivers/gpio/gpio-mxc.c
> +++ b/drivers/gpio/gpio-mxc.c
> @@ -428,17 +428,18 @@ static int mxc_gpio_probe(struct platform_device *pdev)

It seems you missed updating the headers (like switching from of.h to
property.h). Other than that, it looks good.

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 9/9] gpio: mxc: simplify gpio_set_wake_irq() with irq_set_irq_wake and assign_bit
  2026-10-03 12:06 ` [PATCH 9/9] gpio: mxc: simplify gpio_set_wake_irq() with irq_set_irq_wake and assign_bit Peng Fan (OSS)
@ 2026-10-03 17:59   ` Andy Shevchenko
  0 siblings, 0 replies; 20+ messages in thread
From: Andy Shevchenko @ 2026-10-03 17:59 UTC (permalink / raw)
  To: Peng Fan (OSS)
  Cc: Linus Walleij, Bartosz Golaszewski, Frank Li, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, Shenwei Wang, linux-gpio,
	imx, linux-arm-kernel, linux-kernel, Peng Fan

On Sat, Oct 3, 2026 at 3:10 PM Peng Fan (OSS) <peng.fan@oss.nxp.com> wrote:
>
> To simplify gpio_set_wake_irq():
>  - Replace the enable/disable_irq_wake() if/else branches with a single
>    irq_set_irq_wake() call which handles both directions internally.
>  - Replace the separate set_bit()/clear_bit() calls with assign_bit()
>    which sets or clears the bit based on the enable parameter.

...

> -       if (enable) {
> -               if (port->irq_high && (gpio_idx >= 16))
> -                       ret = enable_irq_wake(port->irq_high);
> -               else
> -                       ret = enable_irq_wake(port->irq);
> -               if (!ret)
> -                       set_bit(gpio_idx, &port->wakeup_pads);
> -       } else {
> -               if (port->irq_high && (gpio_idx >= 16))
> -                       ret = disable_irq_wake(port->irq_high);
> -               else
> -                       ret = disable_irq_wake(port->irq);
> -               if (!ret)
> -                       clear_bit(gpio_idx, &port->wakeup_pads);
> -       }
> +       if (port->irq_high && (gpio_idx >= 16))
> +               ret = irq_set_irq_wake(port->irq_high, enable);
> +       else
> +               ret = irq_set_irq_wake(port->irq, enable);

> +       if (!ret)
> +               assign_bit(gpio_idx, &port->wakeup_pads, enable);
>
>         return ret;

This uses an unusual pattern, we check for the error first.
But also this part should not be ping-ponged over the series, it
should be from the start like this, see my comment against the
respective patch.

>  }

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 5/9] gpio: mxc: use devres-managed PM runtime and dev_err_probe
  2026-10-03 12:06 ` [PATCH 5/9] gpio: mxc: use devres-managed PM runtime and dev_err_probe Peng Fan (OSS)
  2026-10-03 17:52   ` Andy Shevchenko
@ 2026-10-04  3:00   ` Frank Li
  1 sibling, 0 replies; 20+ messages in thread
From: Frank Li @ 2026-10-04  3:00 UTC (permalink / raw)
  To: Peng Fan (OSS)
  Cc: Linus Walleij, Bartosz Golaszewski, Frank Li, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, Shenwei Wang,
	Andy Shevchenko, linux-gpio, imx, linux-arm-kernel, linux-kernel,
	Peng Fan

On Sat, Oct 03, 2026 at 08:06:47PM +0800, Peng Fan (OSS) wrote:
> From: Peng Fan <peng.fan@nxp.com>
>
> Switch pm_runtime_get_noresume() and pm_runtime_enable() to their
> devm-managed variants so that pm_runtime_put_noidle() and
> pm_runtime_disable() are handled automatically by devres on both
> probe failure and device unbind.
>
> Remove the out_bgio goto label and replacing all error paths with
> direct returns using dev_err_probe(), which provides better
> diagnostic output and handles -EPROBE_DEFER.
>
> Assisted-by: LLM
> Signed-off-by: Peng Fan <peng.fan@nxp.com>
> ---
>  drivers/gpio/gpio-mxc.c | 30 ++++++++++--------------------
>  1 file changed, 10 insertions(+), 20 deletions(-)
>
> diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c
> index 3c395c82d7d4..73e19d2bf235 100644
> --- a/drivers/gpio/gpio-mxc.c
> +++ b/drivers/gpio/gpio-mxc.c
> @@ -474,9 +474,9 @@ static int mxc_gpio_probe(struct platform_device *pdev)
>  	if (of_device_is_compatible(np, "fsl,imx8qm-gpio"))
>  		port->is_imx8qm = true;
>
> -	pm_runtime_get_noresume(&pdev->dev);
> +	devm_pm_runtime_get_noresume(&pdev->dev);
>  	pm_runtime_set_active(&pdev->dev);
> -	pm_runtime_enable(&pdev->dev);
> +	devm_pm_runtime_enable(&pdev->dev);

devm_pm_runtime_set_active_enabled() can include pm_runtime_set_active()
and need check return value here.

And why call pm_runtime_get_noresume() before enable()?

Frank

>
>  	/* disable the interrupt and clear the status */
>  	writel(0, port->base + GPIO_IMR);
> @@ -502,7 +502,7 @@ static int mxc_gpio_probe(struct platform_device *pdev)
>
>  	err = gpio_generic_chip_init(&port->gen_gc, &config);
>  	if (err)
> -		goto out_bgio;
> +		return dev_err_probe(&pdev->dev, err, "Failed to init gpio chip\n");
>
>  	port->gen_gc.gc.request = mxc_gpio_request;
>  	port->gen_gc.gc.free = mxc_gpio_free;
> @@ -518,31 +518,27 @@ static int mxc_gpio_probe(struct platform_device *pdev)
>
>  	err = devm_gpiochip_add_data(&pdev->dev, &port->gen_gc.gc, port);
>  	if (err)
> -		goto out_bgio;
> +		return dev_err_probe(&pdev->dev, err, "Failed to add gpiochip data\n");
>
>  	irq_base = devm_irq_alloc_descs(&pdev->dev, -1, 0, 32, numa_node_id());
> -	if (irq_base < 0) {
> -		err = irq_base;
> -		goto out_bgio;
> -	}
> +	if (irq_base < 0)
> +		return dev_err_probe(&pdev->dev, irq_base, "Failed to alloc irq desc\n");
>
>  	port->domain = irq_domain_create_legacy(dev_fwnode(&pdev->dev), 32, irq_base, 0,
>  						&irq_domain_simple_ops, NULL);
> -	if (!port->domain) {
> -		err = -ENODEV;
> -		goto out_bgio;
> -	}
> +	if (!port->domain)
> +		return dev_err_probe(&pdev->dev, -ENODEV, "Failed to create irq domain\n");
>
>  	err = devm_add_action_or_reset(&pdev->dev, mxc_gpio_irq_domain_remove, port->domain);
>  	if (err)
> -		goto out_bgio;
> +		return dev_err_probe(&pdev->dev, err, "Failed to add irq_domain_remove\n");
>
>  	irq_domain_set_pm_device(port->domain, &pdev->dev);
>
>  	/* gpio-mxc can be a generic irq chip */
>  	err = mxc_gpio_init_gc(port, irq_base);
>  	if (err < 0)
> -		goto out_bgio;
> +		return dev_err_probe(&pdev->dev, err, "Failed mxc_gpio_init_gc\n");
>
>  	list_add_tail(&port->node, &mxc_gpio_ports);
>
> @@ -552,12 +548,6 @@ static int mxc_gpio_probe(struct platform_device *pdev)
>  	pm_runtime_put_autosuspend(&pdev->dev);
>
>  	return 0;
> -
> -out_bgio:
> -	pm_runtime_disable(&pdev->dev);
> -	pm_runtime_put_noidle(&pdev->dev);
> -	dev_info(&pdev->dev, "%s failed with errno %d\n", __func__, err);
> -	return err;
>  }
>
>  static void mxc_gpio_save_regs(struct mxc_gpio_port *port)
>
> --
> 2.51.0
>
>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 3/9] gpio: mxc: cache compatible checks at probe time
  2026-10-03 12:06 ` [PATCH 3/9] gpio: mxc: cache compatible checks at probe time Peng Fan (OSS)
  2026-10-03 17:45   ` Andy Shevchenko
@ 2026-10-04  3:06   ` Frank Li
  1 sibling, 0 replies; 20+ messages in thread
From: Frank Li @ 2026-10-04  3:06 UTC (permalink / raw)
  To: Peng Fan (OSS)
  Cc: Linus Walleij, Bartosz Golaszewski, Frank Li, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, Shenwei Wang,
	Andy Shevchenko, linux-gpio, imx, linux-arm-kernel, linux-kernel,
	Peng Fan

On Sat, Oct 03, 2026 at 08:06:45PM +0800, Peng Fan (OSS) wrote:
> From: Peng Fan <peng.fan@nxp.com>
>
> mxc_gpio_generic_config() and mxc_gpio_set_pad_wakeup() call
> of_device_is_compatible() on every invocation to determine pad wakeup
> capability and i.MX8QM-specific behavior. These properties are
> invariant for the lifetime of the device.
>
> Cache them as bool fields (has_pad_wakeup, is_imx8qm) in mxc_gpio_port
> during probe, eliminating repeated device tree string comparisons in
> the suspend/resume hot path.
>
> Assisted-by: LLM
> Signed-off-by: Peng Fan <peng.fan@nxp.com>
> ---
>  drivers/gpio/gpio-mxc.c | 24 ++++++++++++++----------
>  1 file changed, 14 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c
> index 8a755ac1af83..1c27232f6a80 100644
> --- a/drivers/gpio/gpio-mxc.c
> +++ b/drivers/gpio/gpio-mxc.c
> @@ -73,6 +73,8 @@ struct mxc_gpio_port {
>  	bool power_off;
>  	unsigned long wakeup_pads;
>  	bool is_pad_wakeup;
> +	bool has_pad_wakeup;
> +	bool is_imx8qm;
>  	u32 pad_type[32];
>  	const struct mxc_gpio_hwdata *hwdata;
>  };
> @@ -457,6 +459,14 @@ static int mxc_gpio_probe(struct platform_device *pdev)
>  	if (of_device_is_compatible(np, "fsl,imx7d-gpio"))
>  		port->power_off = true;
>
> +	if (of_device_is_compatible(np, "fsl,imx8dxl-gpio") ||
> +	    of_device_is_compatible(np, "fsl,imx8qxp-gpio") ||
> +	    of_device_is_compatible(np, "fsl,imx8qm-gpio"))
> +		port->has_pad_wakeup = true;

can you move has_pad_wakeup/is_imx8qm in mxc_gpio_hw_data?

Frank

> +
> +	if (of_device_is_compatible(np, "fsl,imx8qm-gpio"))
> +		port->is_imx8qm = true;
> +
>  	pm_runtime_get_noresume(&pdev->dev);
>  	pm_runtime_set_active(&pdev->dev);
>  	pm_runtime_enable(&pdev->dev);
> @@ -570,15 +580,10 @@ static void mxc_gpio_restore_regs(struct mxc_gpio_port *port)
>  static bool mxc_gpio_generic_config(struct mxc_gpio_port *port,
>  		unsigned int offset, unsigned long conf)
>  {
> -	struct device_node *np = port->dev->of_node;
> -
> -	if (of_device_is_compatible(np, "fsl,imx8dxl-gpio") ||
> -	    of_device_is_compatible(np, "fsl,imx8qxp-gpio") ||
> -	    of_device_is_compatible(np, "fsl,imx8qm-gpio"))
> -		return (gpiochip_generic_config(&port->gen_gc.gc,
> -						offset, conf) == 0);
> +	if (!port->has_pad_wakeup)
> +		return false;
>
> -	return false;
> +	return (gpiochip_generic_config(&port->gen_gc.gc, offset, conf) == 0);
>  }
>
>  static bool mxc_gpio_set_pad_wakeup(struct mxc_gpio_port *port, bool enable)
> @@ -586,7 +591,6 @@ static bool mxc_gpio_set_pad_wakeup(struct mxc_gpio_port *port, bool enable)
>  	unsigned long config;
>  	bool ret = false;
>  	int i, type;
> -	bool is_imx8qm = of_device_is_compatible(port->dev->of_node, "fsl,imx8qm-gpio");
>
>  	static const u32 pad_type_map[] = {
>  		IMX_SCU_WAKEUP_OFF,		/* 0 */
> @@ -608,7 +612,7 @@ static bool mxc_gpio_set_pad_wakeup(struct mxc_gpio_port *port, bool enable)
>  			else
>  				config = IMX_SCU_WAKEUP_OFF;
>
> -			if (is_imx8qm && config == IMX_SCU_WAKEUP_FALL_EDGE) {
> +			if (port->is_imx8qm && config == IMX_SCU_WAKEUP_FALL_EDGE) {
>  				dev_warn_once(port->dev,
>  					      "No falling-edge support for wakeup on i.MX8QM\n");
>  				config = IMX_SCU_WAKEUP_OFF;
>
> --
> 2.51.0
>
>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 4/9] gpio: mxc: use devm action for irq_domain cleanup
  2026-10-03 12:06 ` [PATCH 4/9] gpio: mxc: use devm action for irq_domain cleanup Peng Fan (OSS)
  2026-10-03 17:48   ` Andy Shevchenko
@ 2026-10-04  3:32   ` Frank Li
  1 sibling, 0 replies; 20+ messages in thread
From: Frank Li @ 2026-10-04  3:32 UTC (permalink / raw)
  To: Peng Fan (OSS)
  Cc: Linus Walleij, Bartosz Golaszewski, Frank Li, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, Shenwei Wang,
	Andy Shevchenko, linux-gpio, imx, linux-arm-kernel, linux-kernel,
	Peng Fan

On Sat, Oct 03, 2026 at 08:06:46PM +0800, Peng Fan (OSS) wrote:
> From: Peng Fan <peng.fan@nxp.com>
>
> Replace the manual irq_domain_remove() error path with
> devm_add_action_or_reset(), so the IRQ domain is cleaned up
> automatically on both probe failure to eliminate the
> out_irqdomain_remove goto label.
>
> Assisted-by: LLM
> Signed-off-by: Peng Fan <peng.fan@nxp.com>
> ---
>  drivers/gpio/gpio-mxc.c | 15 ++++++++++++---
>  1 file changed, 12 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c
> index 1c27232f6a80..3c395c82d7d4 100644
> --- a/drivers/gpio/gpio-mxc.c
> +++ b/drivers/gpio/gpio-mxc.c
> @@ -417,6 +417,13 @@ static void mxc_update_irq_chained_handler(struct mxc_gpio_port *port, bool enab
>  	}
>  }
>
> +static void mxc_gpio_irq_domain_remove(void *data)
> +{
> +	struct irq_domain *domain = data;
> +
> +	irq_domain_remove(domain);
> +}
> +
>  static int mxc_gpio_probe(struct platform_device *pdev)
>  {
>  	struct gpio_generic_chip_config config = { };
> @@ -526,12 +533,16 @@ static int mxc_gpio_probe(struct platform_device *pdev)
>  		goto out_bgio;
>  	}
>

No sure why not irq_domain_create_linear(),
https://lore.kernel.org/imx/aoW8V84mQ7UZhpaC@SMW015318/

Thomas Gleixner accept add devm_irq_domain_create_linear().

Frank

> +	err = devm_add_action_or_reset(&pdev->dev, mxc_gpio_irq_domain_remove, port->domain);
> +	if (err)
> +		goto out_bgio;
> +
>  	irq_domain_set_pm_device(port->domain, &pdev->dev);
>
>  	/* gpio-mxc can be a generic irq chip */
>  	err = mxc_gpio_init_gc(port, irq_base);
>  	if (err < 0)
> -		goto out_irqdomain_remove;
> +		goto out_bgio;
>
>  	list_add_tail(&port->node, &mxc_gpio_ports);
>
> @@ -542,8 +553,6 @@ static int mxc_gpio_probe(struct platform_device *pdev)
>
>  	return 0;
>
> -out_irqdomain_remove:
> -	irq_domain_remove(port->domain);
>  out_bgio:
>  	pm_runtime_disable(&pdev->dev);
>  	pm_runtime_put_noidle(&pdev->dev);
>
> --
> 2.51.0
>
>

^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2026-10-04  3:32 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-03 12:06 [PATCH 0/9] gpio: mxc: bug fixes and probe cleanup Peng Fan (OSS)
2026-10-03 12:06 ` [PATCH 1/9] gpio: mxc: fix race between chained IRQ handler install and probe completion Peng Fan (OSS)
2026-10-03 17:35   ` Andy Shevchenko
2026-10-03 12:06 ` [PATCH 2/9] gpio: mxc: fix wakeup_pads bit operations for correctness Peng Fan (OSS)
2026-10-03 17:41   ` Andy Shevchenko
2026-10-03 12:06 ` [PATCH 3/9] gpio: mxc: cache compatible checks at probe time Peng Fan (OSS)
2026-10-03 17:45   ` Andy Shevchenko
2026-10-04  3:06   ` Frank Li
2026-10-03 12:06 ` [PATCH 4/9] gpio: mxc: use devm action for irq_domain cleanup Peng Fan (OSS)
2026-10-03 17:48   ` Andy Shevchenko
2026-10-04  3:32   ` Frank Li
2026-10-03 12:06 ` [PATCH 5/9] gpio: mxc: use devres-managed PM runtime and dev_err_probe Peng Fan (OSS)
2026-10-03 17:52   ` Andy Shevchenko
2026-10-04  3:00   ` Frank Li
2026-10-03 12:06 ` [PATCH 6/9] gpio: mxc: use local dev variable and device_is_compatible() Peng Fan (OSS)
2026-10-03 17:54   ` Andy Shevchenko
2026-10-03 12:06 ` [PATCH 7/9] gpio: mxc: introduce MXC_ICR macros and use field_prep/field_get Peng Fan (OSS)
2026-10-03 12:06 ` [PATCH 8/9] gpio: mxc: use BIT() macro for single-bit operations Peng Fan (OSS)
2026-10-03 12:06 ` [PATCH 9/9] gpio: mxc: simplify gpio_set_wake_irq() with irq_set_irq_wake and assign_bit Peng Fan (OSS)
2026-10-03 17:59   ` Andy Shevchenko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®