Skip to contentSkip to conversation

pinctrl: airoha: add EcoNet EN7528 pin controller support

PATCH Superseded Ahmed Naseef 6 participants 15 messages Aug 9 – Sep 9

Subsystems (5)

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore
#0 lore raw

cover pinctrl: airoha: add EcoNet EN7528 pin controller support

The EcoNet EN7528 is a MIPS SoC that uses the same pin controller and GPIO IP as the Airoha SoCs, so it reuses the shared driver code introduced by the split into per-SoC drivers. Its register layout differs from every existing variant though: all IOMUX mode bits live in a single CHIP SCU register plus a few spill-over bits in IOMUX Control 3, EJTAG has its own enable register, and every pin configuration register is at a different offset than on EN7523.

It also differs in a way the shared code did not model: only GPIO0-GPIO15 are wired to the interrupt controller, while the driver assumed all AIROHA_NUM_PINS GPIOs could raise an interrupt. Patch 1 adds a num_irq_pins field to the per-SoC match data to describe that, bounds the interrupt callbacks and handler with it, and feeds it to gpiolib through gpio_irq_chip::init_valid_mask so gpiod_to_irq() fails up front for a pin that can never be an interrupt source. All existing SoCs pass AIROHA_NUM_PINS and are unaffected.

Patch 2 documents the binding, patch 3 adds the driver.

The series is based on linux-pinctrl/for-next, as it depends on the per-SoC driver split and on the CHIP SCU lookup by "airoha,chip-scu" phandle that landed there.

Tested on a DASAN H660GM-A (EN7528, Airtel), booting OpenWrt.

Ahmed Naseef (2):
pinctrl: airoha: limit GPIO interrupts to interrupt-capable pins
dt-bindings: pinctrl: Add EcoNet EN7528 pin controller

Benjamin Larsson (1):
pinctrl: airoha: add support of en7528 SoC

 .../pinctrl/econet,en7528-pinctrl.yaml        |  190 +++
 drivers/pinctrl/airoha/Kconfig                |   15 +-
 drivers/pinctrl/airoha/Makefile               |    1 +
 drivers/pinctrl/airoha/airoha-common.h        |    3 +
 drivers/pinctrl/airoha/pinctrl-airoha.c       |   33 +-
 drivers/pinctrl/airoha/pinctrl-an7563.c       |    1 +
 drivers/pinctrl/airoha/pinctrl-an7581.c       |    1 +
 drivers/pinctrl/airoha/pinctrl-an7583.c       |    1 +
 drivers/pinctrl/airoha/pinctrl-en7523.c       |    1 +
 drivers/pinctrl/airoha/pinctrl-en7528.c       | 1204 +++++++++++++++++
 10 files changed, 1443 insertions(+), 7 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/econet,en7528-pinctrl.yaml
 create mode 100644 drivers/pinctrl/airoha/pinctrl-en7528.c

base-commit: 87e787e591a82b9b324aa0968795b256f789d287

Signature · 1 line
2.34.1
#1 lore raw

PATCH 1/3 pinctrl: airoha: limit GPIO interrupts to interrupt-capable pins

The driver assumes that every one of the AIROHA_NUM_PINS GPIOs can raise an interrupt. That holds for the SoCs supported so far, but not for every member of the family: on EN7528 only GPIO0-GPIO15 are wired to the interrupt controller.

Without this the driver hands out interrupts for GPIOs that can never fire, and the interrupt handler reads status registers that are not backed by any pin.

Add a num_irq_pins field to the per-SoC match data and use it to bound the interrupt callbacks and to size the loop in the interrupt handler. Feed it to gpiolib through gpio_irq_chip::init_valid_mask as well, so that gpiod_to_irq() fails for a pin that cannot be an interrupt source instead of deferring the failure to request_irq().

---
 drivers/pinctrl/airoha/airoha-common.h  |  3 +++
 drivers/pinctrl/airoha/pinctrl-airoha.c | 33 +++++++++++++++++++++----
 drivers/pinctrl/airoha/pinctrl-an7563.c |  1 +
 drivers/pinctrl/airoha/pinctrl-an7581.c |  1 +
 drivers/pinctrl/airoha/pinctrl-an7583.c |  1 +
 drivers/pinctrl/airoha/pinctrl-en7523.c |  1 +
 6 files changed, 35 insertions(+), 5 deletions(-)
drivers/pinctrl/airoha/airoha-common.h +3 -0
index c1acbfb7426e..16f7abcdfb83 100644
@@ -127,6 +127,7 @@ struct airoha_pinctrl {
 
 	struct gpio_chip gpiochip;
 	struct airoha_gpiochip_regs *gpio_regs;
+	unsigned int num_irq_pins;
 };
 
 struct airoha_pinctrl_match_data {
@@ -140,6 +141,8 @@ struct airoha_pinctrl_match_data {
 	const struct airoha_pinctrl_func *funcs;
 	const unsigned int num_funcs;
 	const struct airoha_pinctrl_confs_info confs_info[AIROHA_PINCTRL_CONFS_MAX];
+	/* number of GPIOs wired to the interrupt controller */
+	const unsigned int num_irq_pins;
 };
 
 int airoha_pinctrl_probe(struct platform_device *pdev);
drivers/pinctrl/airoha/pinctrl-airoha.c +28 -5
index f505a3f69c5d..52a768c859b7 100644
@@ -213,7 +213,7 @@ static void airoha_irq_unmask(struct irq_data *data)
 	u32 mask = GENMASK(2 * offset + 1, 2 * offset);
 	u32 val = BIT(2 * offset);
 
-	if (WARN_ON_ONCE(data->hwirq >= AIROHA_NUM_PINS))
+	if (WARN_ON_ONCE(data->hwirq >= pinctrl->num_irq_pins))
 		return;
 
 	gpiochip_enable_irq(gc, irqd_to_hwirq(data));
@@ -249,7 +249,7 @@ static void airoha_irq_mask(struct irq_data *data)
 	u8 index = data->hwirq / AIROHA_REG_GPIOCTRL_NUM_PIN;
 	u32 mask = GENMASK(2 * offset + 1, 2 * offset);
 
-	if (data->hwirq >= AIROHA_NUM_PINS)
+	if (data->hwirq >= pinctrl->num_irq_pins)
 		return;
 
 	regmap_clear_bits(pinctrl->regmap, gpio_regs->level[index], mask);
@@ -265,7 +265,7 @@ static void airoha_irq_ack(struct irq_data *data)
 	u8 offset = data->hwirq % AIROHA_PIN_BANK_SIZE;
 	u8 index = data->hwirq / AIROHA_PIN_BANK_SIZE;
 
-	if (data->hwirq >= AIROHA_NUM_PINS)
+	if (data->hwirq >= pinctrl->num_irq_pins)
 		return;
 
 	regmap_write(pinctrl->regmap, gpio_regs->status[index], BIT(offset));
@@ -273,7 +273,10 @@ static void airoha_irq_ack(struct irq_data *data)
 
 static int airoha_irq_type(struct irq_data *data, unsigned int type)
 {
-	if (data->hwirq >= AIROHA_NUM_PINS)
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
+	struct airoha_pinctrl *pinctrl = gpiochip_get_data(gc);
+
+	if (data->hwirq >= pinctrl->num_irq_pins)
 		return -EINVAL;
 
 	if (type == IRQ_TYPE_NONE) {
@@ -304,9 +307,11 @@ static irqreturn_t airoha_irq_handler(int irq, void *data)
 {
 	struct airoha_pinctrl *pinctrl = data;
 	bool handled = false;
+	unsigned int nbanks;
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(irq_status_regs); i++) {
+	nbanks = DIV_ROUND_UP(pinctrl->num_irq_pins, AIROHA_PIN_BANK_SIZE);
+	for (i = 0; i < nbanks; i++) {
 		struct gpio_irq_chip *girq = &pinctrl->gpiochip.irq;
 		u32 regmap;
 		unsigned long status;
@@ -340,6 +345,22 @@ static const struct irq_chip airoha_gpio_irq_chip = {
 	GPIOCHIP_IRQ_RESOURCE_HELPERS,
 };
 
+/*
+ * Mark the GPIOs that are not wired to the interrupt controller as not
+ * valid, so that gpiod_to_irq() fails for them with -ENXIO instead of
+ * handing out an interrupt that can never fire.
+ */
+static void airoha_gpio_init_valid_mask(struct gpio_chip *gc,
+					unsigned long *valid_mask,
+					unsigned int ngpios)
+{
+	struct airoha_pinctrl *pinctrl = gpiochip_get_data(gc);
+	unsigned int num_irq_pins = pinctrl->num_irq_pins;
+
+	if (num_irq_pins < ngpios)
+		bitmap_clear(valid_mask, num_irq_pins, ngpios - num_irq_pins);
+}
+
 static int airoha_pinctrl_add_gpiochip(struct airoha_pinctrl *pinctrl,
 					struct platform_device *pdev)
 {
@@ -362,6 +383,7 @@ static int airoha_pinctrl_add_gpiochip(struct airoha_pinctrl *pinctrl,
 
 	girq->default_type = IRQ_TYPE_NONE;
 	girq->handler = handle_bad_irq;
+	girq->init_valid_mask = airoha_gpio_init_valid_mask;
 	gpio_irq_chip_set_chip(girq, &airoha_gpio_irq_chip);
 
 	irq = platform_get_irq(pdev, 0);
@@ -848,6 +870,7 @@ int airoha_pinctrl_probe(struct platform_device *pdev)
 	pinctrl->grps = data->grps;
 	pinctrl->funcs = data->funcs;
 	pinctrl->confs_info = data->confs_info;
+	pinctrl->num_irq_pins = data->num_irq_pins;
 
 	err = pinctrl_enable(pinctrl->ctrl);
 	if (err)
drivers/pinctrl/airoha/pinctrl-an7563.c +1 -0
index 40cbbe90cc46..f011c6c9ccce 100644
@@ -1069,6 +1069,7 @@ static const struct airoha_pinctrl_match_data pinctrl_match_data = {
 	.num_grps = ARRAY_SIZE(pinctrl_groups),
 	.funcs = pinctrl_funcs,
 	.num_funcs = ARRAY_SIZE(pinctrl_funcs),
+	.num_irq_pins = AIROHA_NUM_PINS,
 	.confs_info = {
 		[AIROHA_PINCTRL_CONFS_PULLUP] = {
 			.confs = pinctrl_pullup_conf,
drivers/pinctrl/airoha/pinctrl-an7581.c +1 -0
index 2fcf88106e11..bfb777594811 100644
@@ -1441,6 +1441,7 @@ static const struct airoha_pinctrl_match_data pinctrl_match_data = {
 	.num_grps = ARRAY_SIZE(pinctrl_groups),
 	.funcs = pinctrl_funcs,
 	.num_funcs = ARRAY_SIZE(pinctrl_funcs),
+	.num_irq_pins = AIROHA_NUM_PINS,
 	.confs_info = {
 		[AIROHA_PINCTRL_CONFS_PULLUP] = {
 			.confs = pinctrl_pullup_conf,
drivers/pinctrl/airoha/pinctrl-an7583.c +1 -0
index 2c3a75c35915..1cd0f442ddc1 100644
@@ -1471,6 +1471,7 @@ static const struct airoha_pinctrl_match_data pinctrl_match_data = {
 	.num_grps = ARRAY_SIZE(pinctrl_groups),
 	.funcs = pinctrl_funcs,
 	.num_funcs = ARRAY_SIZE(pinctrl_funcs),
+	.num_irq_pins = AIROHA_NUM_PINS,
 	.confs_info = {
 		[AIROHA_PINCTRL_CONFS_PULLUP] = {
 			.confs = pinctrl_pullup_conf,
drivers/pinctrl/airoha/pinctrl-en7523.c +1 -0
index 5aa39bacf460..b0c5e60f0aeb 100644
@@ -1113,6 +1113,7 @@ static const struct airoha_pinctrl_match_data pinctrl_match_data = {
 	.num_grps = ARRAY_SIZE(pinctrl_groups),
 	.funcs = pinctrl_funcs,
 	.num_funcs = ARRAY_SIZE(pinctrl_funcs),
+	.num_irq_pins = AIROHA_NUM_PINS,
 	.confs_info = {
 		[AIROHA_PINCTRL_CONFS_PULLUP] = {
 			.confs = pinctrl_pullup_conf,
Signature · 1 line
2.34.1
#2 lore raw

Re: [PATCH 1/3] pinctrl: airoha: limit GPIO interrupts to interrupt-capable pins

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:

Pre-existing issues:
- [High] The shared parent interrupt is requested before the gpiochip and its IRQ domain are fully registered, creating a race condition that loses hardware interrupts during probe.
- [High] The interrupt handler manually clears the hardware status bit after the child handler completes, creating a race condition that drops edge-triggered interrupts.
- [High] The driver acquires a sleepable spinlock inside IRQ chip callbacks while holding a raw_spinlock_t, violating PREEMPT_RT lock nesting rules.
- [High] The interrupt handler loops over banks bounded by num_irq_pins but fails to mask out unbacked bits within the final bank, neutralizing spurious interrupt mitigation. --

--- Patch [1]: [PATCH 1/3] pinctrl: airoha: limit GPIO interrupts to interrupt-capable pins --- commit 540e2cd0ad7d06a01aca006b216ac539740ee038
Author: Ahmed Naseef <[email protected]>
pinctrl: airoha: limit GPIO interrupts to interrupt-capable pins

This patch limits GPIO interrupts to interrupt-capable pins by introducing a num_irq_pins field to the SoC match data. It restricts the interrupt callbacks and the loop in the interrupt handler, and feeds the count to gpiolib to prevent requesting invalid interrupts.

Quoted 13 lines
drivers/pinctrl/airoha/pinctrl-airoha.c +1 -1
index f505a3f69c5d1..52a768c859b71 100644
@@ -213,7 +213,7 @@ static void airoha_irq_unmask(struct irq_data *data)
 	u32 mask = GENMASK(2 * offset + 1, 2 * offset);
 	u32 val = BIT(2 * offset);
 
-	if (WARN_ON_ONCE(data->hwirq >= AIROHA_NUM_PINS))
+	if (WARN_ON_ONCE(data->hwirq >= pinctrl->num_irq_pins))
 		return;
 
 	gpiochip_enable_irq(gc, irqd_to_hwirq(data));

drivers/pinctrl/airoha/pinctrl-airoha.c

Quoted 7 lines
drivers/pinctrl/airoha/pinctrl-airoha.c +0 -0
 	switch (irqd_get_trigger_type(data)) {
 	case IRQ_TYPE_LEVEL_LOW:
 		val = val << 1;
 		fallthrough;
 	case IRQ_TYPE_LEVEL_HIGH:
 		regmap_update_bits(pinctrl->regmap, gpio_regs->level[index],
 				   mask, val);

[Severity: High]
This isn't a bug introduced by this patch, but does calling regmap_update_bits() here cause a lock nesting violation on PREEMPT_RT kernels?

The IRQ chip callbacks like airoha_irq_unmask() are invoked by the IRQ core with the descriptor lock (desc->lock) held, which is a raw_spinlock_t.

The syscon regmap (pinctrl->regmap) uses a standard spinlock_t that becomes a sleepable RT-mutex on PREEMPT_RT. Acquiring a sleepable lock under a raw spinlock leads to a kernel panic.

[ ... ]

Quoted 16 lines
drivers/pinctrl/airoha/pinctrl-airoha.c +3 -1
@@ -304,9 +307,11 @@ static irqreturn_t airoha_irq_handler(int irq, void *data)
 {
 	struct airoha_pinctrl *pinctrl = data;
 	bool handled = false;
+	unsigned int nbanks;
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(irq_status_regs); i++) {
+	nbanks = DIV_ROUND_UP(pinctrl->num_irq_pins, AIROHA_PIN_BANK_SIZE);
+	for (i = 0; i < nbanks; i++) {
 		struct gpio_irq_chip *girq = &pinctrl->gpiochip.irq;
 		u32 regmap;
 		unsigned long status;
drivers/pinctrl/airoha/pinctrl-airoha.c +0 -0
 		int irq;
 
 		if (regmap_read(pinctrl->regmap, pinctrl->gpio_regs->status[i],

drivers/pinctrl/airoha/pinctrl-airoha.c

Quoted 10 lines
drivers/pinctrl/airoha/pinctrl-airoha.c +0 -0
 				&regmap))
 			continue;
 
 		status = regmap;
 		for_each_set_bit(irq, &status, AIROHA_PIN_BANK_SIZE) {
 			u32 offset = irq + i * AIROHA_PIN_BANK_SIZE;
 
 			generic_handle_domain_irq(girq->domain, offset);
 			regmap_write(pinctrl->regmap,
 				     pinctrl->gpio_regs->status[i], BIT(irq));

[Severity: High]
This isn't a bug introduced by this patch, but does clearing the hardware status bit after the child handler completes cause edge-triggered interrupts to be dropped?

In airoha_irq_handler(), after generic_handle_domain_irq() returns, the handler manually clears the hardware status bit using regmap_write(). However, the IRQ core (such as handle_edge_irq) already invokes the chip's irq_ack callback to clear this bit before executing the child handler.

By clearing the bit a second time after the child handler returns, any new edge-triggered interrupts that arrived while the child handler was executing would be silently erased.

drivers/pinctrl/airoha/pinctrl-airoha.c

Quoted 2 lines
drivers/pinctrl/airoha/pinctrl-airoha.c +0 -0
 		}
 		handled |= !!status;

[Severity: High]
This is a pre-existing issue, but does failing to mask out unbacked bits in the final bank neutralize the spurious interrupt mitigation?

While nbanks limits the outer loop, on EN7528 num_irq_pins is 16, so nbanks is 1. The loop reads status[0] and for_each_set_bit() iterates over all 32 bits.

If any unbacked hardware bit (16-31) reads as 1, generic_handle_domain_irq() is called (and safely returns -EINVAL), but handled incorrectly evaluates to true. This would cause IRQ_HANDLED to be returned for spurious interrupts on the shared line, defeating the kernel's spurious interrupt storm mitigation.

[ ... ]

Quoted 8 lines
drivers/pinctrl/airoha/pinctrl-airoha.c +1 -0
@@ -362,6 +383,7 @@ static int airoha_pinctrl_add_gpiochip(struct airoha_pinctrl *pinctrl,
 
 	girq->default_type = IRQ_TYPE_NONE;
 	girq->handler = handle_bad_irq;
+	girq->init_valid_mask = airoha_gpio_init_valid_mask;
 	gpio_irq_chip_set_chip(girq, &airoha_gpio_irq_chip);
 
 	irq = platform_get_irq(pdev, 0);

drivers/pinctrl/airoha/pinctrl-airoha.c

Quoted 10 lines
drivers/pinctrl/airoha/pinctrl-airoha.c +0 -0
 	if (irq < 0)
 		return irq;
 
 	err = devm_request_irq(dev, irq, airoha_irq_handler, IRQF_SHARED,
 				dev_name(dev), pinctrl);
 	if (err)
 		return err;
 
 	return devm_gpiochip_add_data(dev, gc, pinctrl);
 }

[Severity: High]
This isn't a bug introduced by this patch, but does requesting the shared parent interrupt before registering the gpiochip cause a race condition during probe?

The driver requests the shared parent IRQ via devm_request_irq() before calling devm_gpiochip_add_data().

If the shared IRQ line is asserted by another device before devm_gpiochip_add_data() completes, airoha_irq_handler() will run, read the hardware status, and call generic_handle_domain_irq() with an uninitialized girq->domain. The core lookup fails, but the handler proceeds to clear the hardware status and returns IRQ_HANDLED, dropping the interrupt.

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
Reviewed-by on v1 1/3
#3 lore raw

Re: [PATCH 1/3] pinctrl: airoha: limit GPIO interrupts to interrupt-capable pins

In reply to Ahmed Naseef

Hi.

Quoted 111 lines · Ahmed Naseef

The driver assumes that every one of the AIROHA_NUM_PINS GPIOs can raise an interrupt. That holds for the SoCs supported so far, but not for every member of the family: on EN7528 only GPIO0-GPIO15 are wired to the interrupt controller.

Without this the driver hands out interrupts for GPIOs that can never fire, and the interrupt handler reads status registers that are not backed by any pin.

Add a num_irq_pins field to the per-SoC match data and use it to bound the interrupt callbacks and to size the loop in the interrupt handler. Feed it to gpiolib through gpio_irq_chip::init_valid_mask as well, so that gpiod_to_irq() fails for a pin that cannot be an interrupt source instead of deferring the failure to request_irq().

---
  drivers/pinctrl/airoha/airoha-common.h  |  3 +++
  drivers/pinctrl/airoha/pinctrl-airoha.c | 33 +++++++++++++++++++++----
  drivers/pinctrl/airoha/pinctrl-an7563.c |  1 +
  drivers/pinctrl/airoha/pinctrl-an7581.c |  1 +
  drivers/pinctrl/airoha/pinctrl-an7583.c |  1 +
  drivers/pinctrl/airoha/pinctrl-en7523.c |  1 +
  6 files changed, 35 insertions(+), 5 deletions(-)
drivers/pinctrl/airoha/airoha-common.h +3 -0
index c1acbfb7426e..16f7abcdfb83 100644
@@ -127,6 +127,7 @@ struct airoha_pinctrl {
 
  	struct gpio_chip gpiochip;
  	struct airoha_gpiochip_regs *gpio_regs;
+	unsigned int num_irq_pins;
  };
 
  struct airoha_pinctrl_match_data {
@@ -140,6 +141,8 @@ struct airoha_pinctrl_match_data {
  	const struct airoha_pinctrl_func *funcs;
  	const unsigned int num_funcs;
  	const struct airoha_pinctrl_confs_info confs_info[AIROHA_PINCTRL_CONFS_MAX];
+	/* number of GPIOs wired to the interrupt controller */
+	const unsigned int num_irq_pins;
  };
 
  int airoha_pinctrl_probe(struct platform_device *pdev);
drivers/pinctrl/airoha/pinctrl-airoha.c +15 -5
index f505a3f69c5d..52a768c859b7 100644
@@ -213,7 +213,7 @@ static void airoha_irq_unmask(struct irq_data *data)
  	u32 mask = GENMASK(2 * offset + 1, 2 * offset);
  	u32 val = BIT(2 * offset);
 
-	if (WARN_ON_ONCE(data->hwirq >= AIROHA_NUM_PINS))
+	if (WARN_ON_ONCE(data->hwirq >= pinctrl->num_irq_pins))
  		return;
 
  	gpiochip_enable_irq(gc, irqd_to_hwirq(data));
@@ -249,7 +249,7 @@ static void airoha_irq_mask(struct irq_data *data)
  	u8 index = data->hwirq / AIROHA_REG_GPIOCTRL_NUM_PIN;
  	u32 mask = GENMASK(2 * offset + 1, 2 * offset);
 
-	if (data->hwirq >= AIROHA_NUM_PINS)
+	if (data->hwirq >= pinctrl->num_irq_pins)
  		return;
 
  	regmap_clear_bits(pinctrl->regmap, gpio_regs->level[index], mask);
@@ -265,7 +265,7 @@ static void airoha_irq_ack(struct irq_data *data)
  	u8 offset = data->hwirq % AIROHA_PIN_BANK_SIZE;
  	u8 index = data->hwirq / AIROHA_PIN_BANK_SIZE;
 
-	if (data->hwirq >= AIROHA_NUM_PINS)
+	if (data->hwirq >= pinctrl->num_irq_pins)
  		return;
 
  	regmap_write(pinctrl->regmap, gpio_regs->status[index], BIT(offset));
@@ -273,7 +273,10 @@ static void airoha_irq_ack(struct irq_data *data)
 
  static int airoha_irq_type(struct irq_data *data, unsigned int type)
  {
-	if (data->hwirq >= AIROHA_NUM_PINS)
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
+	struct airoha_pinctrl *pinctrl = gpiochip_get_data(gc);
+
+	if (data->hwirq >= pinctrl->num_irq_pins)
  		return -EINVAL;
 
  	if (type == IRQ_TYPE_NONE) {
@@ -304,9 +307,11 @@ static irqreturn_t airoha_irq_handler(int irq, void *data)
  {
  	struct airoha_pinctrl *pinctrl = data;
  	bool handled = false;
+	unsigned int nbanks;
  	int i;
 
-	for (i = 0; i < ARRAY_SIZE(irq_status_regs); i++) {
+	nbanks = DIV_ROUND_UP(pinctrl->num_irq_pins, AIROHA_PIN_BANK_SIZE);
+	for (i = 0; i < nbanks; i++) {
  		struct gpio_irq_chip *girq = &pinctrl->gpiochip.irq;
  		u32 regmap;
  		unsigned long status;
@@ -340,6 +345,22 @@ static const struct irq_chip airoha_gpio_irq_chip = {
  	GPIOCHIP_IRQ_RESOURCE_HELPERS,
  };
 
+/*
+ * Mark the GPIOs that are not wired to the interrupt controller as not
+ * valid, so that gpiod_to_irq() fails for them with -ENXIO instead of
+ * handing out an interrupt that can never fire.
+ */

drivers/pinctrl/airoha/pinctrl-airoha.c static const struct irq_chip airoha_gpio_irq_chip = { · line 362

Quoted 10 lines
drivers/pinctrl/airoha/pinctrl-airoha.c +10 -0
+static void airoha_gpio_init_valid_mask(struct gpio_chip *gc,
+					unsigned long *valid_mask,
+					unsigned int ngpios)
+{
+	struct airoha_pinctrl *pinctrl = gpiochip_get_data(gc);
+	unsigned int num_irq_pins = pinctrl->num_irq_pins;
+
+	if (num_irq_pins < ngpios)
+		bitmap_clear(valid_mask, num_irq_pins, ngpios - num_irq_pins);
+}

I'm not sure if there is something that gives a sane error log if this trigger. Maybe make it explicit?

Either way:

Quoted 68 lines
drivers/pinctrl/airoha/pinctrl-airoha.c +3 -0
+
  static int airoha_pinctrl_add_gpiochip(struct airoha_pinctrl *pinctrl,
  					struct platform_device *pdev)
  {
@@ -362,6 +383,7 @@ static int airoha_pinctrl_add_gpiochip(struct airoha_pinctrl *pinctrl,
 
  	girq->default_type = IRQ_TYPE_NONE;
  	girq->handler = handle_bad_irq;
+	girq->init_valid_mask = airoha_gpio_init_valid_mask;
  	gpio_irq_chip_set_chip(girq, &airoha_gpio_irq_chip);
 
  	irq = platform_get_irq(pdev, 0);
@@ -848,6 +870,7 @@ int airoha_pinctrl_probe(struct platform_device *pdev)
  	pinctrl->grps = data->grps;
  	pinctrl->funcs = data->funcs;
  	pinctrl->confs_info = data->confs_info;
+	pinctrl->num_irq_pins = data->num_irq_pins;
 
  	err = pinctrl_enable(pinctrl->ctrl);
  	if (err)
drivers/pinctrl/airoha/pinctrl-an7563.c +1 -0
index 40cbbe90cc46..f011c6c9ccce 100644
@@ -1069,6 +1069,7 @@ static const struct airoha_pinctrl_match_data pinctrl_match_data = {
  	.num_grps = ARRAY_SIZE(pinctrl_groups),
  	.funcs = pinctrl_funcs,
  	.num_funcs = ARRAY_SIZE(pinctrl_funcs),
+	.num_irq_pins = AIROHA_NUM_PINS,
  	.confs_info = {
  		[AIROHA_PINCTRL_CONFS_PULLUP] = {
  			.confs = pinctrl_pullup_conf,
drivers/pinctrl/airoha/pinctrl-an7581.c +1 -0
index 2fcf88106e11..bfb777594811 100644
@@ -1441,6 +1441,7 @@ static const struct airoha_pinctrl_match_data pinctrl_match_data = {
  	.num_grps = ARRAY_SIZE(pinctrl_groups),
  	.funcs = pinctrl_funcs,
  	.num_funcs = ARRAY_SIZE(pinctrl_funcs),
+	.num_irq_pins = AIROHA_NUM_PINS,
  	.confs_info = {
  		[AIROHA_PINCTRL_CONFS_PULLUP] = {
  			.confs = pinctrl_pullup_conf,
drivers/pinctrl/airoha/pinctrl-an7583.c +1 -0
index 2c3a75c35915..1cd0f442ddc1 100644
@@ -1471,6 +1471,7 @@ static const struct airoha_pinctrl_match_data pinctrl_match_data = {
  	.num_grps = ARRAY_SIZE(pinctrl_groups),
  	.funcs = pinctrl_funcs,
  	.num_funcs = ARRAY_SIZE(pinctrl_funcs),
+	.num_irq_pins = AIROHA_NUM_PINS,
  	.confs_info = {
  		[AIROHA_PINCTRL_CONFS_PULLUP] = {
  			.confs = pinctrl_pullup_conf,
drivers/pinctrl/airoha/pinctrl-en7523.c +1 -0
index 5aa39bacf460..b0c5e60f0aeb 100644
@@ -1113,6 +1113,7 @@ static const struct airoha_pinctrl_match_data pinctrl_match_data = {
  	.num_grps = ARRAY_SIZE(pinctrl_groups),
  	.funcs = pinctrl_funcs,
  	.num_funcs = ARRAY_SIZE(pinctrl_funcs),
+	.num_irq_pins = AIROHA_NUM_PINS,
  	.confs_info = {
  		[AIROHA_PINCTRL_CONFS_PULLUP] = {
  			.confs = pinctrl_pullup_conf,
#4 lore raw

Re: [PATCH 1/3] pinctrl: airoha: limit GPIO interrupts to interrupt-capable pins

Quoted 11 lines

drivers/pinctrl/airoha/pinctrl-airoha.c static const struct irq_chip airoha_gpio_irq_chip = { · line 362

Quoted 7 lines
drivers/pinctrl/airoha/pinctrl-airoha.c +7 -0
+{
+	struct airoha_pinctrl *pinctrl = gpiochip_get_data(gc);
+	unsigned int num_irq_pins = pinctrl->num_irq_pins;
+
+	if (num_irq_pins < ngpios)
+		bitmap_clear(valid_mask, num_irq_pins, ngpios - num_irq_pins);
+}

I'm not sure if there is something that gives a sane error log if this trigger. Maybe make it explicit?

Quoted 2 lines

Either way:

Nothing logs the limit itself, the -ENXIO only surfaces at the consumer.

However Most of the gpio_irq_chip::init_valid_mask implementations in the tree log nothing at all. Only pinctrl-baytrail does, and not for the valid range.

Happy to make it explicit if you prefer, at probe:

        if (pinctrl->num_irq_pins < AIROHA_NUM_PINS)
                dev_dbg(dev, "GPIO%u and above cannot be used as interrupts\n",
                        pinctrl->num_irq_pins);

Thanks for the review!

Linus, since the merge window is open. Is this still worth taking for v7.3, or would you rather it soaked in for v7.4? 2/3 has no DT ack yet either.

Ahmed

Quoted 66 lines
Quoted 66 lines
drivers/pinctrl/airoha/pinctrl-airoha.c +3 -0
+
  static int airoha_pinctrl_add_gpiochip(struct airoha_pinctrl *pinctrl,
  					struct platform_device *pdev)
  {
@@ -362,6 +383,7 @@ static int airoha_pinctrl_add_gpiochip(struct airoha_pinctrl *pinctrl,
  	girq->default_type = IRQ_TYPE_NONE;
  	girq->handler = handle_bad_irq;
+	girq->init_valid_mask = airoha_gpio_init_valid_mask;
  	gpio_irq_chip_set_chip(girq, &airoha_gpio_irq_chip);
  	irq = platform_get_irq(pdev, 0);
@@ -848,6 +870,7 @@ int airoha_pinctrl_probe(struct platform_device *pdev)
  	pinctrl->grps = data->grps;
  	pinctrl->funcs = data->funcs;
  	pinctrl->confs_info = data->confs_info;
+	pinctrl->num_irq_pins = data->num_irq_pins;
  	err = pinctrl_enable(pinctrl->ctrl);
  	if (err)
drivers/pinctrl/airoha/pinctrl-an7563.c +1 -0
index 40cbbe90cc46..f011c6c9ccce 100644
@@ -1069,6 +1069,7 @@ static const struct airoha_pinctrl_match_data pinctrl_match_data = {
  	.num_grps = ARRAY_SIZE(pinctrl_groups),
  	.funcs = pinctrl_funcs,
  	.num_funcs = ARRAY_SIZE(pinctrl_funcs),
+	.num_irq_pins = AIROHA_NUM_PINS,
  	.confs_info = {
  		[AIROHA_PINCTRL_CONFS_PULLUP] = {
  			.confs = pinctrl_pullup_conf,
drivers/pinctrl/airoha/pinctrl-an7581.c +1 -0
index 2fcf88106e11..bfb777594811 100644
@@ -1441,6 +1441,7 @@ static const struct airoha_pinctrl_match_data pinctrl_match_data = {
  	.num_grps = ARRAY_SIZE(pinctrl_groups),
  	.funcs = pinctrl_funcs,
  	.num_funcs = ARRAY_SIZE(pinctrl_funcs),
+	.num_irq_pins = AIROHA_NUM_PINS,
  	.confs_info = {
  		[AIROHA_PINCTRL_CONFS_PULLUP] = {
  			.confs = pinctrl_pullup_conf,
drivers/pinctrl/airoha/pinctrl-an7583.c +1 -0
index 2c3a75c35915..1cd0f442ddc1 100644
@@ -1471,6 +1471,7 @@ static const struct airoha_pinctrl_match_data pinctrl_match_data = {
  	.num_grps = ARRAY_SIZE(pinctrl_groups),
  	.funcs = pinctrl_funcs,
  	.num_funcs = ARRAY_SIZE(pinctrl_funcs),
+	.num_irq_pins = AIROHA_NUM_PINS,
  	.confs_info = {
  		[AIROHA_PINCTRL_CONFS_PULLUP] = {
  			.confs = pinctrl_pullup_conf,
drivers/pinctrl/airoha/pinctrl-en7523.c +1 -0
index 5aa39bacf460..b0c5e60f0aeb 100644
@@ -1113,6 +1113,7 @@ static const struct airoha_pinctrl_match_data pinctrl_match_data = {
  	.num_grps = ARRAY_SIZE(pinctrl_groups),
  	.funcs = pinctrl_funcs,
  	.num_funcs = ARRAY_SIZE(pinctrl_funcs),
+	.num_irq_pins = AIROHA_NUM_PINS,
  	.confs_info = {
  		[AIROHA_PINCTRL_CONFS_PULLUP] = {
  			.confs = pinctrl_pullup_conf,
#5 lore raw

PATCH 2/3 dt-bindings: pinctrl: Add EcoNet EN7528 pin controller

In reply to Ahmed Naseef

Add the binding for the pin controller found on the EcoNet EN7528 MIPS SoC. It shares the IP with the Airoha pin controllers, but its IOMUX and pin configuration registers have a different layout, so it gets its own compatible.

The CHIP SCU holding those registers is referenced by the airoha,chip-scu phandle.

---
 .../pinctrl/econet,en7528-pinctrl.yaml        | 190 ++++++++++++++++++
 1 file changed, 190 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/econet,en7528-pinctrl.yaml
Documentation/devicetree/bindings/pinctrl/econet,en7528-pinctrl.yaml new file +190 -0
new file mode 100644
index 000000000000..574285939c9d
@@ -0,0 +1,190 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/econet,en7528-pinctrl.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: EcoNet EN7528 Pin Controller
+
+maintainers:
+  - Lorenzo Bianconi <[email protected]>
+
+description:
+  The EcoNet EN7528 pin controller is used to control SoC pins. It shares the
+  IP with the Airoha pin controllers, but its IOMUX and pin configuration
+  registers have a different layout.
+
+properties:
+  compatible:
+    const: econet,en7528-pinctrl
+
+  airoha,chip-scu:
+    description: phandle to the chip SCU syscon
+    $ref: /schemas/types.yaml#/definitions/phandle
+
+  interrupts:
+    maxItems: 1
+
+  gpio-controller: true
+
+  '#gpio-cells':
+    const: 2
+
+  gpio-ranges:
+    maxItems: 1
+
+  interrupt-controller: true
+
+  '#interrupt-cells':
+    const: 2
+
+allOf:
+  - $ref: pinctrl.yaml#
+
+required:
+  - compatible
+  - airoha,chip-scu
+  - interrupts
+  - gpio-controller
+  - gpio-ranges
+  - "#gpio-cells"
+  - interrupt-controller
+  - "#interrupt-cells"
+
+patternProperties:
+  '-pins$':
+    type: object
+
+    patternProperties:
+      '^mux(-|$)':
+        type: object
+
+        description:
+          pinmux configuration nodes.
+
+        $ref: /schemas/pinctrl/pinmux-node.yaml
+
+        properties:
+          function:
+            description:
+              A string containing the name of the function to mux to the group.
+            enum: [gpio, jtag, pcie_reset, pcm, pcm_spi, phy1_led0,
+                   phy1_led1, phy2_led0, phy2_led1, phy3_led0, phy3_led1,
+                   phy4_led0, phy4_led1, pnand, pon, pwm, sipo, spi, uart]
+
+          groups:
+            description:
+              An array of strings. Each string contains the name of a group.
+            items:
+              enum: [pon, sipo, sipo_rclk, uart2, uart2_cts_rts, uart3,
+                     ejtag, pcm1, pcm2, spi_quad, spi_cs1, pcm_spi,
+                     pcm_spi_int, pcm_spi_rst, pcm_spi_cs1, pcm_spi_cs2,
+                     pcm_spi_cs3, pcm_spi_cs4, pcm_spi_cs5, pcm_spi_cs6,
+                     pcm_spi_cs7, pnand, gpio0, gpio1, gpio2, gpio3, gpio4,
+                     gpio5, gpio6, gpio7, gpio8, gpio9, gpio10, gpio11,
+                     gpio12, gpio13, gpio14, gpio15, gpio16, gpio17,
+                     gpio18, gpio19, gpio20, gpio21, gpio22, gpio23,
+                     gpio24, gpio25, gpio26, gpio27, gpio28, gpio29,
+                     gpio30, gpio31, gpio32, gpio33, gpio34, gpio35,
+                     gpio36, gpio37, gpio38, gpio39, gpio40, gpio41,
+                     pcie_reset0, pcie_reset1]
+
+        required:
+          - function
+          - groups
+
+        additionalProperties: false
+
+      '^conf(-|$)':
+        type: object
+
+        description:
+          pinconf configuration nodes.
+
+        $ref: /schemas/pinctrl/pincfg-node.yaml
+
+        properties:
+          pins:
+            description:
+              An array of strings. Each string contains the name of a pin.
+            items:
+              enum: [gpio0, gpio1, gpio2, gpio3, gpio4, gpio5, gpio6,
+                     gpio7, gpio8, gpio9, gpio10, gpio11, gpio12, gpio13,
+                     gpio14, gpio15, gpio16, gpio17, gpio18, gpio19,
+                     gpio20, gpio21, gpio22, gpio23, gpio24, gpio25,
+                     gpio26, gpio27, gpio28, gpio29, gpio30, gpio31,
+                     gpio32, gpio33, gpio34, gpio35, gpio36, gpio37,
+                     gpio38, gpio39, pcie_reset0, pcie_reset1, i2c_sda,
+                     i2c_scl, uart_txd, uart_rxd, spi_cs0, spi_clk,
+                     spi_mosi, spi_miso]
+            minItems: 1
+            maxItems: 50
+
+          bias-disable: true
+
+          bias-pull-up: true
+
+          bias-pull-down: true
+
+          input-enable: true
+
+          output-enable: true
+
+          output-low: true
+
+          output-high: true
+
+          drive-strength:
+            description:
+              Selects the drive strength for the pin, in mA.
+            enum: [2, 4]
+
+        required:
+          - pins
+
+        additionalProperties: false
+
+    additionalProperties: false
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/mips-gic.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    pinctrl {
+      compatible = "econet,en7528-pinctrl";
+
+      airoha,chip-scu = <&chip_scu>;
+
+      interrupt-parent = <&gic>;
+      interrupts = <GIC_SHARED 10 IRQ_TYPE_LEVEL_HIGH>;
+
+      gpio-controller;
+      #gpio-cells = <2>;
+
+      interrupt-controller;
+      #interrupt-cells = <2>;
+
+      gpio-ranges = <&pinctrl 0 0 42>;
+
+      uart2-pins {
+        mux {
+          function = "uart";
+          groups = "uart2";
+        };
+
+        conf {
+          pins = "gpio28", "gpio29";
+          bias-pull-up;
+        };
+      };
+
+      pwm-pins {
+        mux {
+          function = "pwm";
+          groups = "gpio30";
+        };
+      };
+    };
Signature · 1 line
2.34.1
#6 lore raw

Re: [PATCH 2/3] dt-bindings: pinctrl: Add EcoNet EN7528 pin controller

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: - [Low] Top-level `additionalProperties: false` incorrectly used instead of `unevaluatedProperties: false`…

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Low] Top-level additionalProperties: false incorrectly used instead of unevaluatedProperties: false, violating schema inheritance rules.
- [Low] Missing node labels for &pinctrl, &chip_scu, and &gic phandles in the DT binding example.
--

--- Patch [2]: [PATCH 2/3] dt-bindings: pinctrl: Add EcoNet EN7528 pin controller --- commit 416526d5ba1573bed48e64c8f0fa2557dff04dcd
Author: Ahmed Naseef <[email protected]>

dt-bindings: pinctrl: Add EcoNet EN7528 pin controller

Add the binding for the pin controller found on the EcoNet EN7528 MIPS SoC. It shares the IP with the Airoha pin controllers, but its IOMUX and pin configuration registers have a different layout, so it gets its own compatible.

Quoted 13 lines
Documentation/devicetree/bindings/pinctrl/econet,en7528-pinctrl.yaml new file +7 -0
new file mode 100644
index 0000000000000..574285939c9d6
@@ -0,0 +1,190 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/econet,en7528-pinctrl.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: EcoNet EN7528 Pin Controller

[ ... ]

Quoted 5 lines
Documentation/devicetree/bindings/pinctrl/econet,en7528-pinctrl.yaml new file +5 -0
+allOf:
+  - $ref: pinctrl.yaml#
+
+required:
+  - compatible

[ ... ]

Documentation/devicetree/bindings/pinctrl/econet,en7528-pinctrl.yaml line 150

Quoted 9 lines
Documentation/devicetree/bindings/pinctrl/econet,en7528-pinctrl.yaml new file +9 -0
+        required:
+          - pins
+
+        additionalProperties: false
+
+    additionalProperties: false
+
+additionalProperties: false
+

[Severity: Low]
Does this prevent the use of common pinctrl properties? Since this schema includes a reference to pinctrl.yaml# earlier in the file, using
additionalProperties: false at the top level will incorrectly reject valid properties inherited from the referenced schema.

Should this be unevaluatedProperties: false instead?

Quoted 10 lines
Documentation/devicetree/bindings/pinctrl/econet,en7528-pinctrl.yaml new file +10 -0
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/mips-gic.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    pinctrl {
+      compatible = "econet,en7528-pinctrl";
+
+      airoha,chip-scu = <&chip_scu>;
+

Documentation/devicetree/bindings/pinctrl/econet,en7528-pinctrl.yaml line 170

Quoted 10 lines
Documentation/devicetree/bindings/pinctrl/econet,en7528-pinctrl.yaml new file +10 -0
+      interrupt-parent = <&gic>;
+      interrupts = <GIC_SHARED 10 IRQ_TYPE_LEVEL_HIGH>;
+
+      gpio-controller;
+      #gpio-cells = <2>;
+
+      interrupt-controller;
+      #interrupt-cells = <2>;
+
+      gpio-ranges = <&pinctrl 0 0 42>;

[Severity: Low]
Will this example fail dt_binding_check compilation due to missing labels? The phandles &chip_scu, &gic, and &pinctrl are referenced here, but they are not defined as labels within the example snippet.

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
#7 lore raw

Re: [PATCH 2/3] dt-bindings: pinctrl: Add EcoNet EN7528 pin controller

Quoted 3 lines · On Sun, Aug 09, 2026 at 08:15:52AM +0000, [email protected] wrote:

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Low] Top-level additionalProperties: false incorrectly used instead of unevaluatedProperties: false, violating schema inheritance rules.
- [Low] Missing node labels for &pinctrl, &chip_scu, and &gic phandles in the DT binding example.

Both can be ignored.

Best regards,
Krzysztof

#8 lore raw

Re: [PATCH 2/3] dt-bindings: pinctrl: Add EcoNet EN7528 pin controller

In reply to Ahmed Naseef
Quoted 5 lines · Ahmed Naseef
Documentation/devicetree/bindings/pinctrl/econet,en7528-pinctrl.yaml new file +5 -0
+maintainers:
+  - Lorenzo Bianconi <[email protected]>
+
+description:
+  The EcoNet EN7528 pin controller is used to control SoC pins. It shares the

Documentation/devicetree/bindings/pinctrl/econet,en7528-pinctrl.yaml line 23

Quoted 10 lines
Documentation/devicetree/bindings/pinctrl/econet,en7528-pinctrl.yaml new file +10 -0
+  IP with the Airoha pin controllers, but its IOMUX and pin configuration
+  registers have a different layout.
+
+properties:
+  compatible:
+    const: econet,en7528-pinctrl
+
+  airoha,chip-scu:
+    description: phandle to the chip SCU syscon
+    $ref: /schemas/types.yaml#/definitions/phandle

If the entire address space is part of the SCU, then this device should be part of the SCU, e.g. its subnode.

Quoted 8 lines
Documentation/devicetree/bindings/pinctrl/econet,en7528-pinctrl.yaml new file +8 -0
+
+  interrupts:
+    maxItems: 1
+
+  gpio-controller: true
+
+  '#gpio-cells':
+    const: 2

Documentation/devicetree/bindings/pinctrl/econet,en7528-pinctrl.yaml line 41

Quoted 10 lines
Documentation/devicetree/bindings/pinctrl/econet,en7528-pinctrl.yaml new file +10 -0
+
+  gpio-ranges:
+    maxItems: 1
+
+  interrupt-controller: true
+
+  '#interrupt-cells':
+    const: 2
+
+allOf:

This goes to the end of the file, before the additionalProperties.

Quoted 5 lines
Documentation/devicetree/bindings/pinctrl/econet,en7528-pinctrl.yaml new file +5 -0
+  - $ref: pinctrl.yaml#
+
+required:
+  - compatible
+  - airoha,chip-scu

Documentation/devicetree/bindings/pinctrl/econet,en7528-pinctrl.yaml line 56

Quoted 10 lines
Documentation/devicetree/bindings/pinctrl/econet,en7528-pinctrl.yaml new file +10 -0
+  - interrupts
+  - gpio-controller
+  - gpio-ranges
+  - "#gpio-cells"
+  - interrupt-controller
+  - "#interrupt-cells"
+
+patternProperties:
+  '-pins$':
+    type: object

"patternProperties" should follow "properties"

Quoted 7 lines
Documentation/devicetree/bindings/pinctrl/econet,en7528-pinctrl.yaml new file +7 -0
+
+    patternProperties:
+      '^mux(-|$)':
+        type: object
+
+        description:
+          pinmux configuration nodes.

Documentation/devicetree/bindings/pinctrl/econet,en7528-pinctrl.yaml line 73

Quoted 10 lines
Documentation/devicetree/bindings/pinctrl/econet,en7528-pinctrl.yaml new file +10 -0
+
+        $ref: /schemas/pinctrl/pinmux-node.yaml
+
+        properties:
+          function:
+            description:
+              A string containing the name of the function to mux to the group.
+            enum: [gpio, jtag, pcie_reset, pcm, pcm_spi, phy1_led0,
+                   phy1_led1, phy2_led0, phy2_led1, phy3_led0, phy3_led1,
+                   phy4_led0, phy4_led1, pnand, pon, pwm, sipo, spi, uart]

Best regards,
Krzysztof

#9 lore raw

Re: [PATCH 2/3] dt-bindings: pinctrl: Add EcoNet EN7528 pin controller

Quoted 11 lines · Krzysztof Kozlowski
Quoted 10 lines · Ahmed Naseef
Documentation/devicetree/bindings/pinctrl/econet,en7528-pinctrl.yaml new file +10 -0
+maintainers:
+  - Lorenzo Bianconi <[email protected]>
+
+description:
+  The EcoNet EN7528 pin controller is used to control SoC pins. It shares the
+  IP with the Airoha pin controllers, but its IOMUX and pin configuration
+  registers have a different layout.
+
+properties:
+  compatible:
Quoted 8 lines

Documentation/devicetree/bindings/pinctrl/econet,en7528-pinctrl.yaml line 23

Quoted 5 lines
Documentation/devicetree/bindings/pinctrl/econet,en7528-pinctrl.yaml new file +5 -0
+    const: econet,en7528-pinctrl
+
+  airoha,chip-scu:
+    description: phandle to the chip SCU syscon
+    $ref: /schemas/types.yaml#/definitions/phandle

If the entire address space is part of the SCU, then this device should be part of the SCU, e.g. its subnode.

It is not: the registers are split over two blocks. The GPIO, interrupt and PWM flash-mode registers are in the block the node sits under, and the IOMUX and pin configuration registers are in the SCU. Both are needed, so whichever of the two is the parent, the other one has to come in by phandle.

Quoted 13 lines
Quoted 13 lines
Documentation/devicetree/bindings/pinctrl/econet,en7528-pinctrl.yaml new file +12 -0
+
+  interrupts:
+    maxItems: 1
+
+  gpio-controller: true
+
+  '#gpio-cells':
+    const: 2
+
+  gpio-ranges:
+    maxItems: 1
+
Quoted 9 lines

Documentation/devicetree/bindings/pinctrl/econet,en7528-pinctrl.yaml line 41

Quoted 6 lines
Documentation/devicetree/bindings/pinctrl/econet,en7528-pinctrl.yaml new file +6 -0
+  interrupt-controller: true
+
+  '#interrupt-cells':
+    const: 2
+
+allOf:

This goes to the end of the file, before the additionalProperties.

Will address in v2.

Quoted 9 lines
Quoted 9 lines
Documentation/devicetree/bindings/pinctrl/econet,en7528-pinctrl.yaml new file +9 -0
+  - $ref: pinctrl.yaml#
+
+required:
+  - compatible
+  - airoha,chip-scu
+  - interrupts
+  - gpio-controller
+  - gpio-ranges
+  - "#gpio-cells"
Quoted 9 lines

Documentation/devicetree/bindings/pinctrl/econet,en7528-pinctrl.yaml line 56

Quoted 6 lines
Documentation/devicetree/bindings/pinctrl/econet,en7528-pinctrl.yaml new file +6 -0
+  - interrupt-controller
+  - "#interrupt-cells"
+
+patternProperties:
+  '-pins$':
+    type: object

"patternProperties" should follow "properties"

Will address in v2.

Thanks for the review!

Ahmed

Quoted 20 lines
Quoted 7 lines
Documentation/devicetree/bindings/pinctrl/econet,en7528-pinctrl.yaml new file +7 -0
+
+    patternProperties:
+      '^mux(-|$)':
+        type: object
+
+        description:
+          pinmux configuration nodes.

Documentation/devicetree/bindings/pinctrl/econet,en7528-pinctrl.yaml line 73

Quoted 10 lines
Documentation/devicetree/bindings/pinctrl/econet,en7528-pinctrl.yaml new file +10 -0
+
+        $ref: /schemas/pinctrl/pinmux-node.yaml
+
+        properties:
+          function:
+            description:
+              A string containing the name of the function to mux to the group.
+            enum: [gpio, jtag, pcie_reset, pcm, pcm_spi, phy1_led0,
+                   phy1_led1, phy2_led0, phy2_led1, phy3_led0, phy3_led1,
+                   phy4_led0, phy4_led1, pnand, pon, pwm, sipo, spi, uart]

Best regards,
Krzysztof

#10 lore raw

Re: [PATCH 2/3] dt-bindings: pinctrl: Add EcoNet EN7528 pin controller

Quoted 21 lines · Ahmed Naseef
Quoted 11 lines · Krzysztof Kozlowski
Quoted 10 lines · Ahmed Naseef
Documentation/devicetree/bindings/pinctrl/econet,en7528-pinctrl.yaml new file +10 -0
+maintainers:
+  - Lorenzo Bianconi <[email protected]>
+
+description:
+  The EcoNet EN7528 pin controller is used to control SoC pins. It shares the
+  IP with the Airoha pin controllers, but its IOMUX and pin configuration
+  registers have a different layout.
+
+properties:
+  compatible:
Quoted 8 lines

Documentation/devicetree/bindings/pinctrl/econet,en7528-pinctrl.yaml line 23

Quoted 5 lines
Documentation/devicetree/bindings/pinctrl/econet,en7528-pinctrl.yaml new file +5 -0
+    const: econet,en7528-pinctrl
+
+  airoha,chip-scu:
+    description: phandle to the chip SCU syscon
+    $ref: /schemas/types.yaml#/definitions/phandle

If the entire address space is part of the SCU, then this device should be part of the SCU, e.g. its subnode.

Quoted 5 lines

It is not: the registers are split over two blocks. The GPIO, interrupt and PWM flash-mode registers are in the block the node sits under, and the IOMUX and pin configuration registers are in the SCU. Both are needed, so whichever of the two is the parent, the other one has to come in by phandle.

Sure, one is parent and other is sibling. This is standard. But non-standard is to claim to have no MMIO but then get that MMIO from someone else...

Best regards,
Krzysztof

#11 lore raw

PATCH 3/3 pinctrl: airoha: add support of en7528 SoC

In reply to Ahmed Naseef

From: Benjamin Larsson <[email protected]>

The EcoNet EN7528 MIPS SoC uses the same pin controller and GPIO IP as the Airoha SoCs, so it can reuse the shared driver code. Its register layout differs from every existing variant though: all IOMUX mode bits live in a single CHIP SCU register (RG_PON_I2C_MODE at 0x15c) plus the spill-over bits in IOMUX Control 3 (0x224), EJTAG has its own enable register at 0x1ac, the LED mapping registers sit at 0x1b0/0x1b4 and all pin configuration registers are at different offsets than on EN7523.

Pin numbering follows the GPIO line numbering, so pins 0-41 map to GPIO0-GPIO41. Pins 42-49 are the standalone I2C/UART/SPI pads, which have no GPIO function and are only referenced by the pinconf tables.

Only GPIO0-GPIO15 are wired to the interrupt controller, so num_irq_pins is 16. EN7528 has no PCIe reset open drain register, so AIROHA_PINCTRL_CONFS_PCIE_RST_OD is left empty and PIN_CONFIG_DRIVE_OPEN_DRAIN is rejected for all pins.

---
 drivers/pinctrl/airoha/Kconfig          |   15 +-
 drivers/pinctrl/airoha/Makefile         |    1 +
 drivers/pinctrl/airoha/pinctrl-en7528.c | 1204 +++++++++++++++++++++++
 3 files changed, 1218 insertions(+), 2 deletions(-)
 create mode 100644 drivers/pinctrl/airoha/pinctrl-en7528.c
drivers/pinctrl/airoha/Kconfig +13 -2
index 22b8f850cee1..0f0986c81219 100644
@@ -1,11 +1,11 @@
 # SPDX-License-Identifier: GPL-2.0-only
 menu "Airoha pinctrl drivers"
-	depends on ARCH_AIROHA || COMPILE_TEST
+	depends on ARCH_AIROHA || ECONET || COMPILE_TEST
 
 config PINCTRL_AIROHA
 	tristate "Airoha pin control"
 	depends on OF
-	depends on ARCH_AIROHA || COMPILE_TEST
+	depends on ARCH_AIROHA || ECONET || COMPILE_TEST
 	select PINMUX
 	select GENERIC_PINCONF
 	select GENERIC_PINCTRL_GROUPS
@@ -17,6 +17,7 @@ config PINCTRL_AIROHA
 	imply PINCTRL_AIROHA_AN7581
 	imply PINCTRL_AIROHA_AN7583
 	imply PINCTRL_AIROHA_EN7523
+	imply PINCTRL_AIROHA_EN7528
 	help
 	  Shared pin controller and gpio driver code for different
 	  Airoha SoCs.
@@ -53,4 +54,14 @@ config PINCTRL_AIROHA_EN7523
 	  Say yes here to support pin controller and gpio driver
 	  on Airoha EN7523, EN7529, EN7562 and other compatible SoCs.
 
+config PINCTRL_AIROHA_EN7528
+	tristate "EN7528 pinctrl"
+	depends on ECONET || COMPILE_TEST
+	depends on PINCTRL_AIROHA
+	help
+	  Say yes here to support pin controller and gpio driver
+	  on EcoNet EN7528 and other compatible SoCs. Unlike the
+	  other variants, only the first sixteen GPIOs of this SoC
+	  are wired to the interrupt controller.
+
 endmenu
drivers/pinctrl/airoha/Makefile +1 -0
index 30e4bee57a4a..4dc7c556ce4d 100644
@@ -8,3 +8,4 @@ obj-$(CONFIG_PINCTRL_AIROHA_AN7563)	+= pinctrl-an7563.o
 obj-$(CONFIG_PINCTRL_AIROHA_AN7581)	+= pinctrl-an7581.o
 obj-$(CONFIG_PINCTRL_AIROHA_AN7583)	+= pinctrl-an7583.o
 obj-$(CONFIG_PINCTRL_AIROHA_EN7523)	+= pinctrl-en7523.o
+obj-$(CONFIG_PINCTRL_AIROHA_EN7528)	+= pinctrl-en7528.o
drivers/pinctrl/airoha/pinctrl-en7528.c new file +1204 -0

1,204 lines not on this page · raw message

Signature · 1 line
2.34.1
maintainer
#12 lore raw
In reply to Ahmed Naseef

Hi Ahmed,

thanks for your patches!

Quoted 3 lines · Ahmed Naseef

The series is based on linux-pinctrl/for-next, as it depends on the per-SoC driver split and on the CHIP SCU lookup by "airoha,chip-scu" phandle that landed there.

If we can get a speedy review on these patches I don't mind merging them for v7.3 already, it's nice to get some movement on all the nice Airoha silicon.

Yours,
Linus Walleij

#13 lore raw

Il giorno lun 10 ago 2026 alle ore 09:23 Linus Walleij <[email protected]> ha scritto:

Quoted 7 lines

Hi Ahmed,

thanks for your patches!

On Sun, Aug 9, 2026 at 10:05 AM Ahmed Naseef <[email protected]> wrote:

Quoted 8 lines
Quoted 3 lines

The series is based on linux-pinctrl/for-next, as it depends on the per-SoC driver split and on the CHIP SCU lookup by "airoha,chip-scu" phandle that landed there.

If we can get a speedy review on these patches I don't mind merging them for v7.3 already, it's nice to get some movement on all the nice Airoha silicon.

Hi Linus,

I wonder if the same speed treatment can be done also for the clock driver and also dts?
There are a few patch there that are currently blocking usb phy and pcie...

maintainer
#14 lore raw
Quoted 10 lines · Christian Marangi (Ansuel)

Il giorno lun 10 ago 2026 alle ore 09:23 Linus Walleij <[email protected]> ha scritto:

Quoted 3 lines

If we can get a speedy review on these patches I don't mind merging them for v7.3 already, it's nice to get some movement on all the nice Airoha silicon.

I wonder if the same speed treatment can be done also for the clock driver and also dts?
There are a few patch there that are currently blocking usb phy and pcie...

Heh not my department. I think the SoC maintainers can merge some late DTS patches, the clock driver is up to the clock maintainers.

Yours,
Linus Walleij