Linux GPIO subsystem development
 help / color / mirror / Atom feed
* [PATCH 00/12]  pinctrl: airoha: configure GPIO muxes explicitly and fix pad mappings
@ 2026-11-10  9:43 Zhengping Zhang
  2026-11-10  9:43 ` [PATCH 01/12] pinctrl: airoha: fix setting of GPIO direction Zhengping Zhang
                   ` (11 more replies)
  0 siblings, 12 replies; 17+ messages in thread
From: Zhengping Zhang @ 2026-11-10  9:43 UTC (permalink / raw)
  To: linusw, lorenzo
  Cc: robh, krzk+dt, conor+dt, brgl, mikhail.kshevetskiy, naseefkm,
	benjamin.larsson, linux-gpio, devicetree, linux-kernel,
	linux-mediatek, lei.dong, ansuelsmth, Zhengping Zhang

This series makes GPIO mode selection explicit on AN7581, AN7583 and
EN7523, and fixes related GPIO direction, LED group and SPI/eMMC mux
configuration issues.

Background
----------
GPIO direction and data register programming is separate from pad mux
selection on these SoCs. The current GPIO request path does not select
the GPIO function, relying on the pads already being in an appropriate
state. If the bootloader leaves a pad configured for an alternate
function, a GPIO request can succeed without connecting the GPIO
controller to the pad. Output writes may then fail to drive the pin,
and input reads may not reflect the external signal.
The problem also affects the opposite transition. Once a pad has been
forced to GPIO mode, selecting its peripheral mux without releasing
the GPIO override can leave the peripheral disconnected from the pad.
While addressing these transitions, the series also corrects GPIO
direction programming, AN7581 PHY LED group assignments, AN7583 SPI/eMMC
mux configuration and the EN7523 128-pin PCM SPI CS2 pad assignment.

Implementation
--------------
On these SoCs, shared GPIO pads can be routed to peripheral functions
through mux control bits in the SCU registers. In the absence of an
enabled alternate function, these shared pads normally operate as
GPIOs. Dedicated peripheral pads have separate selectors for GPIO
operation, so clearing all mux bits is not a universal way to select
GPIO mode.

Per-pad force GPIO controls allow individual shared pads to operate
as GPIOs while leaving shared peripheral mode settings intact for
other pads. GPIO-controller PWM output also requires the appropriate
pad routing: selecting ordinary GPIO operation clears the pad's PWM
selection, while PWM operation uses the PWM selection together with
the applicable GPIO routing controls.

The series uses these per-pad controls to configure GPIO mode on
demand. Resetting the IOMUX registers at probe could disrupt interfaces
still using bootloader settings, while clearing shared peripheral
mode bits could affect pads outside the requested group.

The common driver gains a gpio_request_enable callback and identifies
GPIO-category functions through the pinmux core. It finds the matching
single-pin GPIO group using pinctrl pin numbers, including controllers
whose GPIO ranges have a nonzero pin base. GPIO requests and explicit
GPIO pinctrl states apply the same SoC-specific group configuration.

The common code checks for incompatible values of shared mux bits
against GPIO owners and claimed mux groups. Validation and register
updates are serialized, and register update failures are returned to
the caller. GPIO request handling and conflict checks are enabled
through SoC match data.

The SoC-specific changes select GPIO mode as follows:

  - AN7581: GPIO1-31 use SCU 0x228, and GPIO32-46 use 0x22c.
    GPIO47-49 retain their PCIe reset GPIO selectors at 0x21c.
    GPIO1/2 additionally require the I2C/MDIO routing to be disabled.

  - AN7583: GPIO1-31 use SCU 0x228, and GPIO32-38 use 0x22c.
    GPIO39-52 use the dedicated-pad GPIO selectors at 0x21c.

  - EN7523: GPIO0-29 use SCU 0x224. GPIO28/29 also retain their
    existing PCIe reset GPIO selector settings at 0x218.

AN7581 and AN7583 have no documented force GPIO bit for GPIO0; their
GPIO0 configuration clears the existing PWM selection only.

Peripheral group configurations release the corresponding GPIO
overrides when selecting their functions. AN7581 retains its existing
MDIO and PWM configurations; AN7583 and EN7523 also enable the required
GPIO overrides when selecting GPIO-controller PWM output.

The AN7583 and EN7523 PON groups exclude the software-controlled
TX_DIS/RX_DIS pads so they can be requested independently as GPIOs by
the PON PHY driver, avoiding ownership conflicts with PON mux selection.

The bindings describe the expanded GPIO groups and corrected pad
assignments. GPIO numbering and existing compatible strings are retained.
The final patch adds an Airoha co-maintainer and extends the maintained
file patterns to cover the SoC-specific drivers and bindings.

Validation
----------
Tested the PINCTRL functionality on AN7581, AN7583 and EN7523 using OpenWrt
master (backport to kernel 6.18), including build tests and explicit GPIO
requests, with particular attention to GPIO-controlled LEDs.

Daniel Schwierzeck (2):
  pinctrl: airoha: fix setting of GPIO direction
  pinctrl: airoha: an7583: fix SPI pin mux config

Robert Marko (1):
  pinctrl: airoha: an7583: fix eMMC pin mux config

Zhengping Zhang (9):
  pinctrl: airoha: configure pin muxes on GPIO requests
  dt-bindings: pinctrl: airoha: describe all EN7581 GPIO mux groups
  pinctrl: airoha: an7581: fix PHY LED GPIO group assignments
  pinctrl: airoha: an7581: select force GPIO mode on GPIO requests
  dt-bindings: pinctrl: airoha: describe all AN7583 GPIO mux groups
  pinctrl: airoha: an7583: use force GPIO mode for GPIO requests
  dt-bindings: pinctrl: airoha: describe all EN7523 GPIO mux groups
  pinctrl: airoha: en7523: use force GPIO mode for GPIO requests
  MAINTAINERS: add myself as Airoha pinctrl co-maintainer

 .../pinctrl/airoha,an7583-pinctrl.yaml        |  18 +-
 .../pinctrl/airoha,en7523-pinctrl.yaml        |   9 +-
 .../pinctrl/airoha,en7581-pinctrl.yaml        |  28 +-
 MAINTAINERS                                   |   5 +-
 drivers/pinctrl/airoha/airoha-common.h        |  15 +-
 drivers/pinctrl/airoha/pinctrl-airoha.c       | 263 ++++++-
 drivers/pinctrl/airoha/pinctrl-an7581.c       | 629 ++++++++++++---
 drivers/pinctrl/airoha/pinctrl-an7583.c       | 736 ++++++++++++++----
 drivers/pinctrl/airoha/pinctrl-en7523.c       | 579 +++++++++++---
 9 files changed, 1855 insertions(+), 427 deletions(-)


base-commit: 05441d697f7f9a927264f4058cbbc6a03dfcac9d
-- 
2.43.0


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

* [PATCH 01/12] pinctrl: airoha: fix setting of GPIO direction
  2026-11-10  9:43 [PATCH 00/12] pinctrl: airoha: configure GPIO muxes explicitly and fix pad mappings Zhengping Zhang
@ 2026-11-10  9:43 ` Zhengping Zhang
  2026-11-10  9:53   ` sashiko-bot
  2026-11-10  9:43 ` [PATCH 02/12] pinctrl: airoha: configure pin muxes on GPIO requests Zhengping Zhang
                   ` (10 subsequent siblings)
  11 siblings, 1 reply; 17+ messages in thread
From: Zhengping Zhang @ 2026-11-10  9:43 UTC (permalink / raw)
  To: linusw, lorenzo
  Cc: robh, krzk+dt, conor+dt, brgl, mikhail.kshevetskiy, naseefkm,
	benjamin.larsson, linux-gpio, devicetree, linux-kernel,
	linux-mediatek, lei.dong, ansuelsmth, Daniel Schwierzeck,
	Zhengping Zhang

From: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>

The GPIO_CTRL registers have two bits per GPIO where the values 0x2 and
0x3 are reserved. It can happen that both bits in GPIO_CTRL of a GPIO
are set when the pinctrl driver is probed (e.g. modified by bootloader),
but the current code just clears the LSB. Thus when switching a certain
GPIO to output, the updated GPIO_CTRL register can contain the reserved
value 0x2 for that GPIO. This can result in not driving the GPIO pin at
all.

Always clear both bits per GPIO and just set the LSB when the GPIO is
configured for output.

Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
Signed-off-by: Zhengping Zhang <zhengping.zhang@airoha.com>
---
 drivers/pinctrl/airoha/pinctrl-airoha.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/pinctrl/airoha/pinctrl-airoha.c b/drivers/pinctrl/airoha/pinctrl-airoha.c
index 52a768c859b71..8dd0881bba4ad 100644
--- a/drivers/pinctrl/airoha/pinctrl-airoha.c
+++ b/drivers/pinctrl/airoha/pinctrl-airoha.c
@@ -164,7 +164,7 @@ static int airoha_gpio_set_direction(struct gpio_chip *chip, unsigned int gpio,
 {
 	struct airoha_pinctrl *pinctrl = gpiochip_get_data(chip);
 	u32 mask, index;
-	int err;
+	int err, offset;
 
 	/* set output enable */
 	mask = BIT(gpio % AIROHA_PIN_BANK_SIZE);
@@ -176,12 +176,13 @@ static int airoha_gpio_set_direction(struct gpio_chip *chip, unsigned int gpio,
 		return err;
 
 	/* set direction */
-	mask = BIT(2 * (gpio % AIROHA_REG_GPIOCTRL_NUM_PIN));
+	offset = 2 * (gpio % AIROHA_REG_GPIOCTRL_NUM_PIN);
+	mask = GENMASK(offset + 1, offset); /* always clear the two bits per GPIO */
 	index = gpio / AIROHA_REG_GPIOCTRL_NUM_PIN;
 
 	return regmap_update_bits(pinctrl->regmap,
 				  pinctrl->gpio_regs->dir[index], mask,
-				  !input ? mask : 0);
+				  !input ? BIT(offset) : 0);
 }
 
 static int airoha_gpio_direction_input(struct gpio_chip *chip,
-- 
2.43.0


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

* [PATCH 02/12] pinctrl: airoha: configure pin muxes on GPIO requests
  2026-11-10  9:43 [PATCH 00/12] pinctrl: airoha: configure GPIO muxes explicitly and fix pad mappings Zhengping Zhang
  2026-11-10  9:43 ` [PATCH 01/12] pinctrl: airoha: fix setting of GPIO direction Zhengping Zhang
@ 2026-11-10  9:43 ` Zhengping Zhang
  2026-11-10 10:14   ` sashiko-bot
  2026-11-10  9:43 ` [PATCH 03/12] dt-bindings: pinctrl: airoha: describe all EN7581 GPIO mux groups Zhengping Zhang
                   ` (9 subsequent siblings)
  11 siblings, 1 reply; 17+ messages in thread
From: Zhengping Zhang @ 2026-11-10  9:43 UTC (permalink / raw)
  To: linusw, lorenzo
  Cc: robh, krzk+dt, conor+dt, brgl, mikhail.kshevetskiy, naseefkm,
	benjamin.larsson, linux-gpio, devicetree, linux-kernel,
	linux-mediatek, lei.dong, ansuelsmth, Zhengping Zhang

GPIO requests currently leave the pin mux unchanged, relying on the
pins already being configured for GPIO operation. A pin configured
for an alternate function by the bootloader can therefore remain
disconnected from the GPIO controller despite being requested as a GPIO.

Add a GPIO request callback that selects the matching single-pin group
from a GPIO-category function. Reuse the group configuration used by
explicit GPIO pinctrl states and resolve pins using pinctrl pin numbers
to support GPIO ranges with a nonzero pin base.

Shared mux bits can affect pins outside the requested group. Add
SoC-selectable checks against GPIO owners and claimed mux groups,
rejecting incompatible register settings with -EBUSY. Serialize these
checks and mux register updates, and propagate register update errors.

Extend function-group configurations to up to three register updates
for GPIO and peripheral mux sequences. Enable GPIO request handling and
conflict checks through SoC match data, leaving GPIO request behavior
unchanged until a SoC opts in.

Signed-off-by: Zhengping Zhang <zhengping.zhang@airoha.com>
---
 drivers/pinctrl/airoha/airoha-common.h  |  15 +-
 drivers/pinctrl/airoha/pinctrl-airoha.c | 256 ++++++++++++++++++++----
 2 files changed, 234 insertions(+), 37 deletions(-)

diff --git a/drivers/pinctrl/airoha/airoha-common.h b/drivers/pinctrl/airoha/airoha-common.h
index 16f7abcdfb832..dbfb33a00b717 100644
--- a/drivers/pinctrl/airoha/airoha-common.h
+++ b/drivers/pinctrl/airoha/airoha-common.h
@@ -49,6 +49,14 @@
 		.group_size = ARRAY_SIZE(table##_func_group),		\
 	}
 
+#define PINCTRL_GPIO_FUNC_DESC(id, table)					\
+	{								\
+		.desc = PINCTRL_GPIO_PINFUNCTION(id, table##_groups,	\
+					 ARRAY_SIZE(table##_groups)),	\
+		.groups = table##_func_group,				\
+		.group_size = ARRAY_SIZE(table##_func_group),		\
+	}
+
 #define PINCTRL_CONF_DESC(p, offset, mask)				\
 	{								\
 		.pin = p,						\
@@ -73,7 +81,7 @@ struct airoha_pinctrl_func_group {
 		u32 offset;
 		u32 mask;
 		u32 val;
-	} regmap[2];
+	} regmap[3];
 	int regmap_size;
 };
 
@@ -115,6 +123,10 @@ enum airoha_pinctrl_confs_type {
 };
 
 struct airoha_pinctrl {
+	/* Serialize shared mux validation and register updates. */
+	struct mutex mux_lock;
+	bool check_mux_conflicts;
+
 	struct pinctrl_dev *ctrl;
 
 	struct pinctrl_desc desc;
@@ -131,6 +143,7 @@ struct airoha_pinctrl {
 };
 
 struct airoha_pinctrl_match_data {
+	bool check_mux_conflicts;
 	const char *chip_scu_compatible;
 	const char *pinctrl_name;
 	struct module *pinctrl_owner;
diff --git a/drivers/pinctrl/airoha/pinctrl-airoha.c b/drivers/pinctrl/airoha/pinctrl-airoha.c
index 8dd0881bba4ad..25562e51ebbdc 100644
--- a/drivers/pinctrl/airoha/pinctrl-airoha.c
+++ b/drivers/pinctrl/airoha/pinctrl-airoha.c
@@ -400,57 +400,236 @@ static int airoha_pinctrl_add_gpiochip(struct airoha_pinctrl *pinctrl,
 }
 
 /* pinmux callbacks */
-static int airoha_pinmux_set_mux(struct pinctrl_dev *pctrl_dev,
-				 unsigned int selector,
-				 unsigned int group)
+static const struct airoha_pinctrl_func_group *
+airoha_pinmux_get_func_group(struct pinctrl_dev *pctldev,
+			    unsigned int selector, unsigned int group)
 {
-	struct airoha_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
-	const struct airoha_pinctrl_func *func;
 	const struct function_desc *desc;
+	const struct airoha_pinctrl_func *func;
 	struct group_desc *grp;
 	int i;
 
-	desc = pinmux_generic_get_function(pctrl_dev, selector);
-	if (!desc)
-		return -EINVAL;
+	desc = pinmux_generic_get_function(pctldev, selector);
+	grp = pinctrl_generic_get_group(pctldev, group);
+	if (!desc || !grp)
+		return NULL;
 
-	grp = pinctrl_generic_get_group(pctrl_dev, group);
-	if (!grp)
-		return -EINVAL;
+	func = desc->data;
+	for (i = 0; i < func->group_size; i++)
+		if (!strcmp(func->groups[i].name, grp->grp.name))
+			return &func->groups[i];
 
-	dev_dbg(pctrl_dev->dev, "enable function %s group %s\n",
-		desc->func->name, grp->grp.name);
+	return NULL;
+}
 
-	func = desc->data;
-	for (i = 0; i < func->group_size; i++) {
-		const struct airoha_pinctrl_func_group *group;
-		int j;
+/* Shared mux bits can affect pads outside the requested pin group. */
+static bool
+airoha_pinmux_groups_conflict(const struct airoha_pinctrl_func_group *a,
+			     const struct airoha_pinctrl_func_group *b)
+{
+	int i, j;
+
+	for (i = 0; i < a->regmap_size; i++) {
+		for (j = 0; j < b->regmap_size; j++) {
+			u32 mask;
 
-		group = &func->groups[i];
-		if (strcmp(group->name, grp->grp.name))
+			if ((a->regmap[i].mux == AIROHA_FUNC_MUX) !=
+			    (b->regmap[j].mux == AIROHA_FUNC_MUX) ||
+			    a->regmap[i].offset != b->regmap[j].offset)
+				continue;
+
+			mask = a->regmap[i].mask & b->regmap[j].mask;
+			if (mask & (a->regmap[i].val ^ b->regmap[j].val))
+				return true;
+		}
+	}
+
+	return false;
+}
+
+/* Use pinctrl pin numbers, including GPIO ranges with nonzero pin_base. */
+static const struct airoha_pinctrl_func_group *
+airoha_pinmux_get_gpio_group(struct pinctrl_dev *pctldev, unsigned int pin)
+{
+	unsigned int selector, count;
+
+	count = pinmux_generic_get_function_count(pctldev);
+	for (selector = 0; selector < count; selector++) {
+		const struct airoha_pinctrl_func *func;
+		const struct function_desc *desc;
+		int i;
+
+		if (!pinmux_generic_function_is_gpio(pctldev, selector))
+			continue;
+		desc = pinmux_generic_get_function(pctldev, selector);
+		if (!desc)
 			continue;
 
-		for (j = 0; j < group->regmap_size; j++) {
-			switch (group->regmap[j].mux) {
-			case AIROHA_FUNC_PWM_EXT_MUX:
-			case AIROHA_FUNC_PWM_MUX:
-				regmap_update_bits(pinctrl->regmap,
-						   group->regmap[j].offset,
-						   group->regmap[j].mask,
-						   group->regmap[j].val);
-				break;
-			default:
-				regmap_update_bits(pinctrl->chip_scu,
-						   group->regmap[j].offset,
-						   group->regmap[j].mask,
-						   group->regmap[j].val);
-				break;
-			}
+		func = desc->data;
+		for (i = 0; i < func->group_size; i++) {
+			struct group_desc *grp;
+			int group;
+
+			group = pinctrl_get_group_selector(pctldev,
+						   func->groups[i].name);
+			if (group < 0)
+				continue;
+			grp = pinctrl_generic_get_group(pctldev, group);
+			if (grp && grp->grp.npins == 1 &&
+			    grp->grp.pins[0] == pin)
+				return &func->groups[i];
 		}
+	}
+
+	return NULL;
+}
+
+static int
+airoha_pinmux_check_conflicts(struct pinctrl_dev *pctldev,
+			     const struct airoha_pinctrl_func_group *group)
+{
+	unsigned int i;
+
+	for (i = 0; i < pctldev->desc->npins; i++) {
+		const struct airoha_pinctrl_func_group *active;
+		struct pinctrl_setting_mux setting;
+		unsigned int number = pctldev->desc->pins[i].number;
+		struct pin_desc *pin;
+		bool claimed, gpio_owned;
+
+		pin = pin_desc_get(pctldev, number);
+		if (!pin)
+			continue;
+
+		scoped_guard(mutex, &pin->mux_lock) {
+			claimed = pin->mux_usecount && pin->mux_setting;
+			gpio_owned = !!pin->gpio_owner;
+			if (claimed)
+				setting = *pin->mux_setting;
+		}
+
+		/* GPIO requests need no explicit DTS pinctrl state. */
+		if (gpio_owned) {
+			active = airoha_pinmux_get_gpio_group(pctldev, number);
+			if (!active)
+				return -EOPNOTSUPP;
+			if (airoha_pinmux_groups_conflict(group, active))
+				goto conflict;
+		}
+
+		if (!claimed)
+			continue;
+		active = airoha_pinmux_get_func_group(pctldev, setting.func,
+						    setting.group);
+		if (!active)
+			return -EINVAL;
+		if (!airoha_pinmux_groups_conflict(group, active))
+			continue;
+
+conflict:
+		dev_err(pctldev->dev,
+			"group %s conflicts with shared mux bits of group %s\n",
+			group->name, active->name);
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+/* Caller holds mux_lock across validation and the register updates. */
+static int
+airoha_pinmux_apply_group(struct airoha_pinctrl *pinctrl,
+			 const struct airoha_pinctrl_func_group *config)
+{
+	int i, err;
+
+	for (i = 0; i < config->regmap_size; i++) {
+		struct regmap *map;
+
+		if (!config->regmap[i].mask)
+			continue;
+		map = config->regmap[i].mux == AIROHA_FUNC_MUX ?
+		      pinctrl->chip_scu : pinctrl->regmap;
+		err = regmap_update_bits(map, config->regmap[i].offset,
+					 config->regmap[i].mask,
+					 config->regmap[i].val);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int
+airoha_gpio_request_enable(struct pinctrl_dev *pctldev,
+			   struct pinctrl_gpio_range *range, unsigned int pin)
+{
+	struct airoha_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev);
+	const struct airoha_pinctrl_func_group *config;
+	int err;
+
+	/* Other SoCs retain their existing request behavior. */
+	if (!pinctrl->check_mux_conflicts)
 		return 0;
+	if (!range)
+		return -EINVAL;
+
+	config = airoha_pinmux_get_gpio_group(pctldev, pin);
+	if (!config)
+		return dev_err_probe(pctldev->dev, -EOPNOTSUPP,
+				     "no verified GPIO mux for pin %u\n", pin);
+
+	guard(mutex)(&pinctrl->mux_lock);
+	err = airoha_pinmux_check_conflicts(pctldev, config);
+	if (err)
+		return err;
+
+	dev_dbg(pctldev->dev, "request GPIO mux group %s pin %u\n",
+		config->name, pin);
+	return airoha_pinmux_apply_group(pinctrl, config);
+}
+
+static int airoha_pinmux_set_mux(struct pinctrl_dev *pctldev,
+			       unsigned int selector, unsigned int group)
+{
+	struct airoha_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev);
+	const struct airoha_pinctrl_func_group *config;
+	int i, err;
+
+	config = airoha_pinmux_get_func_group(pctldev, selector, group);
+	if (!config)
+		return -EINVAL;
+
+	guard(mutex)(&pinctrl->mux_lock);
+	if (pinctrl->check_mux_conflicts) {
+		struct group_desc *grp;
+
+		/* The core permits GPIO-category muxes alongside GPIO owners. */
+		grp = pinctrl_generic_get_group(pctldev, group);
+		if (!pinmux_generic_function_is_gpio(pctldev, selector)) {
+			for (i = 0; i < grp->grp.npins; i++) {
+				struct pin_desc *pin;
+
+				pin = pin_desc_get(pctldev, grp->grp.pins[i]);
+				if (!pin)
+					return -EINVAL;
+				scoped_guard(mutex, &pin->mux_lock) {
+					if (pin->gpio_owner)
+						return -EBUSY;
+				}
+			}
+		}
+
+		err = airoha_pinmux_check_conflicts(pctldev, config);
+		if (err)
+			return err;
 	}
 
-	return -EINVAL;
+	dev_dbg(pctldev->dev, "enable function %s group %s\n",
+		pinmux_generic_get_function_name(pctldev, selector),
+		config->name);
+
+	return airoha_pinmux_apply_group(pinctrl, config);
 }
 
 static int airoha_pinmux_set_direction(struct pinctrl_dev *pctrl_dev,
@@ -468,6 +647,8 @@ static int airoha_pinmux_set_direction(struct pinctrl_dev *pctrl_dev,
 }
 
 static const struct pinmux_ops airoha_pmxops = {
+	.gpio_request_enable = airoha_gpio_request_enable,
+	.function_is_gpio = pinmux_generic_function_is_gpio,
 	.get_functions_count = pinmux_generic_get_function_count,
 	.get_function_name = pinmux_generic_get_function_name,
 	.get_function_groups = pinmux_generic_get_function_groups,
@@ -823,6 +1004,9 @@ int airoha_pinctrl_probe(struct platform_device *pdev)
 
 	pinctrl->chip_scu = map;
 
+	mutex_init(&pinctrl->mux_lock);
+	pinctrl->check_mux_conflicts = data->check_mux_conflicts;
+
 	/* Init pinctrl desc struct */
 	pinctrl->desc.name = data->pinctrl_name;
 	pinctrl->desc.owner = data->pinctrl_owner;
-- 
2.43.0


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

* [PATCH 03/12] dt-bindings: pinctrl: airoha: describe all EN7581 GPIO mux groups
  2026-11-10  9:43 [PATCH 00/12] pinctrl: airoha: configure GPIO muxes explicitly and fix pad mappings Zhengping Zhang
  2026-11-10  9:43 ` [PATCH 01/12] pinctrl: airoha: fix setting of GPIO direction Zhengping Zhang
  2026-11-10  9:43 ` [PATCH 02/12] pinctrl: airoha: configure pin muxes on GPIO requests Zhengping Zhang
@ 2026-11-10  9:43 ` Zhengping Zhang
  2026-11-10  9:43 ` [PATCH 04/12] pinctrl: airoha: an7581: fix PHY LED GPIO group assignments Zhengping Zhang
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 17+ messages in thread
From: Zhengping Zhang @ 2026-11-10  9:43 UTC (permalink / raw)
  To: linusw, lorenzo
  Cc: robh, krzk+dt, conor+dt, brgl, mikhail.kshevetskiy, naseefkm,
	benjamin.larsson, linux-gpio, devicetree, linux-kernel,
	linux-mediatek, lei.dong, ansuelsmth, Zhengping Zhang

Expand the GPIO mux groups from GPIO47-49 to GPIO0-49 to describe
explicit GPIO mode selection across the controller's GPIO range.
Allow multiple GPIO groups in a single mux state.

Correct the PHY LED pin groups to match the EN7581 pad assignments:
LED0 uses GPIO43-46, while LED1 uses GPIO33-35 and GPIO42.

The corresponding driver support is added in subsequent patches.

Signed-off-by: Zhengping Zhang <zhengping.zhang@airoha.com>
---
 .../pinctrl/airoha,en7581-pinctrl.yaml        | 28 +++++++++++++------
 1 file changed, 19 insertions(+), 9 deletions(-)

diff --git a/Documentation/devicetree/bindings/pinctrl/airoha,en7581-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/airoha,en7581-pinctrl.yaml
index 0cf1826c691fc..fa7b3dc58a3ea 100644
--- a/Documentation/devicetree/bindings/pinctrl/airoha,en7581-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/airoha,en7581-pinctrl.yaml
@@ -194,7 +194,17 @@ patternProperties:
             then:
               properties:
                 groups:
-                  enum: [gpio47, gpio48, gpio49]
+                  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, gpio40, gpio41,
+                           gpio42, gpio43, gpio44, gpio45, gpio46, gpio47, gpio48,
+                           gpio49]
+                  minItems: 1
+                  maxItems: 50
           - if:
               properties:
                 function:
@@ -225,7 +235,7 @@ patternProperties:
             then:
               properties:
                 groups:
-                  enum: [gpio33, gpio34, gpio35, gpio42]
+                  enum: [gpio43, gpio44, gpio45, gpio46]
           - if:
               properties:
                 function:
@@ -233,7 +243,7 @@ patternProperties:
             then:
               properties:
                 groups:
-                  enum: [gpio33, gpio34, gpio35, gpio42]
+                  enum: [gpio43, gpio44, gpio45, gpio46]
           - if:
               properties:
                 function:
@@ -241,7 +251,7 @@ patternProperties:
             then:
               properties:
                 groups:
-                  enum: [gpio33, gpio34, gpio35, gpio42]
+                  enum: [gpio43, gpio44, gpio45, gpio46]
           - if:
               properties:
                 function:
@@ -249,7 +259,7 @@ patternProperties:
             then:
               properties:
                 groups:
-                  enum: [gpio33, gpio34, gpio35, gpio42]
+                  enum: [gpio43, gpio44, gpio45, gpio46]
           - if:
               properties:
                 function:
@@ -257,7 +267,7 @@ patternProperties:
             then:
               properties:
                 groups:
-                  enum: [gpio43, gpio44, gpio45, gpio46]
+                  enum: [gpio33, gpio34, gpio35, gpio42]
           - if:
               properties:
                 function:
@@ -265,7 +275,7 @@ patternProperties:
             then:
               properties:
                 groups:
-                  enum: [gpio43, gpio44, gpio45, gpio46]
+                  enum: [gpio33, gpio34, gpio35, gpio42]
           - if:
               properties:
                 function:
@@ -273,7 +283,7 @@ patternProperties:
             then:
               properties:
                 groups:
-                  enum: [gpio43, gpio44, gpio45, gpio46]
+                  enum: [gpio33, gpio34, gpio35, gpio42]
           - if:
               properties:
                 function:
@@ -281,7 +291,7 @@ patternProperties:
             then:
               properties:
                 groups:
-                  enum: [gpio43, gpio44, gpio45, gpio46]
+                  enum: [gpio33, gpio34, gpio35, gpio42]
 
         additionalProperties: false
 
-- 
2.43.0


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

* [PATCH 04/12] pinctrl: airoha: an7581: fix PHY LED GPIO group assignments
  2026-11-10  9:43 [PATCH 00/12] pinctrl: airoha: configure GPIO muxes explicitly and fix pad mappings Zhengping Zhang
                   ` (2 preceding siblings ...)
  2026-11-10  9:43 ` [PATCH 03/12] dt-bindings: pinctrl: airoha: describe all EN7581 GPIO mux groups Zhengping Zhang
@ 2026-11-10  9:43 ` Zhengping Zhang
  2026-11-10  9:43 ` [PATCH 05/12] pinctrl: airoha: an7581: select force GPIO mode on GPIO requests Zhengping Zhang
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 17+ messages in thread
From: Zhengping Zhang @ 2026-11-10  9:43 UTC (permalink / raw)
  To: linusw, lorenzo
  Cc: robh, krzk+dt, conor+dt, brgl, mikhail.kshevetskiy, naseefkm,
	benjamin.larsson, linux-gpio, devicetree, linux-kernel,
	linux-mediatek, lei.dong, ansuelsmth, Zhengping Zhang

The PHY LED function tables associate LED0 mux bits with the GPIO pads
used by LED1, and vice versa. Selecting an LED function therefore
programs the mux bit for a different pad from the requested group.

The LED mux bits in SCU register 0x214 correspond to these GPIO pads:

                  LAN0    LAN1    LAN2    LAN3
  LED0 mux bit       3       5       7       9
  LED0 GPIO         43      44      45      46
  LED1 mux bit       4       6       8      10
  LED1 GPIO         33      34      35      42

Correct both the advertised groups and the function-group entries to
match these assignments. This ensures that the pin claimed by pinctrl
matches the pad controlled by the selected LED mux bit.

Keep the existing mux masks and PHY source selections in the LED0/1
mapping registers unchanged.

Signed-off-by: Zhengping Zhang <zhengping.zhang@airoha.com>
---
 drivers/pinctrl/airoha/pinctrl-an7581.c | 80 ++++++++++++-------------
 1 file changed, 40 insertions(+), 40 deletions(-)

diff --git a/drivers/pinctrl/airoha/pinctrl-an7581.c b/drivers/pinctrl/airoha/pinctrl-an7581.c
index bfb777594811b..3cbdfc31e97e5 100644
--- a/drivers/pinctrl/airoha/pinctrl-an7581.c
+++ b/drivers/pinctrl/airoha/pinctrl-an7581.c
@@ -594,28 +594,28 @@ static const char *const pwm_groups[] = {
 	"gpio46", "gpio47", "gpio48", "gpio49"
 };
 static const char *const phy1_led0_groups[] = {
-	"gpio33", "gpio34", "gpio35", "gpio42"
+	"gpio43", "gpio44", "gpio45", "gpio46"
 };
 static const char *const phy2_led0_groups[] = {
-	"gpio33", "gpio34", "gpio35", "gpio42"
+	"gpio43", "gpio44", "gpio45", "gpio46"
 };
 static const char *const phy3_led0_groups[] = {
-	"gpio33", "gpio34", "gpio35", "gpio42"
+	"gpio43", "gpio44", "gpio45", "gpio46"
 };
 static const char *const phy4_led0_groups[] = {
-	"gpio33", "gpio34", "gpio35", "gpio42"
+	"gpio43", "gpio44", "gpio45", "gpio46"
 };
 static const char *const phy1_led1_groups[] = {
-	"gpio43", "gpio44", "gpio45", "gpio46"
+	"gpio33", "gpio34", "gpio35", "gpio42"
 };
 static const char *const phy2_led1_groups[] = {
-	"gpio43", "gpio44", "gpio45", "gpio46"
+	"gpio33", "gpio34", "gpio35", "gpio42"
 };
 static const char *const phy3_led1_groups[] = {
-	"gpio43", "gpio44", "gpio45", "gpio46"
+	"gpio33", "gpio34", "gpio35", "gpio42"
 };
 static const char *const phy4_led1_groups[] = {
-	"gpio43", "gpio44", "gpio45", "gpio46"
+	"gpio33", "gpio34", "gpio35", "gpio42"
 };
 
 static const struct airoha_pinctrl_func_group pon_func_group[] = {
@@ -1067,90 +1067,90 @@ static const struct airoha_pinctrl_func_group pwm_func_group[] = {
 };
 
 static const struct airoha_pinctrl_func_group phy1_led0_func_group[] = {
-	AIROHA_PINCTRL_PHY_LED0("gpio33", GPIO_LAN0_LED0_MODE_MASK,
+	AIROHA_PINCTRL_PHY_LED0("gpio43", GPIO_LAN0_LED0_MODE_MASK,
 				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(0)),
-	AIROHA_PINCTRL_PHY_LED0("gpio34", GPIO_LAN1_LED0_MODE_MASK,
+	AIROHA_PINCTRL_PHY_LED0("gpio44", GPIO_LAN1_LED0_MODE_MASK,
 				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(0)),
-	AIROHA_PINCTRL_PHY_LED0("gpio35", GPIO_LAN2_LED0_MODE_MASK,
+	AIROHA_PINCTRL_PHY_LED0("gpio45", GPIO_LAN2_LED0_MODE_MASK,
 				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(0)),
-	AIROHA_PINCTRL_PHY_LED0("gpio42", GPIO_LAN3_LED0_MODE_MASK,
+	AIROHA_PINCTRL_PHY_LED0("gpio46", GPIO_LAN3_LED0_MODE_MASK,
 				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(0)),
 };
 
 static const struct airoha_pinctrl_func_group phy2_led0_func_group[] = {
-	AIROHA_PINCTRL_PHY_LED0("gpio33", GPIO_LAN0_LED0_MODE_MASK,
+	AIROHA_PINCTRL_PHY_LED0("gpio43", GPIO_LAN0_LED0_MODE_MASK,
 				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(1)),
-	AIROHA_PINCTRL_PHY_LED0("gpio34", GPIO_LAN1_LED0_MODE_MASK,
+	AIROHA_PINCTRL_PHY_LED0("gpio44", GPIO_LAN1_LED0_MODE_MASK,
 				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(1)),
-	AIROHA_PINCTRL_PHY_LED0("gpio35", GPIO_LAN2_LED0_MODE_MASK,
+	AIROHA_PINCTRL_PHY_LED0("gpio45", GPIO_LAN2_LED0_MODE_MASK,
 				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(1)),
-	AIROHA_PINCTRL_PHY_LED0("gpio42", GPIO_LAN3_LED0_MODE_MASK,
+	AIROHA_PINCTRL_PHY_LED0("gpio46", GPIO_LAN3_LED0_MODE_MASK,
 				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(1)),
 };
 
 static const struct airoha_pinctrl_func_group phy3_led0_func_group[] = {
-	AIROHA_PINCTRL_PHY_LED0("gpio33", GPIO_LAN0_LED0_MODE_MASK,
+	AIROHA_PINCTRL_PHY_LED0("gpio43", GPIO_LAN0_LED0_MODE_MASK,
 				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(2)),
-	AIROHA_PINCTRL_PHY_LED0("gpio34", GPIO_LAN1_LED0_MODE_MASK,
+	AIROHA_PINCTRL_PHY_LED0("gpio44", GPIO_LAN1_LED0_MODE_MASK,
 				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(2)),
-	AIROHA_PINCTRL_PHY_LED0("gpio35", GPIO_LAN2_LED0_MODE_MASK,
+	AIROHA_PINCTRL_PHY_LED0("gpio45", GPIO_LAN2_LED0_MODE_MASK,
 				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(2)),
-	AIROHA_PINCTRL_PHY_LED0("gpio42", GPIO_LAN3_LED0_MODE_MASK,
+	AIROHA_PINCTRL_PHY_LED0("gpio46", GPIO_LAN3_LED0_MODE_MASK,
 				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(2)),
 };
 
 static const struct airoha_pinctrl_func_group phy4_led0_func_group[] = {
-	AIROHA_PINCTRL_PHY_LED0("gpio33", GPIO_LAN0_LED0_MODE_MASK,
+	AIROHA_PINCTRL_PHY_LED0("gpio43", GPIO_LAN0_LED0_MODE_MASK,
 				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(3)),
-	AIROHA_PINCTRL_PHY_LED0("gpio34", GPIO_LAN1_LED0_MODE_MASK,
+	AIROHA_PINCTRL_PHY_LED0("gpio44", GPIO_LAN1_LED0_MODE_MASK,
 				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(3)),
-	AIROHA_PINCTRL_PHY_LED0("gpio35", GPIO_LAN2_LED0_MODE_MASK,
+	AIROHA_PINCTRL_PHY_LED0("gpio45", GPIO_LAN2_LED0_MODE_MASK,
 				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(3)),
-	AIROHA_PINCTRL_PHY_LED0("gpio42", GPIO_LAN3_LED0_MODE_MASK,
+	AIROHA_PINCTRL_PHY_LED0("gpio46", GPIO_LAN3_LED0_MODE_MASK,
 				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(3)),
 };
 
 static const struct airoha_pinctrl_func_group phy1_led1_func_group[] = {
-	AIROHA_PINCTRL_PHY_LED1("gpio43", GPIO_LAN0_LED1_MODE_MASK,
+	AIROHA_PINCTRL_PHY_LED1("gpio33", GPIO_LAN0_LED1_MODE_MASK,
 				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(0)),
-	AIROHA_PINCTRL_PHY_LED1("gpio44", GPIO_LAN1_LED1_MODE_MASK,
+	AIROHA_PINCTRL_PHY_LED1("gpio34", GPIO_LAN1_LED1_MODE_MASK,
 				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(0)),
-	AIROHA_PINCTRL_PHY_LED1("gpio45", GPIO_LAN2_LED1_MODE_MASK,
+	AIROHA_PINCTRL_PHY_LED1("gpio35", GPIO_LAN2_LED1_MODE_MASK,
 				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(0)),
-	AIROHA_PINCTRL_PHY_LED1("gpio46", GPIO_LAN3_LED1_MODE_MASK,
+	AIROHA_PINCTRL_PHY_LED1("gpio42", GPIO_LAN3_LED1_MODE_MASK,
 				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(0)),
 };
 
 static const struct airoha_pinctrl_func_group phy2_led1_func_group[] = {
-	AIROHA_PINCTRL_PHY_LED1("gpio43", GPIO_LAN0_LED1_MODE_MASK,
+	AIROHA_PINCTRL_PHY_LED1("gpio33", GPIO_LAN0_LED1_MODE_MASK,
 				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(1)),
-	AIROHA_PINCTRL_PHY_LED1("gpio44", GPIO_LAN1_LED1_MODE_MASK,
+	AIROHA_PINCTRL_PHY_LED1("gpio34", GPIO_LAN1_LED1_MODE_MASK,
 				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(1)),
-	AIROHA_PINCTRL_PHY_LED1("gpio45", GPIO_LAN2_LED1_MODE_MASK,
+	AIROHA_PINCTRL_PHY_LED1("gpio35", GPIO_LAN2_LED1_MODE_MASK,
 				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(1)),
-	AIROHA_PINCTRL_PHY_LED1("gpio46", GPIO_LAN3_LED1_MODE_MASK,
+	AIROHA_PINCTRL_PHY_LED1("gpio42", GPIO_LAN3_LED1_MODE_MASK,
 				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(1)),
 };
 
 static const struct airoha_pinctrl_func_group phy3_led1_func_group[] = {
-	AIROHA_PINCTRL_PHY_LED1("gpio43", GPIO_LAN0_LED1_MODE_MASK,
+	AIROHA_PINCTRL_PHY_LED1("gpio33", GPIO_LAN0_LED1_MODE_MASK,
 				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(2)),
-	AIROHA_PINCTRL_PHY_LED1("gpio44", GPIO_LAN1_LED1_MODE_MASK,
+	AIROHA_PINCTRL_PHY_LED1("gpio34", GPIO_LAN1_LED1_MODE_MASK,
 				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(2)),
-	AIROHA_PINCTRL_PHY_LED1("gpio45", GPIO_LAN2_LED1_MODE_MASK,
+	AIROHA_PINCTRL_PHY_LED1("gpio35", GPIO_LAN2_LED1_MODE_MASK,
 				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(2)),
-	AIROHA_PINCTRL_PHY_LED1("gpio46", GPIO_LAN3_LED1_MODE_MASK,
+	AIROHA_PINCTRL_PHY_LED1("gpio42", GPIO_LAN3_LED1_MODE_MASK,
 				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(2)),
 };
 
 static const struct airoha_pinctrl_func_group phy4_led1_func_group[] = {
-	AIROHA_PINCTRL_PHY_LED1("gpio43", GPIO_LAN0_LED1_MODE_MASK,
+	AIROHA_PINCTRL_PHY_LED1("gpio33", GPIO_LAN0_LED1_MODE_MASK,
 				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(3)),
-	AIROHA_PINCTRL_PHY_LED1("gpio44", GPIO_LAN1_LED1_MODE_MASK,
+	AIROHA_PINCTRL_PHY_LED1("gpio34", GPIO_LAN1_LED1_MODE_MASK,
 				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(3)),
-	AIROHA_PINCTRL_PHY_LED1("gpio45", GPIO_LAN2_LED1_MODE_MASK,
+	AIROHA_PINCTRL_PHY_LED1("gpio35", GPIO_LAN2_LED1_MODE_MASK,
 				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(3)),
-	AIROHA_PINCTRL_PHY_LED1("gpio46", GPIO_LAN3_LED1_MODE_MASK,
+	AIROHA_PINCTRL_PHY_LED1("gpio42", GPIO_LAN3_LED1_MODE_MASK,
 				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(3)),
 };
 
-- 
2.43.0


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

* [PATCH 05/12] pinctrl: airoha: an7581: select force GPIO mode on GPIO requests
  2026-11-10  9:43 [PATCH 00/12] pinctrl: airoha: configure GPIO muxes explicitly and fix pad mappings Zhengping Zhang
                   ` (3 preceding siblings ...)
  2026-11-10  9:43 ` [PATCH 04/12] pinctrl: airoha: an7581: fix PHY LED GPIO group assignments Zhengping Zhang
@ 2026-11-10  9:43 ` Zhengping Zhang
  2026-11-10 10:00   ` sashiko-bot
  2026-11-10  9:43 ` [PATCH 06/12] dt-bindings: pinctrl: airoha: describe all AN7583 GPIO mux groups Zhengping Zhang
                   ` (6 subsequent siblings)
  11 siblings, 1 reply; 17+ messages in thread
From: Zhengping Zhang @ 2026-11-10  9:43 UTC (permalink / raw)
  To: linusw, lorenzo
  Cc: robh, krzk+dt, conor+dt, brgl, mikhail.kshevetskiy, naseefkm,
	benjamin.larsson, linux-gpio, devicetree, linux-kernel,
	linux-mediatek, lei.dong, ansuelsmth, Zhengping Zhang

Configuring GPIO direction and output data does not select the GPIO
function at the pad. If the bootloader leaves a shared pad configured
for an alternate function, a GPIO request can succeed while the pad
remains controlled by that function. GPIO outputs may then fail to
drive the pin, and input readings may not reflect the external signal,
making GPIO behavior depend on the bootloader configuration.

The AN7581 driver currently exposes explicit GPIO mux groups only for
GPIO47-49 and does not enable the shared GPIO request handling. Extend
the GPIO groups to GPIO0-49, mark the function as a GPIO-category
function and enable GPIO request handling and shared mux conflict
checks through the SoC match data. GPIO consumers can then select the
pad function without requiring an explicit GPIO pinctrl state in DTS.
Explicit GPIO states use the same configuration tables.

Use the per-pad force GPIO overrides instead of disabling shared
alternate-function modes globally. This allows a GPIO request to
override its own pad without changing the mux settings of other pads
controlled by the same peripheral mode bits. Select GPIO mode using
the following SCU register bits, where n is the GPIO number:

  - GPIO1-31: set bit n in register 0x228
    (GPIO1 -> bit 1, ..., GPIO31 -> bit 31).
  - GPIO32-46: set bit (n - 32) in register 0x22c
    (GPIO32 -> bit 0, ..., GPIO46 -> bit 14).
  - GPIO47-49: set the PCIe reset GPIO selector bits in register
    0x21c (GPIO47 -> bit 9, GPIO48 -> bit 10, GPIO49 -> bit 12).
  - GPIO0: clear its PWM selection only; no usable force GPIO bit
    is documented.

Clear the requested pad's PWM selection when selecting GPIO. For
GPIO1/2, also disable the I2C and MDIO routing. The existing MDIO
configuration sets force GPIO bits 1/2 as part of its routing sequence,
so setting these bits alone is insufficient to switch the pads from
MDIO to GPIO.

When selecting a peripheral function, clear the force GPIO overrides
for the pads in its group while retaining the existing mux and LED
mapping writes. Otherwise, a force bit left by the bootloader or an
earlier GPIO configuration could keep the pad in GPIO mode even after
the peripheral mux has been configured. Keep the existing register
configuration for selecting MDIO and PWM functions unchanged.

Enable the shared conflict checks to reject configurations requiring
incompatible values for shared mux bits rather than silently changing
the configuration of an owned group.

Signed-off-by: Zhengping Zhang <zhengping.zhang@airoha.com>
---
 drivers/pinctrl/airoha/pinctrl-an7581.c | 549 ++++++++++++++++++++----
 1 file changed, 476 insertions(+), 73 deletions(-)

diff --git a/drivers/pinctrl/airoha/pinctrl-an7581.c b/drivers/pinctrl/airoha/pinctrl-an7581.c
index 3cbdfc31e97e5..b266cc8bc65f4 100644
--- a/drivers/pinctrl/airoha/pinctrl-an7581.c
+++ b/drivers/pinctrl/airoha/pinctrl-an7581.c
@@ -64,6 +64,7 @@
 #define JTAG_DFD_EN_MASK			BIT(3)
 
 #define REG_FORCE_GPIO_EN			0x0228
+#define REG_FORCE_GPIO32_EN			0x022c
 #define FORCE_GPIO_EN(n)			BIT(n)
 
 /* LED MAP */
@@ -280,7 +281,7 @@
 		.regmap_size = 2,				\
 	}
 
-#define AIROHA_PINCTRL_PHY_LED0(gpio, mux_val, map_mask, map_val)	\
+#define AIROHA_PINCTRL_PHY_LED0(gpio, mux_val, map_mask, map_val, force_reg, force_mask) \
 	{								\
 		.name = (gpio),						\
 		.regmap[0] = {						\
@@ -295,10 +296,14 @@
 			(map_mask),					\
 			(map_val),					\
 		},							\
-		.regmap_size = 2,					\
+		.regmap[2] = {						\
+			AIROHA_FUNC_MUX, (force_reg),			\
+			(force_mask), 0					\
+		},							\
+		.regmap_size = 3,					\
 	}
 
-#define AIROHA_PINCTRL_PHY_LED1(gpio, mux_val, map_mask, map_val)	\
+#define AIROHA_PINCTRL_PHY_LED1(gpio, mux_val, map_mask, map_val, force_reg, force_mask) \
 	{								\
 		.name = (gpio),						\
 		.regmap[0] = {						\
@@ -313,7 +318,11 @@
 			(map_mask),					\
 			(map_val),					\
 		},							\
-		.regmap_size = 2,					\
+		.regmap[2] = {						\
+			AIROHA_FUNC_MUX, (force_reg),			\
+			(force_mask), 0					\
+		},							\
+		.regmap_size = 3,					\
 	}
 
 static struct pinctrl_pin_desc pinctrl_pins[] = {
@@ -579,7 +588,17 @@ static const char *const pcm_spi_groups[] = {
 static const char *const i2s_groups[] = { "i2s" };
 static const char *const emmc_groups[] = { "emmc" };
 static const char *const pnand_groups[] = { "pnand" };
-static const char *const gpio_groups[] = { "gpio47", "gpio48", "gpio49" };
+static const char *const gpio_groups[] = {
+	"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",
+	"gpio42", "gpio43", "gpio44", "gpio45", "gpio46", "gpio47",
+	"gpio48", "gpio49",
+};
 static const char *const pcie_reset_groups[] = {
 	"pcie_reset0", "pcie_reset1", "pcie_reset2"
 };
@@ -627,7 +646,18 @@ static const struct airoha_pinctrl_func_group pon_func_group[] = {
 			GPIO_PON_MODE_MASK,
 			GPIO_PON_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO32_EN,
+			BIT(4) |
+			BIT(5) |
+			BIT(6) |
+			BIT(7) |
+			BIT(8) |
+			BIT(9),
+			0
+		},
+		.regmap_size = 2,
 	},
 };
 
@@ -640,7 +670,13 @@ static const struct airoha_pinctrl_func_group tod_1pps_func_group[] = {
 			PON_TOD_1PPS_MODE_MASK,
 			PON_TOD_1PPS_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO32_EN,
+			BIT(1),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "gsw_tod_1pps",
 		.regmap[0] = {
@@ -649,7 +685,13 @@ static const struct airoha_pinctrl_func_group tod_1pps_func_group[] = {
 			GSW_TOD_1PPS_MODE_MASK,
 			GSW_TOD_1PPS_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO32_EN,
+			BIT(1),
+			0
+		},
+		.regmap_size = 2,
 	},
 };
 
@@ -662,7 +704,14 @@ static const struct airoha_pinctrl_func_group sipo_func_group[] = {
 			GPIO_SIPO_MODE_MASK | SIPO_RCLK_MODE_MASK,
 			GPIO_SIPO_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(3) |
+			BIT(4),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "sipo_rclk",
 		.regmap[0] = {
@@ -671,7 +720,15 @@ static const struct airoha_pinctrl_func_group sipo_func_group[] = {
 			GPIO_SIPO_MODE_MASK | SIPO_RCLK_MODE_MASK,
 			GPIO_SIPO_MODE_MASK | SIPO_RCLK_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(3) |
+			BIT(4) |
+			BIT(30),
+			0
+		},
+		.regmap_size = 2,
 	},
 };
 
@@ -703,7 +760,14 @@ static const struct airoha_pinctrl_func_group uart_func_group[] = {
 			GPIO_UART2_MODE_MASK,
 			GPIO_UART2_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO32_EN,
+			BIT(3) |
+			BIT(10),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "uart2_cts_rts",
 		.regmap[0] = {
@@ -712,7 +776,14 @@ static const struct airoha_pinctrl_func_group uart_func_group[] = {
 			GPIO_UART2_MODE_MASK | GPIO_UART2_CTS_RTS_MODE_MASK,
 			GPIO_UART2_MODE_MASK | GPIO_UART2_CTS_RTS_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO32_EN,
+			BIT(1) |
+			BIT(2),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "hsuart",
 		.regmap[0] = {
@@ -721,7 +792,14 @@ static const struct airoha_pinctrl_func_group uart_func_group[] = {
 			GPIO_HSUART_MODE_MASK | GPIO_HSUART_CTS_RTS_MODE_MASK,
 			GPIO_HSUART_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(15) |
+			BIT(16),
+			0
+		},
+		.regmap_size = 2,
 	},
 	{
 		.name = "hsuart_cts_rts",
@@ -731,7 +809,14 @@ static const struct airoha_pinctrl_func_group uart_func_group[] = {
 			GPIO_HSUART_MODE_MASK | GPIO_HSUART_CTS_RTS_MODE_MASK,
 			GPIO_HSUART_MODE_MASK | GPIO_HSUART_CTS_RTS_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(13) |
+			BIT(14),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "uart4",
 		.regmap[0] = {
@@ -740,7 +825,14 @@ static const struct airoha_pinctrl_func_group uart_func_group[] = {
 			GPIO_UART4_MODE_MASK,
 			GPIO_UART4_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(25) |
+			BIT(26),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "uart5",
 		.regmap[0] = {
@@ -749,7 +841,14 @@ static const struct airoha_pinctrl_func_group uart_func_group[] = {
 			GPIO_UART5_MODE_MASK,
 			GPIO_UART5_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(5) |
+			BIT(6),
+			0
+		},
+		.regmap_size = 2,
 	},
 };
 
@@ -762,7 +861,14 @@ static const struct airoha_pinctrl_func_group i2c_func_group[] = {
 			GPIO_2ND_I2C_MODE_MASK | GPIO_I2C_MASTER_MODE_MODE,
 			GPIO_2ND_I2C_MODE_MASK | GPIO_I2C_MASTER_MODE_MODE
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(1) |
+			BIT(2),
+			0
+		},
+		.regmap_size = 2,
 	},
 };
 
@@ -775,7 +881,17 @@ static const struct airoha_pinctrl_func_group jtag_func_group[] = {
 			JTAG_UDI_EN_MASK,
 			JTAG_UDI_EN_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(3) |
+			BIT(4) |
+			BIT(5) |
+			BIT(6) |
+			BIT(7),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "jtag_dfd",
 		.regmap[0] = {
@@ -784,7 +900,17 @@ static const struct airoha_pinctrl_func_group jtag_func_group[] = {
 			JTAG_DFD_EN_MASK,
 			JTAG_DFD_EN_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(3) |
+			BIT(4) |
+			BIT(5) |
+			BIT(6) |
+			BIT(7),
+			0
+		},
+		.regmap_size = 2,
 	},
 };
 
@@ -797,7 +923,16 @@ static const struct airoha_pinctrl_func_group pcm_func_group[] = {
 			GPIO_PCM1_MODE_MASK,
 			GPIO_PCM1_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(9) |
+			BIT(10) |
+			BIT(11) |
+			BIT(12),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "pcm2",
 		.regmap[0] = {
@@ -806,7 +941,16 @@ static const struct airoha_pinctrl_func_group pcm_func_group[] = {
 			GPIO_PCM2_MODE_MASK,
 			GPIO_PCM2_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(5) |
+			BIT(6) |
+			BIT(7) |
+			BIT(8),
+			0
+		},
+		.regmap_size = 2,
 	},
 };
 
@@ -819,7 +963,14 @@ static const struct airoha_pinctrl_func_group spi_func_group[] = {
 			GPIO_SPI_QUAD_MODE_MASK,
 			GPIO_SPI_QUAD_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(19) |
+			BIT(20),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "spi_cs1",
 		.regmap[0] = {
@@ -828,7 +979,13 @@ static const struct airoha_pinctrl_func_group spi_func_group[] = {
 			GPIO_SPI_CS1_MODE_MASK,
 			GPIO_SPI_CS1_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(21),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "spi_cs2",
 		.regmap[0] = {
@@ -868,7 +1025,20 @@ static const struct airoha_pinctrl_func_group pcm_spi_func_group[] = {
 			GPIO_PCM_SPI_MODE_MASK,
 			GPIO_PCM_SPI_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(5) |
+			BIT(6) |
+			BIT(7) |
+			BIT(8) |
+			BIT(9) |
+			BIT(10) |
+			BIT(11) |
+			BIT(12),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "pcm_spi_int",
 		.regmap[0] = {
@@ -877,7 +1047,13 @@ static const struct airoha_pinctrl_func_group pcm_spi_func_group[] = {
 			GPIO_PCM_INT_MODE_MASK,
 			GPIO_PCM_INT_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(1),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "pcm_spi_rst",
 		.regmap[0] = {
@@ -886,7 +1062,13 @@ static const struct airoha_pinctrl_func_group pcm_spi_func_group[] = {
 			GPIO_PCM_RESET_MODE_MASK,
 			GPIO_PCM_RESET_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(2),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "pcm_spi_cs1",
 		.regmap[0] = {
@@ -895,7 +1077,13 @@ static const struct airoha_pinctrl_func_group pcm_spi_func_group[] = {
 			GPIO_PCM_SPI_CS1_MODE_MASK,
 			GPIO_PCM_SPI_CS1_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(30),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "pcm_spi_cs2_p128",
 		.regmap[0] = {
@@ -904,7 +1092,13 @@ static const struct airoha_pinctrl_func_group pcm_spi_func_group[] = {
 			GPIO_PCM_SPI_CS2_MODE_P128_MASK,
 			GPIO_PCM_SPI_CS2_MODE_P128_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(27),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "pcm_spi_cs2_p156",
 		.regmap[0] = {
@@ -913,7 +1107,13 @@ static const struct airoha_pinctrl_func_group pcm_spi_func_group[] = {
 			GPIO_PCM_SPI_CS2_MODE_P156_MASK,
 			GPIO_PCM_SPI_CS2_MODE_P156_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(27),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "pcm_spi_cs3",
 		.regmap[0] = {
@@ -922,7 +1122,13 @@ static const struct airoha_pinctrl_func_group pcm_spi_func_group[] = {
 			GPIO_PCM_SPI_CS3_MODE_MASK,
 			GPIO_PCM_SPI_CS3_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(28),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "pcm_spi_cs4",
 		.regmap[0] = {
@@ -931,7 +1137,13 @@ static const struct airoha_pinctrl_func_group pcm_spi_func_group[] = {
 			GPIO_PCM_SPI_CS4_MODE_MASK,
 			GPIO_PCM_SPI_CS4_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(29),
+			0
+		},
+		.regmap_size = 2,
 	},
 };
 
@@ -944,7 +1156,16 @@ static const struct airoha_pinctrl_func_group i2s_func_group[] = {
 			GPIO_I2S_MODE_MASK,
 			GPIO_I2S_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(13) |
+			BIT(14) |
+			BIT(15) |
+			BIT(16),
+			0
+		},
+		.regmap_size = 2,
 	},
 };
 
@@ -957,7 +1178,20 @@ static const struct airoha_pinctrl_func_group emmc_func_group[] = {
 			GPIO_EMMC_MODE_MASK,
 			GPIO_EMMC_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(17) |
+			BIT(18) |
+			BIT(19) |
+			BIT(20) |
+			BIT(21) |
+			BIT(22) |
+			BIT(23) |
+			BIT(24),
+			0
+		},
+		.regmap_size = 2,
 	},
 };
 
@@ -970,17 +1204,153 @@ static const struct airoha_pinctrl_func_group pnand_func_group[] = {
 			GPIO_PARALLEL_NAND_MODE_MASK,
 			GPIO_PARALLEL_NAND_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(17) |
+			BIT(18) |
+			BIT(19) |
+			BIT(20) |
+			BIT(21) |
+			BIT(22) |
+			BIT(23) |
+			BIT(24) |
+			BIT(25) |
+			BIT(26) |
+			BIT(27) |
+			BIT(28) |
+			BIT(29),
+			0
+		},
+		.regmap_size = 2,
 	},
 };
 
+/* GPIO0 has no force bit. GPIO47-49 retain their native PCIe selectors. */
+#define AN7581_GPIO_GROUP(n, pwm_mask, force_reg, force_mask)	\
+	{	\
+		.name = "gpio" #n,	\
+		.regmap[0] = {	\
+			AIROHA_FUNC_PWM_MUX,	\
+			(n) < 16 ? REG_GPIO_FLASH_MODE_CFG :	\
+			REG_GPIO_FLASH_MODE_CFG_EXT,	\
+			(pwm_mask), 0	\
+		},	\
+		.regmap[1] = {	\
+			AIROHA_FUNC_MUX, REG_GPIO_2ND_I2C_MODE,	\
+			(n) == 1 || (n) == 2 ?	\
+			GPIO_2ND_I2C_MODE_MASK |	\
+			GPIO_I2C_MASTER_MODE_MODE |	\
+			GPIO_MDC_IO_MASTER_MODE_MASK : 0, 0	\
+		},	\
+		.regmap[2] = {	\
+			AIROHA_FUNC_MUX, (force_reg),	\
+			(force_mask), (force_mask)	\
+		},	\
+		.regmap_size = 3,	\
+	}
+
 static const struct airoha_pinctrl_func_group gpio_func_group[] = {
-	AIROHA_PINCTRL_GPIO_EXT("gpio47", GPIO47_FLASH_MODE_CFG,
-				GPIO_PCIE_RESET0_MASK),
-	AIROHA_PINCTRL_GPIO_EXT("gpio48", GPIO48_FLASH_MODE_CFG,
-				GPIO_PCIE_RESET1_MASK),
-	AIROHA_PINCTRL_GPIO_EXT("gpio49", GPIO49_FLASH_MODE_CFG,
-				GPIO_PCIE_RESET2_MASK),
+	AN7581_GPIO_GROUP(0, GPIO0_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, 0),
+	AN7581_GPIO_GROUP(1, GPIO1_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(1)),
+	AN7581_GPIO_GROUP(2, GPIO2_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(2)),
+	AN7581_GPIO_GROUP(3, GPIO3_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(3)),
+	AN7581_GPIO_GROUP(4, GPIO4_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(4)),
+	AN7581_GPIO_GROUP(5, GPIO5_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(5)),
+	AN7581_GPIO_GROUP(6, GPIO6_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(6)),
+	AN7581_GPIO_GROUP(7, GPIO7_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(7)),
+	AN7581_GPIO_GROUP(8, GPIO8_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(8)),
+	AN7581_GPIO_GROUP(9, GPIO9_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(9)),
+	AN7581_GPIO_GROUP(10, GPIO10_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(10)),
+	AN7581_GPIO_GROUP(11, GPIO11_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(11)),
+	AN7581_GPIO_GROUP(12, GPIO12_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(12)),
+	AN7581_GPIO_GROUP(13, GPIO13_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(13)),
+	AN7581_GPIO_GROUP(14, GPIO14_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(14)),
+	AN7581_GPIO_GROUP(15, GPIO15_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(15)),
+	AN7581_GPIO_GROUP(16, GPIO16_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(16)),
+	AN7581_GPIO_GROUP(17, GPIO17_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(17)),
+	AN7581_GPIO_GROUP(18, GPIO18_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(18)),
+	AN7581_GPIO_GROUP(19, GPIO19_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(19)),
+	AN7581_GPIO_GROUP(20, GPIO20_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(20)),
+	AN7581_GPIO_GROUP(21, GPIO21_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(21)),
+	AN7581_GPIO_GROUP(22, GPIO22_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(22)),
+	AN7581_GPIO_GROUP(23, GPIO23_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(23)),
+	AN7581_GPIO_GROUP(24, GPIO24_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(24)),
+	AN7581_GPIO_GROUP(25, GPIO25_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(25)),
+	AN7581_GPIO_GROUP(26, GPIO26_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(26)),
+	AN7581_GPIO_GROUP(27, GPIO27_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(27)),
+	AN7581_GPIO_GROUP(28, GPIO28_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(28)),
+	AN7581_GPIO_GROUP(29, GPIO29_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(29)),
+	AN7581_GPIO_GROUP(30, GPIO30_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(30)),
+	AN7581_GPIO_GROUP(31, GPIO31_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(31)),
+	AN7581_GPIO_GROUP(32, 0,
+			    REG_FORCE_GPIO32_EN, BIT(0)),
+	AN7581_GPIO_GROUP(33, 0,
+			    REG_FORCE_GPIO32_EN, BIT(1)),
+	AN7581_GPIO_GROUP(34, 0,
+			    REG_FORCE_GPIO32_EN, BIT(2)),
+	AN7581_GPIO_GROUP(35, 0,
+			    REG_FORCE_GPIO32_EN, BIT(3)),
+	AN7581_GPIO_GROUP(36, GPIO36_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO32_EN, BIT(4)),
+	AN7581_GPIO_GROUP(37, GPIO37_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO32_EN, BIT(5)),
+	AN7581_GPIO_GROUP(38, GPIO38_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO32_EN, BIT(6)),
+	AN7581_GPIO_GROUP(39, GPIO39_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO32_EN, BIT(7)),
+	AN7581_GPIO_GROUP(40, GPIO40_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO32_EN, BIT(8)),
+	AN7581_GPIO_GROUP(41, GPIO41_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO32_EN, BIT(9)),
+	AN7581_GPIO_GROUP(42, GPIO42_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO32_EN, BIT(10)),
+	AN7581_GPIO_GROUP(43, GPIO43_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO32_EN, BIT(11)),
+	AN7581_GPIO_GROUP(44, GPIO44_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO32_EN, BIT(12)),
+	AN7581_GPIO_GROUP(45, GPIO45_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO32_EN, BIT(13)),
+	AN7581_GPIO_GROUP(46, GPIO46_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO32_EN, BIT(14)),
+	AN7581_GPIO_GROUP(47, GPIO47_FLASH_MODE_CFG,
+			    REG_GPIO_PON_MODE, GPIO_PCIE_RESET0_MASK),
+	AN7581_GPIO_GROUP(48, GPIO48_FLASH_MODE_CFG,
+			    REG_GPIO_PON_MODE, GPIO_PCIE_RESET1_MASK),
+	AN7581_GPIO_GROUP(49, GPIO49_FLASH_MODE_CFG,
+			    REG_GPIO_PON_MODE, GPIO_PCIE_RESET2_MASK),
 };
 
 static const struct airoha_pinctrl_func_group pcie_reset_func_group[] = {
@@ -1068,90 +1438,122 @@ static const struct airoha_pinctrl_func_group pwm_func_group[] = {
 
 static const struct airoha_pinctrl_func_group phy1_led0_func_group[] = {
 	AIROHA_PINCTRL_PHY_LED0("gpio43", GPIO_LAN0_LED0_MODE_MASK,
-				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(0)),
+				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(0),
+				REG_FORCE_GPIO32_EN, BIT(11)),
 	AIROHA_PINCTRL_PHY_LED0("gpio44", GPIO_LAN1_LED0_MODE_MASK,
-				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(0)),
+				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(0),
+				REG_FORCE_GPIO32_EN, BIT(12)),
 	AIROHA_PINCTRL_PHY_LED0("gpio45", GPIO_LAN2_LED0_MODE_MASK,
-				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(0)),
+				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(0),
+				REG_FORCE_GPIO32_EN, BIT(13)),
 	AIROHA_PINCTRL_PHY_LED0("gpio46", GPIO_LAN3_LED0_MODE_MASK,
-				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(0)),
+				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(0),
+				REG_FORCE_GPIO32_EN, BIT(14)),
 };
 
 static const struct airoha_pinctrl_func_group phy2_led0_func_group[] = {
 	AIROHA_PINCTRL_PHY_LED0("gpio43", GPIO_LAN0_LED0_MODE_MASK,
-				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(1)),
+				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(1),
+				REG_FORCE_GPIO32_EN, BIT(11)),
 	AIROHA_PINCTRL_PHY_LED0("gpio44", GPIO_LAN1_LED0_MODE_MASK,
-				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(1)),
+				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(1),
+				REG_FORCE_GPIO32_EN, BIT(12)),
 	AIROHA_PINCTRL_PHY_LED0("gpio45", GPIO_LAN2_LED0_MODE_MASK,
-				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(1)),
+				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(1),
+				REG_FORCE_GPIO32_EN, BIT(13)),
 	AIROHA_PINCTRL_PHY_LED0("gpio46", GPIO_LAN3_LED0_MODE_MASK,
-				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(1)),
+				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(1),
+				REG_FORCE_GPIO32_EN, BIT(14)),
 };
 
 static const struct airoha_pinctrl_func_group phy3_led0_func_group[] = {
 	AIROHA_PINCTRL_PHY_LED0("gpio43", GPIO_LAN0_LED0_MODE_MASK,
-				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(2)),
+				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(2),
+				REG_FORCE_GPIO32_EN, BIT(11)),
 	AIROHA_PINCTRL_PHY_LED0("gpio44", GPIO_LAN1_LED0_MODE_MASK,
-				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(2)),
+				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(2),
+				REG_FORCE_GPIO32_EN, BIT(12)),
 	AIROHA_PINCTRL_PHY_LED0("gpio45", GPIO_LAN2_LED0_MODE_MASK,
-				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(2)),
+				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(2),
+				REG_FORCE_GPIO32_EN, BIT(13)),
 	AIROHA_PINCTRL_PHY_LED0("gpio46", GPIO_LAN3_LED0_MODE_MASK,
-				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(2)),
+				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(2),
+				REG_FORCE_GPIO32_EN, BIT(14)),
 };
 
 static const struct airoha_pinctrl_func_group phy4_led0_func_group[] = {
 	AIROHA_PINCTRL_PHY_LED0("gpio43", GPIO_LAN0_LED0_MODE_MASK,
-				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(3)),
+				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(3),
+				REG_FORCE_GPIO32_EN, BIT(11)),
 	AIROHA_PINCTRL_PHY_LED0("gpio44", GPIO_LAN1_LED0_MODE_MASK,
-				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(3)),
+				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(3),
+				REG_FORCE_GPIO32_EN, BIT(12)),
 	AIROHA_PINCTRL_PHY_LED0("gpio45", GPIO_LAN2_LED0_MODE_MASK,
-				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(3)),
+				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(3),
+				REG_FORCE_GPIO32_EN, BIT(13)),
 	AIROHA_PINCTRL_PHY_LED0("gpio46", GPIO_LAN3_LED0_MODE_MASK,
-				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(3)),
+				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(3),
+				REG_FORCE_GPIO32_EN, BIT(14)),
 };
 
 static const struct airoha_pinctrl_func_group phy1_led1_func_group[] = {
 	AIROHA_PINCTRL_PHY_LED1("gpio33", GPIO_LAN0_LED1_MODE_MASK,
-				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(0)),
+				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(0),
+				REG_FORCE_GPIO32_EN, BIT(1)),
 	AIROHA_PINCTRL_PHY_LED1("gpio34", GPIO_LAN1_LED1_MODE_MASK,
-				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(0)),
+				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(0),
+				REG_FORCE_GPIO32_EN, BIT(2)),
 	AIROHA_PINCTRL_PHY_LED1("gpio35", GPIO_LAN2_LED1_MODE_MASK,
-				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(0)),
+				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(0),
+				REG_FORCE_GPIO32_EN, BIT(3)),
 	AIROHA_PINCTRL_PHY_LED1("gpio42", GPIO_LAN3_LED1_MODE_MASK,
-				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(0)),
+				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(0),
+				REG_FORCE_GPIO32_EN, BIT(10)),
 };
 
 static const struct airoha_pinctrl_func_group phy2_led1_func_group[] = {
 	AIROHA_PINCTRL_PHY_LED1("gpio33", GPIO_LAN0_LED1_MODE_MASK,
-				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(1)),
+				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(1),
+				REG_FORCE_GPIO32_EN, BIT(1)),
 	AIROHA_PINCTRL_PHY_LED1("gpio34", GPIO_LAN1_LED1_MODE_MASK,
-				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(1)),
+				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(1),
+				REG_FORCE_GPIO32_EN, BIT(2)),
 	AIROHA_PINCTRL_PHY_LED1("gpio35", GPIO_LAN2_LED1_MODE_MASK,
-				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(1)),
+				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(1),
+				REG_FORCE_GPIO32_EN, BIT(3)),
 	AIROHA_PINCTRL_PHY_LED1("gpio42", GPIO_LAN3_LED1_MODE_MASK,
-				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(1)),
+				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(1),
+				REG_FORCE_GPIO32_EN, BIT(10)),
 };
 
 static const struct airoha_pinctrl_func_group phy3_led1_func_group[] = {
 	AIROHA_PINCTRL_PHY_LED1("gpio33", GPIO_LAN0_LED1_MODE_MASK,
-				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(2)),
+				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(2),
+				REG_FORCE_GPIO32_EN, BIT(1)),
 	AIROHA_PINCTRL_PHY_LED1("gpio34", GPIO_LAN1_LED1_MODE_MASK,
-				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(2)),
+				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(2),
+				REG_FORCE_GPIO32_EN, BIT(2)),
 	AIROHA_PINCTRL_PHY_LED1("gpio35", GPIO_LAN2_LED1_MODE_MASK,
-				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(2)),
+				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(2),
+				REG_FORCE_GPIO32_EN, BIT(3)),
 	AIROHA_PINCTRL_PHY_LED1("gpio42", GPIO_LAN3_LED1_MODE_MASK,
-				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(2)),
+				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(2),
+				REG_FORCE_GPIO32_EN, BIT(10)),
 };
 
 static const struct airoha_pinctrl_func_group phy4_led1_func_group[] = {
 	AIROHA_PINCTRL_PHY_LED1("gpio33", GPIO_LAN0_LED1_MODE_MASK,
-				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(3)),
+				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(3),
+				REG_FORCE_GPIO32_EN, BIT(1)),
 	AIROHA_PINCTRL_PHY_LED1("gpio34", GPIO_LAN1_LED1_MODE_MASK,
-				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(3)),
+				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(3),
+				REG_FORCE_GPIO32_EN, BIT(2)),
 	AIROHA_PINCTRL_PHY_LED1("gpio35", GPIO_LAN2_LED1_MODE_MASK,
-				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(3)),
+				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(3),
+				REG_FORCE_GPIO32_EN, BIT(3)),
 	AIROHA_PINCTRL_PHY_LED1("gpio42", GPIO_LAN3_LED1_MODE_MASK,
-				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(3)),
+				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(3),
+				REG_FORCE_GPIO32_EN, BIT(10)),
 };
 
 static const struct airoha_pinctrl_func pinctrl_funcs[] = {
@@ -1168,7 +1570,7 @@ static const struct airoha_pinctrl_func pinctrl_funcs[] = {
 	PINCTRL_FUNC_DESC("i2s", i2s),
 	PINCTRL_FUNC_DESC("emmc", emmc),
 	PINCTRL_FUNC_DESC("pnand", pnand),
-	PINCTRL_FUNC_DESC("gpio", gpio),
+	PINCTRL_GPIO_FUNC_DESC("gpio", gpio),
 	PINCTRL_FUNC_DESC("pcie_reset", pcie_reset),
 	PINCTRL_FUNC_DESC("pwm", pwm),
 	PINCTRL_FUNC_DESC("phy1_led0", phy1_led0),
@@ -1432,6 +1834,7 @@ static const struct airoha_pinctrl_conf pinctrl_pcie_rst_od_conf[] = {
 };
 
 static const struct airoha_pinctrl_match_data pinctrl_match_data = {
+	.check_mux_conflicts = true,
 	.chip_scu_compatible = "airoha,en7581-chip-scu",
 	.pinctrl_name = KBUILD_MODNAME,
 	.pinctrl_owner = THIS_MODULE,
-- 
2.43.0


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

* [PATCH 06/12] dt-bindings: pinctrl: airoha: describe all AN7583 GPIO mux groups
  2026-11-10  9:43 [PATCH 00/12] pinctrl: airoha: configure GPIO muxes explicitly and fix pad mappings Zhengping Zhang
                   ` (4 preceding siblings ...)
  2026-11-10  9:43 ` [PATCH 05/12] pinctrl: airoha: an7581: select force GPIO mode on GPIO requests Zhengping Zhang
@ 2026-11-10  9:43 ` Zhengping Zhang
  2026-11-10  9:43 ` [PATCH 07/12] pinctrl: airoha: an7583: fix SPI pin mux config Zhengping Zhang
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 17+ messages in thread
From: Zhengping Zhang @ 2026-11-10  9:43 UTC (permalink / raw)
  To: linusw, lorenzo
  Cc: robh, krzk+dt, conor+dt, brgl, mikhail.kshevetskiy, naseefkm,
	benjamin.larsson, linux-gpio, devicetree, linux-kernel,
	linux-mediatek, lei.dong, ansuelsmth, Zhengping Zhang

Expand the GPIO mux groups from GPIO39-52 to GPIO0-52 to describe
explicit GPIO mode selection across the controller's GPIO range.
Allow multiple GPIO groups in a single mux state.

Add spi to the supported SPI groups alongside spi_quad and spi_cs1,
and increase maxItems to allow all three groups in a single mux
state.

The corresponding driver support is added in subsequent patches.

Signed-off-by: Zhengping Zhang <zhengping.zhang@airoha.com>
---
 .../pinctrl/airoha,an7583-pinctrl.yaml         | 18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)

diff --git a/Documentation/devicetree/bindings/pinctrl/airoha,an7583-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/airoha,an7583-pinctrl.yaml
index aad2e9880ec6c..1a24c01eb4102 100644
--- a/Documentation/devicetree/bindings/pinctrl/airoha,an7583-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/airoha,an7583-pinctrl.yaml
@@ -157,8 +157,8 @@ patternProperties:
               properties:
                 groups:
                   items:
-                    enum: [spi_quad, spi_cs1]
-                  maxItems: 2
+                    enum: [spi, spi_quad, spi_cs1]
+                  maxItems: 3
           - if:
               properties:
                 function:
@@ -192,9 +192,17 @@ patternProperties:
             then:
               properties:
                 groups:
-                  enum: [gpio39, gpio40, gpio41, gpio42, gpio43, gpio44,
-                         gpio45, gpio46, gpio47, gpio48, gpio49, gpio50,
-                         gpio51, gpio52]
+                  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, gpio40, gpio41,
+                           gpio42, gpio43, gpio44, gpio45, gpio46, gpio47, gpio48,
+                           gpio49, gpio50, gpio51, gpio52]
+                  minItems: 1
+                  maxItems: 53
           - if:
               properties:
                 function:
-- 
2.43.0


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

* [PATCH 07/12] pinctrl: airoha: an7583: fix SPI pin mux config
  2026-11-10  9:43 [PATCH 00/12] pinctrl: airoha: configure GPIO muxes explicitly and fix pad mappings Zhengping Zhang
                   ` (5 preceding siblings ...)
  2026-11-10  9:43 ` [PATCH 06/12] dt-bindings: pinctrl: airoha: describe all AN7583 GPIO mux groups Zhengping Zhang
@ 2026-11-10  9:43 ` Zhengping Zhang
  2026-11-10  9:43 ` [PATCH 08/12] pinctrl: airoha: an7583: fix eMMC " Zhengping Zhang
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 17+ messages in thread
From: Zhengping Zhang @ 2026-11-10  9:43 UTC (permalink / raw)
  To: linusw, lorenzo
  Cc: robh, krzk+dt, conor+dt, brgl, mikhail.kshevetskiy, naseefkm,
	benjamin.larsson, linux-gpio, devicetree, linux-kernel,
	linux-mediatek, lei.dong, ansuelsmth, Daniel Schwierzeck,
	Zhengping Zhang

From: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>

The SPI function does not advertise the base "spi" group or provide its
mux configuration, so a DTS state using function = "spi" and
groups = "spi" cannot be selected successfully.

On AN7583, pinctrl pins 45-48 correspond to GPIO43-46 and are shared
with the first SPI bus. Bits 19-22 of REG_GPIO_PON_MODE select GPIO
operation when set. If the bootloader leaves these bits enabled,
selecting SPI must clear them to release the GPIO overrides.

Add the "spi" group to the SPI function and clear its GPIO mode bits
when selecting it.

Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
Signed-off-by: Zhengping Zhang <zhengping.zhang@airoha.com>
---
 drivers/pinctrl/airoha/pinctrl-an7583.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/drivers/pinctrl/airoha/pinctrl-an7583.c b/drivers/pinctrl/airoha/pinctrl-an7583.c
index 1cd0f442ddc1d..986f10c9f1786 100644
--- a/drivers/pinctrl/airoha/pinctrl-an7583.c
+++ b/drivers/pinctrl/airoha/pinctrl-an7583.c
@@ -43,6 +43,7 @@
 #define MDC_0_GPIO_MODE_MASK			BIT(25)
 #define UART_RXD_GPIO_MODE_MASK			BIT(24)
 #define UART_TXD_GPIO_MODE_MASK			BIT(23)
+#define SPI_GPIO_MODE_MASK			GENMASK(22, 19)
 #define SPI_MISO_GPIO_MODE_MASK			BIT(22)
 #define SPI_MOSI_GPIO_MODE_MASK			BIT(21)
 #define SPI_CS_GPIO_MODE_MASK			BIT(20)
@@ -584,7 +585,7 @@ static const char *const uart_groups[] = {
 static const char *const i2c_groups[] = { "i2c0", "i2c1" };
 static const char *const jtag_groups[] = { "jtag_udi", "jtag_dfd" };
 static const char *const pcm_groups[] = { "pcm1", "pcm2" };
-static const char *const spi_groups[] = { "spi_quad", "spi_cs1" };
+static const char *const spi_groups[] = { "spi", "spi_quad", "spi_cs1" };
 static const char *const pcm_spi_groups[] = {
 	"pcm_spi", "pcm_spi_rst", "pcm_spi_cs1"
 };
@@ -861,6 +862,15 @@ static const struct airoha_pinctrl_func_group pcm_func_group[] = {
 
 static const struct airoha_pinctrl_func_group spi_func_group[] = {
 	{
+		.name = "spi",
+		.regmap[0] = {
+			AIROHA_FUNC_MUX,
+			REG_GPIO_PON_MODE,
+			SPI_GPIO_MODE_MASK,
+			0
+		},
+		.regmap_size = 1,
+	}, {
 		.name = "spi_quad",
 		.regmap[0] = {
 			AIROHA_FUNC_MUX,
-- 
2.43.0


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

* [PATCH 08/12] pinctrl: airoha: an7583: fix eMMC pin mux config
  2026-11-10  9:43 [PATCH 00/12] pinctrl: airoha: configure GPIO muxes explicitly and fix pad mappings Zhengping Zhang
                   ` (6 preceding siblings ...)
  2026-11-10  9:43 ` [PATCH 07/12] pinctrl: airoha: an7583: fix SPI pin mux config Zhengping Zhang
@ 2026-11-10  9:43 ` Zhengping Zhang
  2026-11-10  9:43 ` [PATCH 09/12] pinctrl: airoha: an7583: use force GPIO mode for GPIO requests Zhengping Zhang
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 17+ messages in thread
From: Zhengping Zhang @ 2026-11-10  9:43 UTC (permalink / raw)
  To: linusw, lorenzo
  Cc: robh, krzk+dt, conor+dt, brgl, mikhail.kshevetskiy, naseefkm,
	benjamin.larsson, linux-gpio, devicetree, linux-kernel,
	linux-mediatek, lei.dong, ansuelsmth, Robert Marko,
	Zhengping Zhang

From: Robert Marko <robert.marko@sartura.hr>

The AN7583 eMMC group includes three pads shared with the first SPI
bus: pinctrl pins 45-47, corresponding to GPIO43-45. Their GPIO
operation is selected by bits 19-21 of REG_GPIO_PON_MODE.

The eMMC mux configuration only enables GPIO_EMMC_MODE_MASK, leaving
these pads in GPIO mode if their overrides were enabled by the
bootloader.

Clear the GPIO mode bits for these three pads when selecting eMMC.
Preserve bit 22, which controls the SPI MISO/GPIO46 pad outside the
eMMC group.

Signed-off-by: Robert Marko <robert.marko@sartura.hr>
Signed-off-by: Zhengping Zhang <zhengping.zhang@airoha.com>
---
 drivers/pinctrl/airoha/pinctrl-an7583.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/pinctrl/airoha/pinctrl-an7583.c b/drivers/pinctrl/airoha/pinctrl-an7583.c
index 986f10c9f1786..74628a03ca909 100644
--- a/drivers/pinctrl/airoha/pinctrl-an7583.c
+++ b/drivers/pinctrl/airoha/pinctrl-an7583.c
@@ -44,6 +44,7 @@
 #define UART_RXD_GPIO_MODE_MASK			BIT(24)
 #define UART_TXD_GPIO_MODE_MASK			BIT(23)
 #define SPI_GPIO_MODE_MASK			GENMASK(22, 19)
+#define EMMC_GPIO_MODE_MASK			GENMASK(21, 19)
 #define SPI_MISO_GPIO_MODE_MASK			BIT(22)
 #define SPI_MOSI_GPIO_MODE_MASK			BIT(21)
 #define SPI_CS_GPIO_MODE_MASK			BIT(20)
@@ -991,7 +992,7 @@ static const struct airoha_pinctrl_func_group emmc_func_group[] = {
 		.regmap[0] = {
 			AIROHA_FUNC_MUX,
 			REG_GPIO_PON_MODE,
-			GPIO_EMMC_MODE_MASK,
+			GPIO_EMMC_MODE_MASK | EMMC_GPIO_MODE_MASK,
 			GPIO_EMMC_MODE_MASK
 		},
 		.regmap_size = 1,
-- 
2.43.0


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

* [PATCH 09/12] pinctrl: airoha: an7583: use force GPIO mode for GPIO requests
  2026-11-10  9:43 [PATCH 00/12] pinctrl: airoha: configure GPIO muxes explicitly and fix pad mappings Zhengping Zhang
                   ` (7 preceding siblings ...)
  2026-11-10  9:43 ` [PATCH 08/12] pinctrl: airoha: an7583: fix eMMC " Zhengping Zhang
@ 2026-11-10  9:43 ` Zhengping Zhang
  2026-11-10  9:56   ` sashiko-bot
  2026-11-10  9:43 ` [PATCH 10/12] dt-bindings: pinctrl: airoha: describe all EN7523 GPIO mux groups Zhengping Zhang
                   ` (2 subsequent siblings)
  11 siblings, 1 reply; 17+ messages in thread
From: Zhengping Zhang @ 2026-11-10  9:43 UTC (permalink / raw)
  To: linusw, lorenzo
  Cc: robh, krzk+dt, conor+dt, brgl, mikhail.kshevetskiy, naseefkm,
	benjamin.larsson, linux-gpio, devicetree, linux-kernel,
	linux-mediatek, lei.dong, ansuelsmth, Zhengping Zhang

GPIO requests can leave pads controlled by alternate functions selected
by the bootloader. Enable the shared GPIO request handling and mux
conflict checks so GPIO consumers and explicit GPIO pinctrl states
select the same GPIO group configuration.

Use per-pad GPIO overrides without disabling shared peripheral modes
on other pads. Select GPIO mode using the following SCU register bits,
where n is the GPIO number:

  - GPIO1-31: set bit n in register 0x228.
  - GPIO32-38: set bit (n - 32) in register 0x22c.
  - GPIO39-48: set bit (n - 24) in register 0x21c.
  - GPIO49/50: set the PCIe reset GPIO selectors in register
    0x21c, bits 9/10 respectively.
  - GPIO51/52: set the MDC/MDIO GPIO selectors in register
    0x21c, bits 25/26 respectively.
  - GPIO0: clear its PWM selection only; no force GPIO bit is documented.

Clear the pad's PWM selection when selecting GPIO. When selecting a
peripheral function, clear the GPIO overrides for its pads so an
earlier GPIO configuration does not prevent peripheral operation.
Set the corresponding GPIO override when selecting PWM output.

Exclude the software-controlled TX_DIS/RX_DIS pads from the hardware
PON mux groups. These signals serve the PON interface but are intended
to be requested as GPIOs by the PON PHY driver and controlled through
the GPIO API rather than driven by the PON hardware. This avoids
ownership conflicts between PON mux selection and GPIO requests.

Signed-off-by: Zhengping Zhang <zhengping.zhang@airoha.com>
---
 drivers/pinctrl/airoha/pinctrl-an7583.c | 721 +++++++++++++++++++-----
 1 file changed, 572 insertions(+), 149 deletions(-)

diff --git a/drivers/pinctrl/airoha/pinctrl-an7583.c b/drivers/pinctrl/airoha/pinctrl-an7583.c
index 74628a03ca909..e2f629d9d43cd 100644
--- a/drivers/pinctrl/airoha/pinctrl-an7583.c
+++ b/drivers/pinctrl/airoha/pinctrl-an7583.c
@@ -75,6 +75,7 @@
 #define NPU_UART_EN_MASK			BIT(2)
 
 #define REG_FORCE_GPIO_EN			0x0228
+#define REG_FORCE_GPIO32_EN			0x022c
 #define FORCE_GPIO_EN(n)			BIT(n)
 
 /* LED MAP */
@@ -260,7 +261,7 @@
 	}
 
 /* PWM */
-#define AIROHA_PINCTRL_PWM(gpio, mux_val)			\
+#define AIROHA_PINCTRL_PWM(gpio, mux_val, force_reg, force_mask) \
 	{							\
 		.name = (gpio),					\
 		.regmap[0] = {					\
@@ -269,10 +270,14 @@
 			(mux_val),				\
 			(mux_val)				\
 		},						\
-		.regmap_size = 1,				\
+		.regmap[1] = {					\
+			AIROHA_FUNC_MUX, (force_reg),		\
+			(force_mask), (force_mask)			\
+		},						\
+		.regmap_size = 2,				\
 	}
 
-#define AIROHA_PINCTRL_PWM_EXT(gpio, mux_val)			\
+#define AIROHA_PINCTRL_PWM_EXT(gpio, mux_val, force_reg, force_mask) \
 	{							\
 		.name = (gpio),					\
 		.regmap[0] = {					\
@@ -281,10 +286,14 @@
 			(mux_val),				\
 			(mux_val)				\
 		},						\
-		.regmap_size = 1,				\
+		.regmap[1] = {					\
+			AIROHA_FUNC_MUX, (force_reg),		\
+			(force_mask), (force_mask)			\
+		},						\
+		.regmap_size = 2,				\
 	}
 
-#define AIROHA_PINCTRL_PWM_EXT_SEC(gpio, mux_val, smux_val)	\
+#define AIROHA_PINCTRL_PWM_EXT_SEC(gpio, mux_val, smux_val, force_reg, force_mask) \
 	{							\
 		.name = (gpio),					\
 		.regmap[0] = {					\
@@ -299,10 +308,14 @@
 			(smux_val),				\
 			(smux_val)				\
 		},						\
-		.regmap_size = 2,				\
+		.regmap[2] = {					\
+			AIROHA_FUNC_MUX, (force_reg),		\
+			(force_mask), (force_mask)			\
+		},						\
+		.regmap_size = 3,				\
 	}
 
-#define AIROHA_PINCTRL_PHY_LED0(gpio, mux_val, map_mask, map_val)	\
+#define AIROHA_PINCTRL_PHY_LED0(gpio, mux_val, map_mask, map_val, force_reg, force_mask) \
 	{								\
 		.name = (gpio),						\
 		.regmap[0] = {						\
@@ -317,10 +330,14 @@
 			(map_mask),					\
 			(map_val),					\
 		},							\
-		.regmap_size = 2,					\
+		.regmap[2] = {					\
+			AIROHA_FUNC_MUX, (force_reg),		\
+			(force_mask), 0			\
+		},						\
+		.regmap_size = 3,					\
 	}
 
-#define AIROHA_PINCTRL_PHY_LED1(gpio, mux_val, map_mask, map_val)	\
+#define AIROHA_PINCTRL_PHY_LED1(gpio, mux_val, map_mask, map_val, force_reg, force_mask) \
 	{								\
 		.name = (gpio),						\
 		.regmap[0] = {						\
@@ -335,7 +352,11 @@
 			(map_mask),					\
 			(map_val),					\
 		},							\
-		.regmap_size = 2,					\
+		.regmap[2] = {					\
+			AIROHA_FUNC_MUX, (force_reg),		\
+			(force_mask), 0			\
+		},						\
+		.regmap_size = 3,					\
 	}
 
 static struct pinctrl_pin_desc pinctrl_pins[] = {
@@ -394,8 +415,10 @@ static struct pinctrl_pin_desc pinctrl_pins[] = {
 	PINCTRL_PIN(54, "mdio_0"),
 };
 
-static const int pon_pins[] = { 15, 16, 17, 18, 19, 20 };
-static const int pon_alt_pins[] = { 36, 37, 38, 39, 40 };
+/* TX_DIS (GPIO15) and RX_DIS (GPIO16) are software GPIOs. */
+static const int pon_pins[] = { 15, 16, 19, 20 };
+/* Alternate TX_DIS/RX_DIS (GPIO34-35) remain software GPIOs. */
+static const int pon_alt_pins[] = { 38, 39, 40 };
 static const int olt_pins[] = { 36, 37, 38, 39, 40 };
 static const int pon_tod_1pps_pins[] = { 32 };
 static const int gsw_tod_1pps_pins[] = { 32 };
@@ -593,9 +616,15 @@ static const char *const pcm_spi_groups[] = {
 static const char *const emmc_groups[] = { "emmc" };
 static const char *const pnand_groups[] = { "pnand" };
 static const char *const gpio_groups[] = {
-	"gpio39", "gpio40", "gpio41", "gpio42", "gpio43",
-	"gpio44", "gpio45", "gpio46", "gpio47", "gpio48",
-	"gpio49", "gpio50", "gpio51", "gpio52"
+	"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",
+	"gpio42", "gpio43", "gpio44", "gpio45", "gpio46", "gpio47",
+	"gpio48", "gpio49", "gpio50", "gpio51", "gpio52",
 };
 static const char *const pcie_reset_groups[] = {
 	"pcie_reset0", "pcie_reset1"
@@ -644,7 +673,16 @@ static const struct airoha_pinctrl_func_group pon_func_group[] = {
 			GPIO_PON_MODE_MASK | GPIO_PON_ALT_MODE_MASK,
 			GPIO_PON_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(13) |
+			BIT(14) |
+			BIT(17) |
+			BIT(18),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "pon_alt",
 		.regmap[0] = {
@@ -653,7 +691,15 @@ static const struct airoha_pinctrl_func_group pon_func_group[] = {
 			GPIO_PON_MODE_MASK | GPIO_PON_ALT_MODE_MASK,
 			GPIO_PON_ALT_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO32_EN,
+			BIT(4) |
+			BIT(5) |
+			BIT(6),
+			0
+		},
+		.regmap_size = 2,
 	},
 };
 
@@ -666,7 +712,17 @@ static const struct airoha_pinctrl_func_group olt_func_group[] = {
 			GPIO_OLT_MODE_MASK,
 			GPIO_OLT_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO32_EN,
+			BIT(2) |
+			BIT(3) |
+			BIT(4) |
+			BIT(5) |
+			BIT(6),
+			0
+		},
+		.regmap_size = 2,
 	},
 };
 
@@ -679,7 +735,13 @@ static const struct airoha_pinctrl_func_group tod_1pps_func_group[] = {
 			PON_TOD_1PPS_MODE_MASK,
 			PON_TOD_1PPS_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(30),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "gsw_tod_1pps",
 		.regmap[0] = {
@@ -688,7 +750,13 @@ static const struct airoha_pinctrl_func_group tod_1pps_func_group[] = {
 			GSW_TOD_1PPS_MODE_MASK,
 			GSW_TOD_1PPS_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(30),
+			0
+		},
+		.regmap_size = 2,
 	},
 };
 
@@ -701,7 +769,14 @@ static const struct airoha_pinctrl_func_group sipo_func_group[] = {
 			GPIO_SIPO_MODE_MASK | SIPO_RCLK_MODE_MASK,
 			GPIO_SIPO_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO32_EN,
+			BIT(0) |
+			BIT(1),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "sipo_rclk",
 		.regmap[0] = {
@@ -710,7 +785,20 @@ static const struct airoha_pinctrl_func_group sipo_func_group[] = {
 			GPIO_SIPO_MODE_MASK | SIPO_RCLK_MODE_MASK,
 			GPIO_SIPO_MODE_MASK | SIPO_RCLK_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(31),
+			0
+		},
+		.regmap[2] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO32_EN,
+			BIT(0) |
+			BIT(1),
+			0
+		},
+		.regmap_size = 3,
 	},
 };
 
@@ -736,7 +824,14 @@ static const struct airoha_pinctrl_func_group uart_func_group[] = {
 			GPIO_UART2_MODE_MASK,
 			GPIO_UART2_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO32_EN,
+			BIT(0) |
+			BIT(1),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "uart2_cts_rts",
 		.regmap[0] = {
@@ -745,7 +840,14 @@ static const struct airoha_pinctrl_func_group uart_func_group[] = {
 			GPIO_UART2_MODE_MASK | GPIO_UART2_CTS_RTS_MODE_MASK,
 			GPIO_UART2_MODE_MASK | GPIO_UART2_CTS_RTS_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(30) |
+			BIT(31),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "hsuart",
 		.regmap[0] = {
@@ -754,7 +856,14 @@ static const struct airoha_pinctrl_func_group uart_func_group[] = {
 			GPIO_HSUART_MODE_MASK | GPIO_HSUART_CTS_RTS_MODE_MASK,
 			GPIO_HSUART_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(28) |
+			BIT(29),
+			0
+		},
+		.regmap_size = 2,
 	},
 	{
 		.name = "hsuart_cts_rts",
@@ -764,7 +873,14 @@ static const struct airoha_pinctrl_func_group uart_func_group[] = {
 			GPIO_HSUART_MODE_MASK | GPIO_HSUART_CTS_RTS_MODE_MASK,
 			GPIO_HSUART_MODE_MASK | GPIO_HSUART_CTS_RTS_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(26) |
+			BIT(27),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "uart4",
 		.regmap[0] = {
@@ -773,7 +889,14 @@ static const struct airoha_pinctrl_func_group uart_func_group[] = {
 			GPIO_UART4_MODE_MASK,
 			GPIO_UART4_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(5) |
+			BIT(6),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "uart5",
 		.regmap[0] = {
@@ -782,7 +905,14 @@ static const struct airoha_pinctrl_func_group uart_func_group[] = {
 			GPIO_UART5_MODE_MASK,
 			GPIO_UART5_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(21) |
+			BIT(22),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "npu_uart",
 		.regmap[0] = {
@@ -791,7 +921,14 @@ static const struct airoha_pinctrl_func_group uart_func_group[] = {
 			NPU_UART_EN_MASK,
 			NPU_UART_EN_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(5) |
+			BIT(6),
+			0
+		},
+		.regmap_size = 2,
 	},
 };
 
@@ -826,7 +963,17 @@ static const struct airoha_pinctrl_func_group jtag_func_group[] = {
 			JTAG_UDI_EN_MASK,
 			JTAG_UDI_EN_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(20) |
+			BIT(21) |
+			BIT(22) |
+			BIT(23) |
+			BIT(24),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "jtag_dfd",
 		.regmap[0] = {
@@ -835,7 +982,17 @@ static const struct airoha_pinctrl_func_group jtag_func_group[] = {
 			JTAG_DFD_EN_MASK,
 			JTAG_DFD_EN_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(20) |
+			BIT(21) |
+			BIT(22) |
+			BIT(23) |
+			BIT(24),
+			0
+		},
+		.regmap_size = 2,
 	},
 };
 
@@ -848,7 +1005,17 @@ static const struct airoha_pinctrl_func_group pcm_func_group[] = {
 			GPIO_PCM1_MODE_MASK,
 			GPIO_PCM1_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(8) |
+			BIT(9) |
+			BIT(10) |
+			BIT(11) |
+			BIT(12),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "pcm2",
 		.regmap[0] = {
@@ -857,7 +1024,17 @@ static const struct airoha_pinctrl_func_group pcm_func_group[] = {
 			GPIO_PCM2_MODE_MASK,
 			GPIO_PCM2_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(22) |
+			BIT(26) |
+			BIT(27) |
+			BIT(28) |
+			BIT(29),
+			0
+		},
+		.regmap_size = 2,
 	},
 };
 
@@ -879,7 +1056,14 @@ static const struct airoha_pinctrl_func_group spi_func_group[] = {
 			GPIO_SPI_QUAD_MODE_MASK,
 			GPIO_SPI_QUAD_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(23) |
+			BIT(24),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "spi_cs1",
 		.regmap[0] = {
@@ -888,7 +1072,13 @@ static const struct airoha_pinctrl_func_group spi_func_group[] = {
 			GPIO_SPI_CS1_MODE_MASK,
 			GPIO_SPI_CS1_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(25),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "spi_cs2",
 		.regmap[0] = {
@@ -928,7 +1118,20 @@ static const struct airoha_pinctrl_func_group pcm_spi_func_group[] = {
 			GPIO_PCM_SPI_MODE_MASK,
 			GPIO_PCM_SPI_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(8) |
+			BIT(9) |
+			BIT(10) |
+			BIT(11) |
+			BIT(26) |
+			BIT(27) |
+			BIT(28) |
+			BIT(29),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "pcm_spi_int",
 		.regmap[0] = {
@@ -946,7 +1149,13 @@ static const struct airoha_pinctrl_func_group pcm_spi_func_group[] = {
 			GPIO_PCM_RESET_MODE_MASK,
 			GPIO_PCM_RESET_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(12),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "pcm_spi_cs1",
 		.regmap[0] = {
@@ -955,7 +1164,13 @@ static const struct airoha_pinctrl_func_group pcm_spi_func_group[] = {
 			GPIO_PCM_SPI_CS1_MODE_MASK,
 			GPIO_PCM_SPI_CS1_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(22),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "pcm_spi_cs2",
 		.regmap[0] = {
@@ -995,7 +1210,20 @@ static const struct airoha_pinctrl_func_group emmc_func_group[] = {
 			GPIO_EMMC_MODE_MASK | EMMC_GPIO_MODE_MASK,
 			GPIO_EMMC_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(5) |
+			BIT(6) |
+			BIT(7) |
+			BIT(20) |
+			BIT(21) |
+			BIT(22) |
+			BIT(23) |
+			BIT(24),
+			0
+		},
+		.regmap_size = 2,
 	},
 };
 
@@ -1005,41 +1233,155 @@ static const struct airoha_pinctrl_func_group pnand_func_group[] = {
 		.regmap[0] = {
 			AIROHA_FUNC_MUX,
 			REG_GPIO_PON_MODE,
-			GPIO_PARALLEL_NAND_MODE_MASK,
+			GPIO_PARALLEL_NAND_MODE_MASK | SPI_GPIO_MODE_MASK,
 			GPIO_PARALLEL_NAND_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(5) |
+			BIT(6) |
+			BIT(7) |
+			BIT(20) |
+			BIT(21) |
+			BIT(22) |
+			BIT(23) |
+			BIT(24) |
+			BIT(25) |
+			BIT(26) |
+			BIT(27) |
+			BIT(28) |
+			BIT(29),
+			0
+		},
+		.regmap_size = 2,
 	},
 };
 
+/* Force overrides select individual pads without disabling shared buses. */
+#define AN7583_GPIO_GROUP(n, pwm_mask, force_reg, force_mask)	\
+	{								\
+		.name = "gpio" #n,					\
+		.regmap[0] = {						\
+			AIROHA_FUNC_PWM_MUX,				\
+			(n) < 16 ? REG_GPIO_FLASH_MODE_CFG :		\
+			REG_GPIO_FLASH_MODE_CFG_EXT,			\
+			(pwm_mask), 0					\
+		},							\
+		.regmap[1] = {						\
+			AIROHA_FUNC_MUX, (force_reg),			\
+			(force_mask), (force_mask)			\
+		},							\
+		.regmap_size = 2,					\
+	}
+
 static const struct airoha_pinctrl_func_group gpio_func_group[] = {
-	AIROHA_PINCTRL_GPIO_EXT("gpio39", GPIO39_FLASH_MODE_CFG,
-				I2C0_SCL_GPIO_MODE_MASK),
-	AIROHA_PINCTRL_GPIO_EXT("gpio40", GPIO40_FLASH_MODE_CFG,
-				I2C0_SDA_GPIO_MODE_MASK),
-	AIROHA_PINCTRL_GPIO_EXT("gpio41", GPIO41_FLASH_MODE_CFG,
-				I2C1_SCL_GPIO_MODE_MASK),
-	AIROHA_PINCTRL_GPIO_EXT("gpio42", GPIO42_FLASH_MODE_CFG,
-				I2C1_SDA_GPIO_MODE_MASK),
-	AIROHA_PINCTRL_GPIO_EXT("gpio43", GPIO43_FLASH_MODE_CFG,
-				SPI_CLK_GPIO_MODE_MASK),
-	AIROHA_PINCTRL_GPIO_EXT("gpio44", GPIO44_FLASH_MODE_CFG,
-				SPI_CS_GPIO_MODE_MASK),
-	AIROHA_PINCTRL_GPIO_EXT("gpio45", GPIO45_FLASH_MODE_CFG,
-				SPI_MOSI_GPIO_MODE_MASK),
-	AIROHA_PINCTRL_GPIO_EXT("gpio46", GPIO46_FLASH_MODE_CFG,
-				SPI_MISO_GPIO_MODE_MASK),
-	AIROHA_PINCTRL_GPIO_EXT("gpio47", GPIO47_FLASH_MODE_CFG,
-				UART_TXD_GPIO_MODE_MASK),
-	AIROHA_PINCTRL_GPIO_EXT("gpio48", GPIO48_FLASH_MODE_CFG,
-				UART_RXD_GPIO_MODE_MASK),
-	AIROHA_PINCTRL_GPIO_EXT("gpio49", GPIO49_FLASH_MODE_CFG,
-				GPIO_PCIE_RESET0_MASK),
-	AIROHA_PINCTRL_GPIO_EXT("gpio50", GPIO50_FLASH_MODE_CFG,
-				GPIO_PCIE_RESET1_MASK),
-	AIROHA_PINCTRL_GPIO_EXT("gpio51", GPIO51_FLASH_MODE_CFG,
-				MDC_0_GPIO_MODE_MASK),
-	AIROHA_PINCTRL_GPIO("gpio52", MDIO_0_GPIO_MODE_MASK),
+	AN7583_GPIO_GROUP(0, GPIO0_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, 0),
+	AN7583_GPIO_GROUP(1, GPIO1_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(1)),
+	AN7583_GPIO_GROUP(2, GPIO2_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(2)),
+	AN7583_GPIO_GROUP(3, GPIO3_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(3)),
+	AN7583_GPIO_GROUP(4, GPIO4_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(4)),
+	AN7583_GPIO_GROUP(5, GPIO5_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(5)),
+	AN7583_GPIO_GROUP(6, GPIO6_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(6)),
+	AN7583_GPIO_GROUP(7, GPIO7_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(7)),
+	AN7583_GPIO_GROUP(8, GPIO8_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(8)),
+	AN7583_GPIO_GROUP(9, GPIO9_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(9)),
+	AN7583_GPIO_GROUP(10, GPIO10_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(10)),
+	AN7583_GPIO_GROUP(11, GPIO11_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(11)),
+	AN7583_GPIO_GROUP(12, GPIO12_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(12)),
+	AN7583_GPIO_GROUP(13, GPIO13_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(13)),
+	AN7583_GPIO_GROUP(14, GPIO14_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(14)),
+	AN7583_GPIO_GROUP(15, GPIO15_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(15)),
+	AN7583_GPIO_GROUP(16, GPIO16_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(16)),
+	AN7583_GPIO_GROUP(17, GPIO17_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(17)),
+	AN7583_GPIO_GROUP(18, GPIO18_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(18)),
+	AN7583_GPIO_GROUP(19, GPIO19_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(19)),
+	AN7583_GPIO_GROUP(20, GPIO20_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(20)),
+	AN7583_GPIO_GROUP(21, GPIO21_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(21)),
+	AN7583_GPIO_GROUP(22, GPIO22_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(22)),
+	AN7583_GPIO_GROUP(23, GPIO23_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(23)),
+	AN7583_GPIO_GROUP(24, GPIO24_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(24)),
+	AN7583_GPIO_GROUP(25, GPIO25_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(25)),
+	AN7583_GPIO_GROUP(26, GPIO26_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(26)),
+	AN7583_GPIO_GROUP(27, GPIO27_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(27)),
+	AN7583_GPIO_GROUP(28, GPIO28_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(28)),
+	AN7583_GPIO_GROUP(29, GPIO29_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(29)),
+	AN7583_GPIO_GROUP(30, GPIO30_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(30)),
+	AN7583_GPIO_GROUP(31, GPIO31_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(31)),
+	AN7583_GPIO_GROUP(32, 0,
+			    REG_FORCE_GPIO32_EN, BIT(0)),
+	AN7583_GPIO_GROUP(33, 0,
+			    REG_FORCE_GPIO32_EN, BIT(1)),
+	AN7583_GPIO_GROUP(34, 0,
+			    REG_FORCE_GPIO32_EN, BIT(2)),
+	AN7583_GPIO_GROUP(35, 0,
+			    REG_FORCE_GPIO32_EN, BIT(3)),
+	AN7583_GPIO_GROUP(36, GPIO36_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO32_EN, BIT(4)),
+	AN7583_GPIO_GROUP(37, GPIO37_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO32_EN, BIT(5)),
+	AN7583_GPIO_GROUP(38, GPIO38_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO32_EN, BIT(6)),
+	AN7583_GPIO_GROUP(39, GPIO39_FLASH_MODE_CFG,
+			    REG_GPIO_PON_MODE, I2C0_SCL_GPIO_MODE_MASK),
+	AN7583_GPIO_GROUP(40, GPIO40_FLASH_MODE_CFG,
+			    REG_GPIO_PON_MODE, I2C0_SDA_GPIO_MODE_MASK),
+	AN7583_GPIO_GROUP(41, GPIO41_FLASH_MODE_CFG,
+			    REG_GPIO_PON_MODE, I2C1_SCL_GPIO_MODE_MASK),
+	AN7583_GPIO_GROUP(42, GPIO42_FLASH_MODE_CFG,
+			    REG_GPIO_PON_MODE, I2C1_SDA_GPIO_MODE_MASK),
+	AN7583_GPIO_GROUP(43, GPIO43_FLASH_MODE_CFG,
+			    REG_GPIO_PON_MODE, SPI_CLK_GPIO_MODE_MASK),
+	AN7583_GPIO_GROUP(44, GPIO44_FLASH_MODE_CFG,
+			    REG_GPIO_PON_MODE, SPI_CS_GPIO_MODE_MASK),
+	AN7583_GPIO_GROUP(45, GPIO45_FLASH_MODE_CFG,
+			    REG_GPIO_PON_MODE, SPI_MOSI_GPIO_MODE_MASK),
+	AN7583_GPIO_GROUP(46, GPIO46_FLASH_MODE_CFG,
+			    REG_GPIO_PON_MODE, SPI_MISO_GPIO_MODE_MASK),
+	AN7583_GPIO_GROUP(47, GPIO47_FLASH_MODE_CFG,
+			    REG_GPIO_PON_MODE, UART_TXD_GPIO_MODE_MASK),
+	AN7583_GPIO_GROUP(48, GPIO48_FLASH_MODE_CFG,
+			    REG_GPIO_PON_MODE, UART_RXD_GPIO_MODE_MASK),
+	AN7583_GPIO_GROUP(49, GPIO49_FLASH_MODE_CFG,
+			    REG_GPIO_PON_MODE, GPIO_PCIE_RESET0_MASK),
+	AN7583_GPIO_GROUP(50, GPIO50_FLASH_MODE_CFG,
+			    REG_GPIO_PON_MODE, GPIO_PCIE_RESET1_MASK),
+	AN7583_GPIO_GROUP(51, GPIO51_FLASH_MODE_CFG,
+			    REG_GPIO_PON_MODE, MDC_0_GPIO_MODE_MASK),
+	AN7583_GPIO_GROUP(52, 0,
+			    REG_GPIO_PON_MODE, MDIO_0_GPIO_MODE_MASK),
 };
 
 static const struct airoha_pinctrl_func_group pcie_reset_func_group[] = {
@@ -1065,155 +1407,235 @@ static const struct airoha_pinctrl_func_group pcie_reset_func_group[] = {
 };
 
 static const struct airoha_pinctrl_func_group pwm_func_group[] = {
-	AIROHA_PINCTRL_PWM("gpio0", GPIO0_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM("gpio1", GPIO1_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM("gpio2", GPIO2_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM("gpio3", GPIO3_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM("gpio4", GPIO4_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM("gpio5", GPIO5_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM("gpio6", GPIO6_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM("gpio7", GPIO7_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM("gpio8", GPIO8_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM("gpio9", GPIO9_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM("gpio10", GPIO10_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM("gpio11", GPIO11_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM("gpio12", GPIO12_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM("gpio13", GPIO13_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM("gpio14", GPIO14_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM("gpio15", GPIO15_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM_EXT("gpio16", GPIO16_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM_EXT("gpio17", GPIO17_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM_EXT("gpio18", GPIO18_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM_EXT("gpio19", GPIO19_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM_EXT("gpio20", GPIO20_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM_EXT("gpio21", GPIO21_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM_EXT("gpio22", GPIO22_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM_EXT("gpio23", GPIO23_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM_EXT("gpio24", GPIO24_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM_EXT("gpio25", GPIO25_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM_EXT("gpio26", GPIO26_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM_EXT("gpio27", GPIO27_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM_EXT("gpio28", GPIO28_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM_EXT("gpio29", GPIO29_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM_EXT("gpio30", GPIO30_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM_EXT("gpio31", GPIO31_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM_EXT("gpio36", GPIO36_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM_EXT("gpio37", GPIO37_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM_EXT("gpio38", GPIO38_FLASH_MODE_CFG),
+	AIROHA_PINCTRL_PWM("gpio0", GPIO0_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, 0),
+	AIROHA_PINCTRL_PWM("gpio1", GPIO1_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(1)),
+	AIROHA_PINCTRL_PWM("gpio2", GPIO2_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(2)),
+	AIROHA_PINCTRL_PWM("gpio3", GPIO3_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(3)),
+	AIROHA_PINCTRL_PWM("gpio4", GPIO4_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(4)),
+	AIROHA_PINCTRL_PWM("gpio5", GPIO5_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(5)),
+	AIROHA_PINCTRL_PWM("gpio6", GPIO6_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(6)),
+	AIROHA_PINCTRL_PWM("gpio7", GPIO7_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(7)),
+	AIROHA_PINCTRL_PWM("gpio8", GPIO8_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(8)),
+	AIROHA_PINCTRL_PWM("gpio9", GPIO9_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(9)),
+	AIROHA_PINCTRL_PWM("gpio10", GPIO10_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(10)),
+	AIROHA_PINCTRL_PWM("gpio11", GPIO11_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(11)),
+	AIROHA_PINCTRL_PWM("gpio12", GPIO12_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(12)),
+	AIROHA_PINCTRL_PWM("gpio13", GPIO13_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(13)),
+	AIROHA_PINCTRL_PWM("gpio14", GPIO14_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(14)),
+	AIROHA_PINCTRL_PWM("gpio15", GPIO15_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(15)),
+	AIROHA_PINCTRL_PWM_EXT("gpio16", GPIO16_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(16)),
+	AIROHA_PINCTRL_PWM_EXT("gpio17", GPIO17_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(17)),
+	AIROHA_PINCTRL_PWM_EXT("gpio18", GPIO18_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(18)),
+	AIROHA_PINCTRL_PWM_EXT("gpio19", GPIO19_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(19)),
+	AIROHA_PINCTRL_PWM_EXT("gpio20", GPIO20_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(20)),
+	AIROHA_PINCTRL_PWM_EXT("gpio21", GPIO21_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(21)),
+	AIROHA_PINCTRL_PWM_EXT("gpio22", GPIO22_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(22)),
+	AIROHA_PINCTRL_PWM_EXT("gpio23", GPIO23_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(23)),
+	AIROHA_PINCTRL_PWM_EXT("gpio24", GPIO24_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(24)),
+	AIROHA_PINCTRL_PWM_EXT("gpio25", GPIO25_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(25)),
+	AIROHA_PINCTRL_PWM_EXT("gpio26", GPIO26_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(26)),
+	AIROHA_PINCTRL_PWM_EXT("gpio27", GPIO27_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(27)),
+	AIROHA_PINCTRL_PWM_EXT("gpio28", GPIO28_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(28)),
+	AIROHA_PINCTRL_PWM_EXT("gpio29", GPIO29_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(29)),
+	AIROHA_PINCTRL_PWM_EXT("gpio30", GPIO30_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(30)),
+	AIROHA_PINCTRL_PWM_EXT("gpio31", GPIO31_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(31)),
+	AIROHA_PINCTRL_PWM_EXT("gpio36", GPIO36_FLASH_MODE_CFG,
+				REG_FORCE_GPIO32_EN, BIT(4)),
+	AIROHA_PINCTRL_PWM_EXT("gpio37", GPIO37_FLASH_MODE_CFG,
+				REG_FORCE_GPIO32_EN, BIT(5)),
+	AIROHA_PINCTRL_PWM_EXT("gpio38", GPIO38_FLASH_MODE_CFG,
+				REG_FORCE_GPIO32_EN, BIT(6)),
 	AIROHA_PINCTRL_PWM_EXT_SEC("gpio39", GPIO39_FLASH_MODE_CFG,
-				   I2C0_SCL_GPIO_MODE_MASK),
+				   I2C0_SCL_GPIO_MODE_MASK,
+				REG_FORCE_GPIO_EN, 0),
 	AIROHA_PINCTRL_PWM_EXT_SEC("gpio40", GPIO40_FLASH_MODE_CFG,
-				   I2C0_SDA_GPIO_MODE_MASK),
+				   I2C0_SDA_GPIO_MODE_MASK,
+				REG_FORCE_GPIO_EN, 0),
 	AIROHA_PINCTRL_PWM_EXT_SEC("gpio41", GPIO41_FLASH_MODE_CFG,
-				   I2C1_SCL_GPIO_MODE_MASK),
+				   I2C1_SCL_GPIO_MODE_MASK,
+				REG_FORCE_GPIO_EN, 0),
 	AIROHA_PINCTRL_PWM_EXT_SEC("gpio42", GPIO42_FLASH_MODE_CFG,
-				   I2C1_SDA_GPIO_MODE_MASK),
+				   I2C1_SDA_GPIO_MODE_MASK,
+				REG_FORCE_GPIO_EN, 0),
 	AIROHA_PINCTRL_PWM_EXT_SEC("gpio43", GPIO43_FLASH_MODE_CFG,
-				   SPI_CLK_GPIO_MODE_MASK),
+				   SPI_CLK_GPIO_MODE_MASK,
+				REG_FORCE_GPIO_EN, 0),
 	AIROHA_PINCTRL_PWM_EXT_SEC("gpio44", GPIO44_FLASH_MODE_CFG,
-				   SPI_CS_GPIO_MODE_MASK),
+				   SPI_CS_GPIO_MODE_MASK,
+				REG_FORCE_GPIO_EN, 0),
 	AIROHA_PINCTRL_PWM_EXT_SEC("gpio45", GPIO45_FLASH_MODE_CFG,
-				   SPI_MOSI_GPIO_MODE_MASK),
+				   SPI_MOSI_GPIO_MODE_MASK,
+				REG_FORCE_GPIO_EN, 0),
 	AIROHA_PINCTRL_PWM_EXT_SEC("gpio46", GPIO46_FLASH_MODE_CFG,
-				   SPI_MISO_GPIO_MODE_MASK),
+				   SPI_MISO_GPIO_MODE_MASK,
+				REG_FORCE_GPIO_EN, 0),
 	AIROHA_PINCTRL_PWM_EXT_SEC("gpio47", GPIO47_FLASH_MODE_CFG,
-				   UART_TXD_GPIO_MODE_MASK),
+				   UART_TXD_GPIO_MODE_MASK,
+				REG_FORCE_GPIO_EN, 0),
 	AIROHA_PINCTRL_PWM_EXT_SEC("gpio48", GPIO48_FLASH_MODE_CFG,
-				   UART_RXD_GPIO_MODE_MASK),
+				   UART_RXD_GPIO_MODE_MASK,
+				REG_FORCE_GPIO_EN, 0),
 	AIROHA_PINCTRL_PWM_EXT_SEC("gpio49", GPIO49_FLASH_MODE_CFG,
-				   GPIO_PCIE_RESET0_MASK),
+				   GPIO_PCIE_RESET0_MASK,
+				REG_FORCE_GPIO_EN, 0),
 	AIROHA_PINCTRL_PWM_EXT_SEC("gpio50", GPIO50_FLASH_MODE_CFG,
-				   GPIO_PCIE_RESET1_MASK),
+				   GPIO_PCIE_RESET1_MASK,
+				REG_FORCE_GPIO_EN, 0),
 	AIROHA_PINCTRL_PWM_EXT_SEC("gpio51", GPIO51_FLASH_MODE_CFG,
-				   MDC_0_GPIO_MODE_MASK),
+				   MDC_0_GPIO_MODE_MASK,
+				REG_FORCE_GPIO_EN, 0),
 };
 
 static const struct airoha_pinctrl_func_group phy1_led0_func_group[] = {
 	AIROHA_PINCTRL_PHY_LED0("gpio1", GPIO_LAN0_LED0_MODE_MASK,
-				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(0)),
+				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(0),
+				REG_FORCE_GPIO_EN, BIT(1)),
 	AIROHA_PINCTRL_PHY_LED0("gpio2", GPIO_LAN1_LED0_MODE_MASK,
-				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(0)),
+				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(0),
+				REG_FORCE_GPIO_EN, BIT(2)),
 	AIROHA_PINCTRL_PHY_LED0("gpio3", GPIO_LAN2_LED0_MODE_MASK,
-				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(0)),
+				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(0),
+				REG_FORCE_GPIO_EN, BIT(3)),
 	AIROHA_PINCTRL_PHY_LED0("gpio4", GPIO_LAN3_LED0_MODE_MASK,
-				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(0)),
+				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(0),
+				REG_FORCE_GPIO_EN, BIT(4)),
 };
 
 static const struct airoha_pinctrl_func_group phy2_led0_func_group[] = {
 	AIROHA_PINCTRL_PHY_LED0("gpio1", GPIO_LAN0_LED0_MODE_MASK,
-				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(1)),
+				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(1),
+				REG_FORCE_GPIO_EN, BIT(1)),
 	AIROHA_PINCTRL_PHY_LED0("gpio2", GPIO_LAN1_LED0_MODE_MASK,
-				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(1)),
+				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(1),
+				REG_FORCE_GPIO_EN, BIT(2)),
 	AIROHA_PINCTRL_PHY_LED0("gpio3", GPIO_LAN2_LED0_MODE_MASK,
-				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(1)),
+				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(1),
+				REG_FORCE_GPIO_EN, BIT(3)),
 	AIROHA_PINCTRL_PHY_LED0("gpio4", GPIO_LAN3_LED0_MODE_MASK,
-				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(1)),
+				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(1),
+				REG_FORCE_GPIO_EN, BIT(4)),
 };
 
 static const struct airoha_pinctrl_func_group phy3_led0_func_group[] = {
 	AIROHA_PINCTRL_PHY_LED0("gpio1", GPIO_LAN0_LED0_MODE_MASK,
-				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(2)),
+				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(2),
+				REG_FORCE_GPIO_EN, BIT(1)),
 	AIROHA_PINCTRL_PHY_LED0("gpio2", GPIO_LAN1_LED0_MODE_MASK,
-				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(2)),
+				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(2),
+				REG_FORCE_GPIO_EN, BIT(2)),
 	AIROHA_PINCTRL_PHY_LED0("gpio3", GPIO_LAN2_LED0_MODE_MASK,
-				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(2)),
+				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(2),
+				REG_FORCE_GPIO_EN, BIT(3)),
 	AIROHA_PINCTRL_PHY_LED0("gpio4", GPIO_LAN3_LED0_MODE_MASK,
-				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(2)),
+				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(2),
+				REG_FORCE_GPIO_EN, BIT(4)),
 };
 
 static const struct airoha_pinctrl_func_group phy4_led0_func_group[] = {
 	AIROHA_PINCTRL_PHY_LED0("gpio1", GPIO_LAN0_LED0_MODE_MASK,
-				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(3)),
+				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(3),
+				REG_FORCE_GPIO_EN, BIT(1)),
 	AIROHA_PINCTRL_PHY_LED0("gpio2", GPIO_LAN1_LED0_MODE_MASK,
-				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(3)),
+				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(3),
+				REG_FORCE_GPIO_EN, BIT(2)),
 	AIROHA_PINCTRL_PHY_LED0("gpio3", GPIO_LAN2_LED0_MODE_MASK,
-				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(3)),
+				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(3),
+				REG_FORCE_GPIO_EN, BIT(3)),
 	AIROHA_PINCTRL_PHY_LED0("gpio4", GPIO_LAN3_LED0_MODE_MASK,
-				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(3)),
+				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(3),
+				REG_FORCE_GPIO_EN, BIT(4)),
 };
 
 static const struct airoha_pinctrl_func_group phy1_led1_func_group[] = {
 	AIROHA_PINCTRL_PHY_LED1("gpio8", GPIO_LAN0_LED1_MODE_MASK,
-				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(0)),
+				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(0),
+				REG_FORCE_GPIO_EN, BIT(8)),
 	AIROHA_PINCTRL_PHY_LED1("gpio9", GPIO_LAN1_LED1_MODE_MASK,
-				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(0)),
+				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(0),
+				REG_FORCE_GPIO_EN, BIT(9)),
 	AIROHA_PINCTRL_PHY_LED1("gpio10", GPIO_LAN2_LED1_MODE_MASK,
-				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(0)),
+				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(0),
+				REG_FORCE_GPIO_EN, BIT(10)),
 	AIROHA_PINCTRL_PHY_LED1("gpio11", GPIO_LAN3_LED1_MODE_MASK,
-				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(0)),
+				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(0),
+				REG_FORCE_GPIO_EN, BIT(11)),
 };
 
 static const struct airoha_pinctrl_func_group phy2_led1_func_group[] = {
 	AIROHA_PINCTRL_PHY_LED1("gpio8", GPIO_LAN0_LED1_MODE_MASK,
-				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(1)),
+				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(1),
+				REG_FORCE_GPIO_EN, BIT(8)),
 	AIROHA_PINCTRL_PHY_LED1("gpio9", GPIO_LAN1_LED1_MODE_MASK,
-				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(1)),
+				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(1),
+				REG_FORCE_GPIO_EN, BIT(9)),
 	AIROHA_PINCTRL_PHY_LED1("gpio10", GPIO_LAN2_LED1_MODE_MASK,
-				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(1)),
+				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(1),
+				REG_FORCE_GPIO_EN, BIT(10)),
 	AIROHA_PINCTRL_PHY_LED1("gpio11", GPIO_LAN3_LED1_MODE_MASK,
-				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(1)),
+				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(1),
+				REG_FORCE_GPIO_EN, BIT(11)),
 };
 
 static const struct airoha_pinctrl_func_group phy3_led1_func_group[] = {
 	AIROHA_PINCTRL_PHY_LED1("gpio8", GPIO_LAN0_LED1_MODE_MASK,
-				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(2)),
+				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(2),
+				REG_FORCE_GPIO_EN, BIT(8)),
 	AIROHA_PINCTRL_PHY_LED1("gpio9", GPIO_LAN1_LED1_MODE_MASK,
-				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(2)),
+				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(2),
+				REG_FORCE_GPIO_EN, BIT(9)),
 	AIROHA_PINCTRL_PHY_LED1("gpio10", GPIO_LAN2_LED1_MODE_MASK,
-				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(2)),
+				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(2),
+				REG_FORCE_GPIO_EN, BIT(10)),
 	AIROHA_PINCTRL_PHY_LED1("gpio11", GPIO_LAN3_LED1_MODE_MASK,
-				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(2)),
+				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(2),
+				REG_FORCE_GPIO_EN, BIT(11)),
 };
 
 static const struct airoha_pinctrl_func_group phy4_led1_func_group[] = {
 	AIROHA_PINCTRL_PHY_LED1("gpio8", GPIO_LAN0_LED1_MODE_MASK,
-				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(3)),
+				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(3),
+				REG_FORCE_GPIO_EN, BIT(8)),
 	AIROHA_PINCTRL_PHY_LED1("gpio9", GPIO_LAN1_LED1_MODE_MASK,
-				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(3)),
+				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(3),
+				REG_FORCE_GPIO_EN, BIT(9)),
 	AIROHA_PINCTRL_PHY_LED1("gpio10", GPIO_LAN2_LED1_MODE_MASK,
-				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(3)),
+				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(3),
+				REG_FORCE_GPIO_EN, BIT(10)),
 	AIROHA_PINCTRL_PHY_LED1("gpio11", GPIO_LAN3_LED1_MODE_MASK,
-				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(3)),
+				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(3),
+				REG_FORCE_GPIO_EN, BIT(11)),
 };
 
 static const struct airoha_pinctrl_func pinctrl_funcs[] = {
@@ -1230,7 +1652,7 @@ static const struct airoha_pinctrl_func pinctrl_funcs[] = {
 	PINCTRL_FUNC_DESC("pcm_spi", pcm_spi),
 	PINCTRL_FUNC_DESC("emmc", emmc),
 	PINCTRL_FUNC_DESC("pnand", pnand),
-	PINCTRL_FUNC_DESC("gpio", gpio),
+	PINCTRL_GPIO_FUNC_DESC("gpio", gpio),
 	PINCTRL_FUNC_DESC("pcie_reset", pcie_reset),
 	PINCTRL_FUNC_DESC("pwm", pwm),
 	PINCTRL_FUNC_DESC("phy1_led0", phy1_led0),
@@ -1473,6 +1895,7 @@ static const struct airoha_pinctrl_conf pinctrl_pcie_rst_od_conf[] = {
 };
 
 static const struct airoha_pinctrl_match_data pinctrl_match_data = {
+	.check_mux_conflicts = true,
 	.chip_scu_compatible = "airoha,en7581-chip-scu",
 	.pinctrl_name = KBUILD_MODNAME,
 	.pinctrl_owner = THIS_MODULE,
-- 
2.43.0


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

* [PATCH 10/12] dt-bindings: pinctrl: airoha: describe all EN7523 GPIO mux groups
  2026-11-10  9:43 [PATCH 00/12] pinctrl: airoha: configure GPIO muxes explicitly and fix pad mappings Zhengping Zhang
                   ` (8 preceding siblings ...)
  2026-11-10  9:43 ` [PATCH 09/12] pinctrl: airoha: an7583: use force GPIO mode for GPIO requests Zhengping Zhang
@ 2026-11-10  9:43 ` Zhengping Zhang
  2026-11-10  9:43 ` [PATCH 11/12] pinctrl: airoha: en7523: use force GPIO mode for GPIO requests Zhengping Zhang
  2026-11-10  9:43 ` [PATCH 12/12] MAINTAINERS: add myself as Airoha pinctrl co-maintainer Zhengping Zhang
  11 siblings, 0 replies; 17+ messages in thread
From: Zhengping Zhang @ 2026-11-10  9:43 UTC (permalink / raw)
  To: linusw, lorenzo
  Cc: robh, krzk+dt, conor+dt, brgl, mikhail.kshevetskiy, naseefkm,
	benjamin.larsson, linux-gpio, devicetree, linux-kernel,
	linux-mediatek, lei.dong, ansuelsmth, Zhengping Zhang

Expand the GPIO mux groups from GPIO28-29 to GPIO0-29 to describe
explicit GPIO mode selection across the controller's GPIO range.
Allow multiple GPIO groups in a single mux state.

The corresponding driver support is added in a subsequent patch.

Signed-off-by: Zhengping Zhang <zhengping.zhang@airoha.com>
---
 .../bindings/pinctrl/airoha,en7523-pinctrl.yaml          | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/pinctrl/airoha,en7523-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/airoha,en7523-pinctrl.yaml
index 599f80e94432b..d93cf3a3532a2 100644
--- a/Documentation/devicetree/bindings/pinctrl/airoha,en7523-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/airoha,en7523-pinctrl.yaml
@@ -178,7 +178,14 @@ patternProperties:
             then:
               properties:
                 groups:
-                  enum: [gpio28, gpio29]
+                  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]
+                  minItems: 1
+                  maxItems: 30
           - if:
               properties:
                 function:
-- 
2.43.0


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

* [PATCH 11/12] pinctrl: airoha: en7523: use force GPIO mode for GPIO requests
  2026-11-10  9:43 [PATCH 00/12] pinctrl: airoha: configure GPIO muxes explicitly and fix pad mappings Zhengping Zhang
                   ` (9 preceding siblings ...)
  2026-11-10  9:43 ` [PATCH 10/12] dt-bindings: pinctrl: airoha: describe all EN7523 GPIO mux groups Zhengping Zhang
@ 2026-11-10  9:43 ` Zhengping Zhang
  2026-11-10  9:43 ` [PATCH 12/12] MAINTAINERS: add myself as Airoha pinctrl co-maintainer Zhengping Zhang
  11 siblings, 0 replies; 17+ messages in thread
From: Zhengping Zhang @ 2026-11-10  9:43 UTC (permalink / raw)
  To: linusw, lorenzo
  Cc: robh, krzk+dt, conor+dt, brgl, mikhail.kshevetskiy, naseefkm,
	benjamin.larsson, linux-gpio, devicetree, linux-kernel,
	linux-mediatek, lei.dong, ansuelsmth, Zhengping Zhang

GPIO requests can leave pads controlled by alternate functions selected
by the bootloader. Extend the GPIO mux groups to GPIO0-29 and enable
the shared GPIO request handling and mux conflict checks. GPIO consumers
and explicit GPIO pinctrl states then use the same configuration tables.

Use per-pad force GPIO overrides without disabling shared peripheral
modes on other pads. Select GPIO mode using the following SCU register
bits, where n is the GPIO number:

  - GPIO0-29: set bit n in register 0x224
    (GPIO0 -> bit 0, ..., GPIO29 -> bit 29).
  - GPIO28: also set the PCIe reset0 GPIO selector at register
    0x218, bit 9.
  - GPIO29: also set the PCIe reset1 GPIO selector at register
    0x218, bit 10.

Unlike AN7581 and AN7583, EN7523 provides a force GPIO bit for GPIO0.
Clear the requested pad's PWM selection when selecting GPIO.

When selecting a peripheral function, clear the corresponding force
GPIO overrides so an earlier GPIO configuration does not prevent
peripheral operation. Enable the overrides when selecting PWM output.

Exclude the software-controlled TX_DIS/RX_DIS pads (GPIO16/21) from the
hardware PON mux group. These signals serve the PON interface but are
intended to be requested as GPIOs by the PON PHY driver and controlled
through the GPIO API rather than driven by the PON hardware. This
avoids ownership conflicts between PON mux selection and GPIO requests.

Correct the 128-pin PCM SPI CS2 group to use GPIO29 (pinctrl pin 41)
instead of GPIO27. The share-pin table assigns GPIO29 to CS2 in the
128-pin package and GPIO27 to CS2 in the 156-pin package. Keep the
156-pin group unchanged, and clear GPIO29's PCIe GPIO selector when
selecting its PCM SPI CS2 function.

Signed-off-by: Zhengping Zhang <zhengping.zhang@airoha.com>
---
 drivers/pinctrl/airoha/pinctrl-en7523.c | 579 +++++++++++++++++++-----
 1 file changed, 473 insertions(+), 106 deletions(-)

diff --git a/drivers/pinctrl/airoha/pinctrl-en7523.c b/drivers/pinctrl/airoha/pinctrl-en7523.c
index b0c5e60f0aeb9..041536790fd8b 100644
--- a/drivers/pinctrl/airoha/pinctrl-en7523.c
+++ b/drivers/pinctrl/airoha/pinctrl-en7523.c
@@ -211,7 +211,7 @@
 	}
 
 /* PWM */
-#define AIROHA_PINCTRL_PWM(gpio, mux_val)			\
+#define AIROHA_PINCTRL_PWM(gpio, mux_val, force_reg, force_mask) \
 	{							\
 		.name = (gpio),					\
 		.regmap[0] = {					\
@@ -220,10 +220,14 @@
 			(mux_val),				\
 			(mux_val)				\
 		},						\
-		.regmap_size = 1,				\
+		.regmap[1] = {					\
+			AIROHA_FUNC_MUX, (force_reg),		\
+			(force_mask), (force_mask)			\
+		},						\
+		.regmap_size = 2,				\
 	}
 
-#define AIROHA_PINCTRL_PWM_EXT(gpio, mux_val)			\
+#define AIROHA_PINCTRL_PWM_EXT(gpio, mux_val, force_reg, force_mask) \
 	{							\
 		.name = (gpio),					\
 		.regmap[0] = {					\
@@ -232,10 +236,14 @@
 			(mux_val),				\
 			(mux_val)				\
 		},						\
-		.regmap_size = 1,				\
+		.regmap[1] = {					\
+			AIROHA_FUNC_MUX, (force_reg),		\
+			(force_mask), (force_mask)			\
+		},						\
+		.regmap_size = 2,				\
 	}
 
-#define AIROHA_PINCTRL_PWM_EXT_SEC(gpio, mux_val, smux_val)	\
+#define AIROHA_PINCTRL_PWM_EXT_SEC(gpio, mux_val, smux_val, force_reg, force_mask) \
 	{							\
 		.name = (gpio),					\
 		.regmap[0] = {					\
@@ -250,10 +258,14 @@
 			(smux_val),				\
 			(smux_val)				\
 		},						\
-		.regmap_size = 2,				\
+		.regmap[2] = {					\
+			AIROHA_FUNC_MUX, (force_reg),		\
+			(force_mask), (force_mask)			\
+		},						\
+		.regmap_size = 3,				\
 	}
 
-#define AIROHA_PINCTRL_PHY_LED0(gpio, mux_val, map_mask, map_val)	\
+#define AIROHA_PINCTRL_PHY_LED0(gpio, mux_val, map_mask, map_val, force_reg, force_mask) \
 	{								\
 		.name = (gpio),						\
 		.regmap[0] = {						\
@@ -268,10 +280,14 @@
 			(map_mask),					\
 			(map_val),					\
 		},							\
-		.regmap_size = 2,					\
+		.regmap[2] = {					\
+			AIROHA_FUNC_MUX, (force_reg),		\
+			(force_mask), 0			\
+		},						\
+		.regmap_size = 3,					\
 	}
 
-#define AIROHA_PINCTRL_PHY_LED1(gpio, mux_val, map_mask, map_val)	\
+#define AIROHA_PINCTRL_PHY_LED1(gpio, mux_val, map_mask, map_val, force_reg, force_mask) \
 	{								\
 		.name = (gpio),						\
 		.regmap[0] = {						\
@@ -286,7 +302,11 @@
 			(map_mask),					\
 			(map_val),					\
 		},							\
-		.regmap_size = 2,					\
+		.regmap[2] = {					\
+			AIROHA_FUNC_MUX, (force_reg),		\
+			(force_mask), 0			\
+		},						\
+		.regmap_size = 3,					\
 	}
 
 static struct pinctrl_pin_desc pinctrl_pins[] = {
@@ -330,7 +350,8 @@ static struct pinctrl_pin_desc pinctrl_pins[] = {
 	PINCTRL_PIN(41, "pcie_reset1"),
 };
 
-static const int pon_pins[] = { 28, 29, 30, 31, 32, 33 };
+/* TX_DIS (GPIO16) and RX_DIS (GPIO21) are software GPIOs. */
+static const int pon_pins[] = { 29, 30, 31, 32 };
 static const int pon_tod_1pps_pins[] = { 21 };
 static const int gsw_tod_1pps_pins[] = { 21 };
 static const int sipo_pins[] = { 13, 38 };
@@ -352,7 +373,7 @@ static const int pcm_spi_pins[] = { 16, 17, 18, 19, 24, 25, 26, 27 };
 static const int pcm_spi_int_pins[] = { 15 };
 static const int pcm_spi_rst_pins[] = { 14 };
 static const int pcm_spi_cs1_pins[] = { 22 };
-static const int pcm_spi_cs2_p128_pins[] = { 39 };
+static const int pcm_spi_cs2_p128_pins[] = { 41 };
 static const int pcm_spi_cs2_p156_pins[] = { 39 };
 static const int pcm_spi_cs3_pins[] = { 20 };
 static const int pcm_spi_cs4_pins[] = { 23 };
@@ -466,7 +487,13 @@ static const char *const pcm_spi_groups[] = {
 	"pcm_spi_cs2_p156", "pcm_spi_cs2_p128", "pcm_spi_cs3", "pcm_spi_cs4"
 };
 static const char *const i2s_groups[] = { "i2s" };
-static const char *const gpio_groups[] = { "gpio28", "gpio29" };
+static const char *const gpio_groups[] = {
+	"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",
+};
 static const char *const pcie_reset_groups[] = {
 	"pcie_reset0", "pcie_reset1"
 };
@@ -511,7 +538,16 @@ static const struct airoha_pinctrl_func_group pon_func_group[] = {
 			GPIO_PON_MODE_MASK,
 			GPIO_PON_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(17) |
+			BIT(18) |
+			BIT(19) |
+			BIT(20),
+			0
+		},
+		.regmap_size = 2,
 	},
 };
 
@@ -524,7 +560,13 @@ static const struct airoha_pinctrl_func_group tod_1pps_func_group[] = {
 			PON_TOD_1PPS_MODE_MASK,
 			PON_TOD_1PPS_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(9),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "gsw_tod_1pps",
 		.regmap[0] = {
@@ -533,7 +575,13 @@ static const struct airoha_pinctrl_func_group tod_1pps_func_group[] = {
 			GSW_TOD_1PPS_MODE_MASK,
 			GSW_TOD_1PPS_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(9),
+			0
+		},
+		.regmap_size = 2,
 	},
 };
 
@@ -546,7 +594,14 @@ static const struct airoha_pinctrl_func_group sipo_func_group[] = {
 			GPIO_SIPO_MODE_MASK | SIPO_RCLK_MODE_MASK,
 			GPIO_SIPO_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(1) |
+			BIT(26),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "sipo_rclk",
 		.regmap[0] = {
@@ -555,7 +610,15 @@ static const struct airoha_pinctrl_func_group sipo_func_group[] = {
 			GPIO_SIPO_MODE_MASK | SIPO_RCLK_MODE_MASK,
 			GPIO_SIPO_MODE_MASK | SIPO_RCLK_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(1) |
+			BIT(18) |
+			BIT(26),
+			0
+		},
+		.regmap_size = 2,
 	},
 };
 
@@ -568,7 +631,14 @@ static const struct airoha_pinctrl_func_group mdio_func_group[] = {
 			GPIO_SGMII_MDIO_MODE_MASK,
 			GPIO_SGMII_MDIO_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(8) |
+			BIT(9),
+			0
+		},
+		.regmap_size = 2,
 	},
 };
 
@@ -581,7 +651,14 @@ static const struct airoha_pinctrl_func_group uart_func_group[] = {
 			GPIO_UART2_MODE_MASK,
 			GPIO_UART2_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(8) |
+			BIT(9),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "npu_uart",
 		.regmap[0] = {
@@ -590,7 +667,14 @@ static const struct airoha_pinctrl_func_group uart_func_group[] = {
 			NPU_UART_EN_MASK,
 			NPU_UART_EN_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(1) |
+			BIT(26),
+			0
+		},
+		.regmap_size = 2,
 	}
 };
 
@@ -603,7 +687,14 @@ static const struct airoha_pinctrl_func_group i2c_func_group[] = {
 			GPIO_2ND_I2C_MODE_MASK,
 			GPIO_2ND_I2C_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(2) |
+			BIT(3),
+			0
+		},
+		.regmap_size = 2,
 	},
 };
 
@@ -616,7 +707,17 @@ static const struct airoha_pinctrl_func_group jtag_func_group[] = {
 			JTAG_UDI_EN_MASK,
 			JTAG_UDI_EN_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(22) |
+			BIT(23) |
+			BIT(24) |
+			BIT(25) |
+			BIT(26),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "jtag_dfd",
 		.regmap[0] = {
@@ -625,7 +726,17 @@ static const struct airoha_pinctrl_func_group jtag_func_group[] = {
 			JTAG_DFD_EN_MASK,
 			JTAG_DFD_EN_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(22) |
+			BIT(23) |
+			BIT(24) |
+			BIT(25) |
+			BIT(26),
+			0
+		},
+		.regmap_size = 2,
 	},
 };
 
@@ -638,7 +749,16 @@ static const struct airoha_pinctrl_func_group pcm_func_group[] = {
 			GPIO_PCM1_MODE_MASK,
 			GPIO_PCM1_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(12) |
+			BIT(13) |
+			BIT(14) |
+			BIT(15),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "pcm2",
 		.regmap[0] = {
@@ -647,7 +767,16 @@ static const struct airoha_pinctrl_func_group pcm_func_group[] = {
 			GPIO_PCM2_MODE_MASK,
 			GPIO_PCM2_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(4) |
+			BIT(5) |
+			BIT(6) |
+			BIT(7),
+			0
+		},
+		.regmap_size = 2,
 	},
 };
 
@@ -660,7 +789,14 @@ static const struct airoha_pinctrl_func_group spi_func_group[] = {
 			GPIO_SPI_QUAD_MODE_MASK,
 			GPIO_SPI_QUAD_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(2) |
+			BIT(3),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "spi_cs1",
 		.regmap[0] = {
@@ -669,7 +805,13 @@ static const struct airoha_pinctrl_func_group spi_func_group[] = {
 			GPIO_SPI_CS1_MODE_MASK,
 			GPIO_SPI_CS1_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(9),
+			0
+		},
+		.regmap_size = 2,
 	},
 };
 
@@ -682,7 +824,20 @@ static const struct airoha_pinctrl_func_group pcm_spi_func_group[] = {
 			GPIO_PCM_SPI_MODE_MASK,
 			GPIO_PCM_SPI_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(4) |
+			BIT(5) |
+			BIT(6) |
+			BIT(7) |
+			BIT(12) |
+			BIT(13) |
+			BIT(14) |
+			BIT(15),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "pcm_spi_int",
 		.regmap[0] = {
@@ -691,7 +846,13 @@ static const struct airoha_pinctrl_func_group pcm_spi_func_group[] = {
 			GPIO_PCM_INT_MODE_MASK,
 			GPIO_PCM_INT_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(3),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "pcm_spi_rst",
 		.regmap[0] = {
@@ -700,7 +861,13 @@ static const struct airoha_pinctrl_func_group pcm_spi_func_group[] = {
 			GPIO_PCM_RESET_MODE_MASK,
 			GPIO_PCM_RESET_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(2),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "pcm_spi_cs1",
 		.regmap[0] = {
@@ -709,7 +876,13 @@ static const struct airoha_pinctrl_func_group pcm_spi_func_group[] = {
 			GPIO_PCM_SPI_CS1_MODE_MASK,
 			GPIO_PCM_SPI_CS1_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(10),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "pcm_spi_cs2_p128",
 		.regmap[0] = {
@@ -718,7 +891,19 @@ static const struct airoha_pinctrl_func_group pcm_spi_func_group[] = {
 			GPIO_PCM_SPI_CS2_MODE_P128_MASK,
 			GPIO_PCM_SPI_CS2_MODE_P128_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(29),
+			0
+		},
+		.regmap[2] = {
+			AIROHA_FUNC_MUX,
+			REG_GPIO_PON_MODE,
+			GPIO_PCIE_RESET1_MASK,
+			0
+		},
+		.regmap_size = 3,
 	}, {
 		.name = "pcm_spi_cs2_p156",
 		.regmap[0] = {
@@ -727,7 +912,13 @@ static const struct airoha_pinctrl_func_group pcm_spi_func_group[] = {
 			GPIO_PCM_SPI_CS2_MODE_P156_MASK,
 			GPIO_PCM_SPI_CS2_MODE_P156_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(27),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "pcm_spi_cs3",
 		.regmap[0] = {
@@ -736,7 +927,13 @@ static const struct airoha_pinctrl_func_group pcm_spi_func_group[] = {
 			GPIO_PCM_SPI_CS3_MODE_MASK,
 			GPIO_PCM_SPI_CS3_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(8),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "pcm_spi_cs4",
 		.regmap[0] = {
@@ -745,7 +942,13 @@ static const struct airoha_pinctrl_func_group pcm_spi_func_group[] = {
 			GPIO_PCM_SPI_CS4_MODE_MASK,
 			GPIO_PCM_SPI_CS4_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(11),
+			0
+		},
+		.regmap_size = 2,
 	},
 };
 
@@ -758,15 +961,104 @@ static const struct airoha_pinctrl_func_group i2s_func_group[] = {
 			GPIO_I2S_MODE_MASK,
 			GPIO_I2S_MODE_MASK
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(4) |
+			BIT(5) |
+			BIT(6) |
+			BIT(7),
+			0
+		},
+		.regmap_size = 2,
 	},
 };
 
+/* Force overrides select individual pads without disabling shared buses. */
+#define EN7523_GPIO_GROUP(n, pwm_mask, force_reg, force_mask)	\
+	{								\
+		.name = "gpio" #n,					\
+		.regmap[0] = {						\
+			AIROHA_FUNC_PWM_MUX,				\
+			(n) < 16 ? REG_GPIO_FLASH_MODE_CFG :		\
+			REG_GPIO_FLASH_MODE_CFG_EXT,			\
+			(pwm_mask), 0					\
+		},							\
+		.regmap[1] = {						\
+			AIROHA_FUNC_MUX, (force_reg),			\
+			(force_mask), (force_mask)			\
+		},							\
+		.regmap[2] = {						\
+			AIROHA_FUNC_MUX, REG_GPIO_PON_MODE,		\
+			(n) == 28 ? GPIO_PCIE_RESET0_MASK :		\
+			(n) == 29 ? GPIO_PCIE_RESET1_MASK : 0,		\
+			(n) == 28 ? GPIO_PCIE_RESET0_MASK :		\
+			(n) == 29 ? GPIO_PCIE_RESET1_MASK : 0		\
+		},							\
+		.regmap_size = 3,					\
+	}
+
 static const struct airoha_pinctrl_func_group gpio_func_group[] = {
-	AIROHA_PINCTRL_GPIO_EXT("gpio28", GPIO28_FLASH_MODE_CFG,
-				GPIO_PCIE_RESET0_MASK),
-	AIROHA_PINCTRL_GPIO_EXT("gpio29", GPIO29_FLASH_MODE_CFG,
-				GPIO_PCIE_RESET1_MASK),
+	EN7523_GPIO_GROUP(0, GPIO0_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(0)),
+	EN7523_GPIO_GROUP(1, GPIO1_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(1)),
+	EN7523_GPIO_GROUP(2, GPIO2_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(2)),
+	EN7523_GPIO_GROUP(3, GPIO3_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(3)),
+	EN7523_GPIO_GROUP(4, GPIO4_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(4)),
+	EN7523_GPIO_GROUP(5, GPIO5_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(5)),
+	EN7523_GPIO_GROUP(6, GPIO6_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(6)),
+	EN7523_GPIO_GROUP(7, GPIO7_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(7)),
+	EN7523_GPIO_GROUP(8, GPIO8_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(8)),
+	EN7523_GPIO_GROUP(9, GPIO9_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(9)),
+	EN7523_GPIO_GROUP(10, GPIO10_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(10)),
+	EN7523_GPIO_GROUP(11, GPIO11_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(11)),
+	EN7523_GPIO_GROUP(12, GPIO12_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(12)),
+	EN7523_GPIO_GROUP(13, GPIO13_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(13)),
+	EN7523_GPIO_GROUP(14, GPIO14_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(14)),
+	EN7523_GPIO_GROUP(15, GPIO15_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(15)),
+	EN7523_GPIO_GROUP(16, GPIO16_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(16)),
+	EN7523_GPIO_GROUP(17, GPIO17_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(17)),
+	EN7523_GPIO_GROUP(18, GPIO18_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(18)),
+	EN7523_GPIO_GROUP(19, GPIO19_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(19)),
+	EN7523_GPIO_GROUP(20, GPIO20_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(20)),
+	EN7523_GPIO_GROUP(21, GPIO21_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(21)),
+	EN7523_GPIO_GROUP(22, GPIO22_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(22)),
+	EN7523_GPIO_GROUP(23, GPIO23_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(23)),
+	EN7523_GPIO_GROUP(24, GPIO24_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(24)),
+	EN7523_GPIO_GROUP(25, GPIO25_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(25)),
+	EN7523_GPIO_GROUP(26, GPIO26_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(26)),
+	EN7523_GPIO_GROUP(27, GPIO27_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(27)),
+	EN7523_GPIO_GROUP(28, GPIO28_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(28)),
+	EN7523_GPIO_GROUP(29, GPIO29_FLASH_MODE_CFG,
+			    REG_FORCE_GPIO_EN, BIT(29)),
 };
 
 static const struct airoha_pinctrl_func_group pcie_reset_func_group[] = {
@@ -778,7 +1070,13 @@ static const struct airoha_pinctrl_func_group pcie_reset_func_group[] = {
 			GPIO_PCIE_RESET0_MASK,
 			0
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(28),
+			0
+		},
+		.regmap_size = 2,
 	}, {
 		.name = "pcie_reset1",
 		.regmap[0] = {
@@ -787,131 +1085,199 @@ static const struct airoha_pinctrl_func_group pcie_reset_func_group[] = {
 			GPIO_PCIE_RESET1_MASK,
 			0
 		},
-		.regmap_size = 1,
+		.regmap[1] = {
+			AIROHA_FUNC_MUX,
+			REG_FORCE_GPIO_EN,
+			BIT(29),
+			0
+		},
+		.regmap_size = 2,
 	},
 };
 
 static const struct airoha_pinctrl_func_group pwm_func_group[] = {
-	AIROHA_PINCTRL_PWM("gpio0", GPIO0_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM("gpio1", GPIO1_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM("gpio2", GPIO2_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM("gpio3", GPIO3_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM("gpio4", GPIO4_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM("gpio5", GPIO5_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM("gpio6", GPIO6_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM("gpio7", GPIO7_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM("gpio8", GPIO8_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM("gpio9", GPIO9_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM("gpio10", GPIO10_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM("gpio11", GPIO11_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM("gpio12", GPIO12_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM("gpio13", GPIO13_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM("gpio14", GPIO14_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM("gpio15", GPIO15_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM_EXT("gpio16", GPIO16_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM_EXT("gpio17", GPIO17_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM_EXT("gpio18", GPIO18_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM_EXT("gpio19", GPIO19_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM_EXT("gpio20", GPIO20_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM_EXT("gpio21", GPIO21_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM_EXT("gpio22", GPIO22_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM_EXT("gpio23", GPIO23_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM_EXT("gpio24", GPIO24_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM_EXT("gpio25", GPIO25_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM_EXT("gpio26", GPIO26_FLASH_MODE_CFG),
-	AIROHA_PINCTRL_PWM_EXT("gpio27", GPIO27_FLASH_MODE_CFG),
+	AIROHA_PINCTRL_PWM("gpio0", GPIO0_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(0)),
+	AIROHA_PINCTRL_PWM("gpio1", GPIO1_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(1)),
+	AIROHA_PINCTRL_PWM("gpio2", GPIO2_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(2)),
+	AIROHA_PINCTRL_PWM("gpio3", GPIO3_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(3)),
+	AIROHA_PINCTRL_PWM("gpio4", GPIO4_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(4)),
+	AIROHA_PINCTRL_PWM("gpio5", GPIO5_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(5)),
+	AIROHA_PINCTRL_PWM("gpio6", GPIO6_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(6)),
+	AIROHA_PINCTRL_PWM("gpio7", GPIO7_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(7)),
+	AIROHA_PINCTRL_PWM("gpio8", GPIO8_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(8)),
+	AIROHA_PINCTRL_PWM("gpio9", GPIO9_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(9)),
+	AIROHA_PINCTRL_PWM("gpio10", GPIO10_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(10)),
+	AIROHA_PINCTRL_PWM("gpio11", GPIO11_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(11)),
+	AIROHA_PINCTRL_PWM("gpio12", GPIO12_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(12)),
+	AIROHA_PINCTRL_PWM("gpio13", GPIO13_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(13)),
+	AIROHA_PINCTRL_PWM("gpio14", GPIO14_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(14)),
+	AIROHA_PINCTRL_PWM("gpio15", GPIO15_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(15)),
+	AIROHA_PINCTRL_PWM_EXT("gpio16", GPIO16_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(16)),
+	AIROHA_PINCTRL_PWM_EXT("gpio17", GPIO17_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(17)),
+	AIROHA_PINCTRL_PWM_EXT("gpio18", GPIO18_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(18)),
+	AIROHA_PINCTRL_PWM_EXT("gpio19", GPIO19_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(19)),
+	AIROHA_PINCTRL_PWM_EXT("gpio20", GPIO20_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(20)),
+	AIROHA_PINCTRL_PWM_EXT("gpio21", GPIO21_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(21)),
+	AIROHA_PINCTRL_PWM_EXT("gpio22", GPIO22_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(22)),
+	AIROHA_PINCTRL_PWM_EXT("gpio23", GPIO23_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(23)),
+	AIROHA_PINCTRL_PWM_EXT("gpio24", GPIO24_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(24)),
+	AIROHA_PINCTRL_PWM_EXT("gpio25", GPIO25_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(25)),
+	AIROHA_PINCTRL_PWM_EXT("gpio26", GPIO26_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(26)),
+	AIROHA_PINCTRL_PWM_EXT("gpio27", GPIO27_FLASH_MODE_CFG,
+				REG_FORCE_GPIO_EN, BIT(27)),
 	AIROHA_PINCTRL_PWM_EXT_SEC("gpio28", GPIO28_FLASH_MODE_CFG,
-				   GPIO_PCIE_RESET0_MASK),
+				   GPIO_PCIE_RESET0_MASK,
+				REG_FORCE_GPIO_EN, BIT(28)),
 	AIROHA_PINCTRL_PWM_EXT_SEC("gpio29", GPIO29_FLASH_MODE_CFG,
-				   GPIO_PCIE_RESET1_MASK),
+				   GPIO_PCIE_RESET1_MASK,
+				REG_FORCE_GPIO_EN, BIT(29)),
 };
 
 static const struct airoha_pinctrl_func_group phy1_led0_func_group[] = {
 	AIROHA_PINCTRL_PHY_LED0("gpio22", GPIO_LAN0_LED0_MODE_MASK,
-				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(0)),
+				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(0),
+				REG_FORCE_GPIO_EN, BIT(22)),
 	AIROHA_PINCTRL_PHY_LED0("gpio23", GPIO_LAN1_LED0_MODE_MASK,
-				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(0)),
+				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(0),
+				REG_FORCE_GPIO_EN, BIT(23)),
 	AIROHA_PINCTRL_PHY_LED0("gpio24", GPIO_LAN2_LED0_MODE_MASK,
-				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(0)),
+				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(0),
+				REG_FORCE_GPIO_EN, BIT(24)),
 	AIROHA_PINCTRL_PHY_LED0("gpio25", GPIO_LAN3_LED0_MODE_MASK,
-				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(0)),
+				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(0),
+				REG_FORCE_GPIO_EN, BIT(25)),
 };
 
 static const struct airoha_pinctrl_func_group phy2_led0_func_group[] = {
 	AIROHA_PINCTRL_PHY_LED0("gpio22", GPIO_LAN0_LED0_MODE_MASK,
-				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(1)),
+				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(1),
+				REG_FORCE_GPIO_EN, BIT(22)),
 	AIROHA_PINCTRL_PHY_LED0("gpio23", GPIO_LAN1_LED0_MODE_MASK,
-				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(1)),
+				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(1),
+				REG_FORCE_GPIO_EN, BIT(23)),
 	AIROHA_PINCTRL_PHY_LED0("gpio24", GPIO_LAN2_LED0_MODE_MASK,
-				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(1)),
+				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(1),
+				REG_FORCE_GPIO_EN, BIT(24)),
 	AIROHA_PINCTRL_PHY_LED0("gpio25", GPIO_LAN3_LED0_MODE_MASK,
-				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(1)),
+				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(1),
+				REG_FORCE_GPIO_EN, BIT(25)),
 };
 
 static const struct airoha_pinctrl_func_group phy3_led0_func_group[] = {
 	AIROHA_PINCTRL_PHY_LED0("gpio22", GPIO_LAN0_LED0_MODE_MASK,
-				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(2)),
+				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(2),
+				REG_FORCE_GPIO_EN, BIT(22)),
 	AIROHA_PINCTRL_PHY_LED0("gpio23", GPIO_LAN1_LED0_MODE_MASK,
-				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(2)),
+				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(2),
+				REG_FORCE_GPIO_EN, BIT(23)),
 	AIROHA_PINCTRL_PHY_LED0("gpio24", GPIO_LAN2_LED0_MODE_MASK,
-				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(2)),
+				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(2),
+				REG_FORCE_GPIO_EN, BIT(24)),
 	AIROHA_PINCTRL_PHY_LED0("gpio25", GPIO_LAN3_LED0_MODE_MASK,
-				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(2)),
+				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(2),
+				REG_FORCE_GPIO_EN, BIT(25)),
 };
 
 static const struct airoha_pinctrl_func_group phy4_led0_func_group[] = {
 	AIROHA_PINCTRL_PHY_LED0("gpio22", GPIO_LAN0_LED0_MODE_MASK,
-				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(3)),
+				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(3),
+				REG_FORCE_GPIO_EN, BIT(22)),
 	AIROHA_PINCTRL_PHY_LED0("gpio23", GPIO_LAN1_LED0_MODE_MASK,
-				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(3)),
+				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(3),
+				REG_FORCE_GPIO_EN, BIT(23)),
 	AIROHA_PINCTRL_PHY_LED0("gpio24", GPIO_LAN2_LED0_MODE_MASK,
-				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(3)),
+				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(3),
+				REG_FORCE_GPIO_EN, BIT(24)),
 	AIROHA_PINCTRL_PHY_LED0("gpio25", GPIO_LAN3_LED0_MODE_MASK,
-				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(3)),
+				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(3),
+				REG_FORCE_GPIO_EN, BIT(25)),
 };
 
 static const struct airoha_pinctrl_func_group phy1_led1_func_group[] = {
 	AIROHA_PINCTRL_PHY_LED1("gpio7", GPIO_LAN0_LED1_MODE_MASK,
-				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(0)),
+				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(0),
+				REG_FORCE_GPIO_EN, BIT(7)),
 	AIROHA_PINCTRL_PHY_LED1("gpio6", GPIO_LAN1_LED1_MODE_MASK,
-				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(0)),
+				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(0),
+				REG_FORCE_GPIO_EN, BIT(6)),
 	AIROHA_PINCTRL_PHY_LED1("gpio5", GPIO_LAN2_LED1_MODE_MASK,
-				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(0)),
+				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(0),
+				REG_FORCE_GPIO_EN, BIT(5)),
 	AIROHA_PINCTRL_PHY_LED1("gpio4", GPIO_LAN3_LED1_MODE_MASK,
-				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(0)),
+				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(0),
+				REG_FORCE_GPIO_EN, BIT(4)),
 };
 
 static const struct airoha_pinctrl_func_group phy2_led1_func_group[] = {
 	AIROHA_PINCTRL_PHY_LED1("gpio7", GPIO_LAN0_LED1_MODE_MASK,
-				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(1)),
+				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(1),
+				REG_FORCE_GPIO_EN, BIT(7)),
 	AIROHA_PINCTRL_PHY_LED1("gpio6", GPIO_LAN1_LED1_MODE_MASK,
-				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(1)),
+				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(1),
+				REG_FORCE_GPIO_EN, BIT(6)),
 	AIROHA_PINCTRL_PHY_LED1("gpio5", GPIO_LAN2_LED1_MODE_MASK,
-				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(1)),
+				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(1),
+				REG_FORCE_GPIO_EN, BIT(5)),
 	AIROHA_PINCTRL_PHY_LED1("gpio4", GPIO_LAN3_LED1_MODE_MASK,
-				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(1)),
+				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(1),
+				REG_FORCE_GPIO_EN, BIT(4)),
 };
 
 static const struct airoha_pinctrl_func_group phy3_led1_func_group[] = {
 	AIROHA_PINCTRL_PHY_LED1("gpio7", GPIO_LAN0_LED1_MODE_MASK,
-				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(2)),
+				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(2),
+				REG_FORCE_GPIO_EN, BIT(7)),
 	AIROHA_PINCTRL_PHY_LED1("gpio6", GPIO_LAN1_LED1_MODE_MASK,
-				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(2)),
+				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(2),
+				REG_FORCE_GPIO_EN, BIT(6)),
 	AIROHA_PINCTRL_PHY_LED1("gpio5", GPIO_LAN2_LED1_MODE_MASK,
-				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(2)),
+				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(2),
+				REG_FORCE_GPIO_EN, BIT(5)),
 	AIROHA_PINCTRL_PHY_LED1("gpio4", GPIO_LAN3_LED1_MODE_MASK,
-				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(2)),
+				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(2),
+				REG_FORCE_GPIO_EN, BIT(4)),
 };
 
 static const struct airoha_pinctrl_func_group phy4_led1_func_group[] = {
 	AIROHA_PINCTRL_PHY_LED1("gpio7", GPIO_LAN0_LED1_MODE_MASK,
-				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(3)),
+				LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(3),
+				REG_FORCE_GPIO_EN, BIT(7)),
 	AIROHA_PINCTRL_PHY_LED1("gpio6", GPIO_LAN1_LED1_MODE_MASK,
-				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(3)),
+				LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(3),
+				REG_FORCE_GPIO_EN, BIT(6)),
 	AIROHA_PINCTRL_PHY_LED1("gpio5", GPIO_LAN2_LED1_MODE_MASK,
-				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(3)),
+				LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(3),
+				REG_FORCE_GPIO_EN, BIT(5)),
 	AIROHA_PINCTRL_PHY_LED1("gpio4", GPIO_LAN3_LED1_MODE_MASK,
-				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(3)),
+				LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(3),
+				REG_FORCE_GPIO_EN, BIT(4)),
 };
 
 static const struct airoha_pinctrl_func pinctrl_funcs[] = {
@@ -926,7 +1292,7 @@ static const struct airoha_pinctrl_func pinctrl_funcs[] = {
 	PINCTRL_FUNC_DESC("spi", spi),
 	PINCTRL_FUNC_DESC("pcm_spi", pcm_spi),
 	PINCTRL_FUNC_DESC("i2s", i2s),
-	PINCTRL_FUNC_DESC("gpio", gpio),
+	PINCTRL_GPIO_FUNC_DESC("gpio", gpio),
 	PINCTRL_FUNC_DESC("pcie_reset", pcie_reset),
 	PINCTRL_FUNC_DESC("pwm", pwm),
 	PINCTRL_FUNC_DESC("phy1_led0", phy1_led0),
@@ -1104,6 +1470,7 @@ static const struct airoha_pinctrl_conf pinctrl_drive_e4_conf[] = {
 };
 
 static const struct airoha_pinctrl_match_data pinctrl_match_data = {
+	.check_mux_conflicts = true,
 	.chip_scu_compatible = "airoha,en7523-chip-scu",
 	.pinctrl_name = KBUILD_MODNAME,
 	.pinctrl_owner = THIS_MODULE,
-- 
2.43.0


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

* [PATCH 12/12] MAINTAINERS: add myself as Airoha pinctrl co-maintainer
  2026-11-10  9:43 [PATCH 00/12] pinctrl: airoha: configure GPIO muxes explicitly and fix pad mappings Zhengping Zhang
                   ` (10 preceding siblings ...)
  2026-11-10  9:43 ` [PATCH 11/12] pinctrl: airoha: en7523: use force GPIO mode for GPIO requests Zhengping Zhang
@ 2026-11-10  9:43 ` Zhengping Zhang
  11 siblings, 0 replies; 17+ messages in thread
From: Zhengping Zhang @ 2026-11-10  9:43 UTC (permalink / raw)
  To: linusw, lorenzo
  Cc: robh, krzk+dt, conor+dt, brgl, mikhail.kshevetskiy, naseefkm,
	benjamin.larsson, linux-gpio, devicetree, linux-kernel,
	linux-mediatek, lei.dong, ansuelsmth, Zhengping Zhang

Add myself as a co-maintainer of the Airoha pinctrl drivers alongside
Lorenzo, providing support from Airoha for patch review,
hardware-specific issues and ongoing driver maintenance.

Expand the file patterns to cover the entire Airoha pinctrl driver
directory and all corresponding Device Tree bindings.

Signed-off-by: Zhengping Zhang <zhengping.zhang@airoha.com>
---
 MAINTAINERS | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index 93abbb315065d..15599bca4d125 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -21990,10 +21990,11 @@ F:	include/linux/pinctrl/
 
 PIN CONTROLLER - AIROHA
 M:	Lorenzo Bianconi <lorenzo@kernel.org>
+M:	Zhengping Zhang <zhengping.zhang@airoha.com>
 L:	linux-mediatek@lists.infradead.org (moderated for non-subscribers)
 S:	Maintained
-F:	Documentation/devicetree/bindings/pinctrl/airoha,en7581-pinctrl.yaml
-F:	drivers/pinctrl/airoha/pinctrl-airoha.c
+F:	Documentation/devicetree/bindings/pinctrl/airoha,*pinctrl.yaml
+F:	drivers/pinctrl/airoha/
 
 PIN CONTROLLER - AMD
 M:	Basavaraj Natikar <Basavaraj.Natikar@amd.com>
-- 
2.43.0


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

* Re: [PATCH 01/12] pinctrl: airoha: fix setting of GPIO direction
  2026-11-10  9:43 ` [PATCH 01/12] pinctrl: airoha: fix setting of GPIO direction Zhengping Zhang
@ 2026-11-10  9:53   ` sashiko-bot
  0 siblings, 0 replies; 17+ messages in thread
From: sashiko-bot @ 2026-11-10  9:53 UTC (permalink / raw)
  To: Zhengping Zhang; +Cc: linux-gpio, devicetree, robh, conor+dt

Thank you for your contribution! Sashiko AI review found 1 potential
issue to consider:
- [Low] pinctrl: airoha: missing Fixes: trailer on GPIO direction fix
--

commit 6dcec8340cfdb81d9b7f8c972e7a3451fe15d376
Author: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>

> pinctrl: airoha: fix setting of GPIO direction
>
> The GPIO_CTRL registers have two bits per GPIO where the values 0x2 and
> 0x3 are reserved. It can happen that both bits in GPIO_CTRL of a GPIO
> are set when the pinctrl driver is probed (e.g. modified by bootloader),
> but the current code just clears the LSB. Thus when switching a certain
> GPIO to output, the updated GPIO_CTRL register can contain the reserved
> value 0x2 for that GPIO. This can result in not driving the GPIO pin at
> all.
>
> Always clear both bits per GPIO and just set the LSB when the GPIO is
> configured for output.
>
> Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
> Signed-off-by: Zhengping Zhang <zhengping.zhang@airoha.com>

[Severity: Low]
Since this fixes the single-bit GPIO_CTRL mask introduced in
1c8ace2d0725 ("pinctrl: airoha: Add support for EN7581 SoC") and later
moved into airoha_gpio_set_direction() by 62b1dd7eeaca ("pinctrl: airoha:
add set_direction() helper for gpio_chip"), should it include a Fixes:
tag?

  Fixes: 1c8ace2d0725 ("pinctrl: airoha: Add support for EN7581 SoC")

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261110094339.749110-1-zhengping.zhang@airoha.com?part=1

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

* Re: [PATCH 09/12] pinctrl: airoha: an7583: use force GPIO mode for GPIO requests
  2026-11-10  9:43 ` [PATCH 09/12] pinctrl: airoha: an7583: use force GPIO mode for GPIO requests Zhengping Zhang
@ 2026-11-10  9:56   ` sashiko-bot
  0 siblings, 0 replies; 17+ messages in thread
From: sashiko-bot @ 2026-11-10  9:56 UTC (permalink / raw)
  To: Zhengping Zhang; +Cc: linux-gpio, devicetree, robh, conor+dt

Thank you for your contribution! Sashiko AI review found 2 potential
issues to consider:
- [Medium] pinctrl: airoha: an7583: hsuart and hsuart_cts_rts mux
  conflict
- [Low] pinctrl: airoha: an7583: redundant regmap[2] in PWM_EXT_SEC and
  unused macros
--

commit f7d089a2abc89c3f0877be6d6eb92f87952452c6
Author: Zhengping Zhang <zhengping.zhang@airoha.com>

pinctrl: airoha: an7583: use force GPIO mode for GPIO requests

This commit enables per-pad force GPIO overrides, shared GPIO request
handling, and mux conflict checking on AN7583, while updating peripheral,
PWM, and PON pinmux groups accordingly.

> diff --git a/drivers/pinctrl/airoha/pinctrl-an7583.c b/drivers/pinctrl/airoha/pinctrl-an7583.c
> index 74628a03ca909..e2f629d9d43cd 100644
> --- a/drivers/pinctrl/airoha/pinctrl-an7583.c
> +++ b/drivers/pinctrl/airoha/pinctrl-an7583.c

[ ... ]

> -#define AIROHA_PINCTRL_PWM_EXT_SEC(gpio, mux_val, smux_val)	\
> +#define AIROHA_PINCTRL_PWM_EXT_SEC(gpio, mux_val, smux_val, force_reg, force_mask) \
>  	{							\
>  		.name = (gpio),					\
>  		.regmap[0] = {					\
> @@ -299,10 +308,14 @@
>  			(smux_val),				\
>  			(smux_val)				\
>  		},						\
> -		.regmap_size = 2,				\
> +		.regmap[2] = {					\
> +			AIROHA_FUNC_MUX, (force_reg),		\
> +			(force_mask), (force_mask)			\
> +		},						\
> +		.regmap_size = 3,				\
>  	}

[Severity: Low]
This isn't a bug, but AIROHA_PINCTRL_PWM_EXT_SEC() already sets the
per-pad GPIO selector bit (smux_val) in REG_GPIO_PON_MODE via regmap[1],
and all 13 callers (gpio39 through gpio51 in pwm_func_group) pass 0 for
force_mask, making regmap[2] a no-op entry.  In addition, replacing the
entries in gpio_func_group with AN7583_GPIO_GROUP() leaves
AIROHA_PINCTRL_GPIO() and AIROHA_PINCTRL_GPIO_EXT() unused.

[ ... ]

> @@ -745,7 +840,14 @@ static const struct airoha_pinctrl_func_group uart_func_group[] = {
>  			GPIO_UART2_MODE_MASK | GPIO_UART2_CTS_RTS_MODE_MASK,
>  			GPIO_UART2_MODE_MASK | GPIO_UART2_CTS_RTS_MODE_MASK
>  		},
> -		.regmap_size = 1,
> +		.regmap[1] = {
> +			AIROHA_FUNC_MUX,
> +			REG_FORCE_GPIO_EN,
> +			BIT(30) |
> +			BIT(31),
> +			0
> +		},
> +		.regmap_size = 2,
>  	}, {
>  		.name = "hsuart",
>  		.regmap[0] = {
> @@ -754,7 +856,14 @@ static const struct airoha_pinctrl_func_group uart_func_group[] = {
>  			GPIO_HSUART_MODE_MASK | GPIO_HSUART_CTS_RTS_MODE_MASK,
>  			GPIO_HSUART_MODE_MASK
>  		},
> -		.regmap_size = 1,
> +		.regmap[1] = {
> +			AIROHA_FUNC_MUX,
> +			REG_FORCE_GPIO_EN,
> +			BIT(28) |
> +			BIT(29),
> +			0
> +		},
> +		.regmap_size = 2,
>  	},
>  	{
>  		.name = "hsuart_cts_rts",
> @@ -764,7 +873,14 @@ static const struct airoha_pinctrl_func_group uart_func_group[] = {
>  			GPIO_HSUART_MODE_MASK | GPIO_HSUART_CTS_RTS_MODE_MASK,
>  			GPIO_HSUART_MODE_MASK | GPIO_HSUART_CTS_RTS_MODE_MASK
>  		},
> -		.regmap_size = 1,
> +		.regmap[1] = {
> +			AIROHA_FUNC_MUX,
> +			REG_FORCE_GPIO_EN,
> +			BIT(26) |
> +			BIT(27),
> +			0
> +		},
> +		.regmap_size = 2,
>  	}, {

[Severity: Medium]
Does enabling check_mux_conflicts in pinctrl_match_data cause selecting
both "hsuart" and "hsuart_cts_rts" to fail with -EBUSY?

On AN7583, hsuart_pins covers only the TX/RX pins (30 and 31) and
hsuart_cts_rts_pins covers only the CTS/RTS pins (28 and 29), and their
regmap[1] entries clear the force-GPIO bits for those disjoint pin sets
(BIT(28) | BIT(29) vs BIT(26) | BIT(27)).  Enabling HSUART with flow
control therefore requires selecting both groups, just like "uart2" and
"uart2_cts_rts".  However, unlike "uart2" (whose regmap[0].mask is only
GPIO_UART2_MODE_MASK), "hsuart" includes GPIO_HSUART_CTS_RTS_MODE_MASK in
regmap[0].mask with value 0 while "hsuart_cts_rts" sets that bit to 1, so
airoha_pinmux_check_conflicts() rejects combining them.  Conversely,
selecting "hsuart_cts_rts" alone leaves the TX/RX pins unclaimed and their
force-GPIO overrides (BIT(28) | BIT(29)) uncleared.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261110094339.749110-1-zhengping.zhang@airoha.com?part=9

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

* Re: [PATCH 05/12] pinctrl: airoha: an7581: select force GPIO mode on GPIO requests
  2026-11-10  9:43 ` [PATCH 05/12] pinctrl: airoha: an7581: select force GPIO mode on GPIO requests Zhengping Zhang
@ 2026-11-10 10:00   ` sashiko-bot
  0 siblings, 0 replies; 17+ messages in thread
From: sashiko-bot @ 2026-11-10 10:00 UTC (permalink / raw)
  To: Zhengping Zhang; +Cc: linux-gpio, devicetree, robh, conor+dt

Thank you for your contribution! Sashiko AI review found 1 potential
issue to consider:
- [Medium] pinctrl: airoha: an7581: mux conflict between hsuart and
  hsuart_cts_rts
--

commit b98ded648dd882fe63d659f1c2bdcde0ac118345
Author: Zhengping Zhang <zhengping.zhang@airoha.com>

pinctrl: airoha: an7581: select force GPIO mode on GPIO requests

This commit extends the AN7581 pinctrl driver to support GPIO mux groups for
GPIO0-49 using per-pad force GPIO overrides, clears force GPIO bits when
selecting peripheral functions, and enables shared mux conflict checks.

> diff --git a/drivers/pinctrl/airoha/pinctrl-an7581.c b/drivers/pinctrl/airoha/pinctrl-an7581.c
> index 3cbdfc31e97e5..b266cc8bc65f4 100644
> --- a/drivers/pinctrl/airoha/pinctrl-an7581.c
> +++ b/drivers/pinctrl/airoha/pinctrl-an7581.c

[ ... ]

> @@ -721,7 +792,14 @@ static const struct airoha_pinctrl_func_group uart_func_group[] = {
>  			GPIO_HSUART_MODE_MASK | GPIO_HSUART_CTS_RTS_MODE_MASK,
>  			GPIO_HSUART_MODE_MASK
>  		},
> -		.regmap_size = 1,
> +		.regmap[1] = {
> +			AIROHA_FUNC_MUX,
> +			REG_FORCE_GPIO_EN,
> +			BIT(15) |
> +			BIT(16),
> +			0
> +		},
> +		.regmap_size = 2,
>  	},
>  	{
>  		.name = "hsuart_cts_rts",
> @@ -731,7 +809,14 @@ static const struct airoha_pinctrl_func_group uart_func_group[] = {
>  			GPIO_HSUART_MODE_MASK | GPIO_HSUART_CTS_RTS_MODE_MASK,
>  			GPIO_HSUART_MODE_MASK | GPIO_HSUART_CTS_RTS_MODE_MASK
>  		},
> -		.regmap_size = 1,
> +		.regmap[1] = {
> +			AIROHA_FUNC_MUX,
> +			REG_FORCE_GPIO_EN,
> +			BIT(13) |
> +			BIT(14),
> +			0
> +		},
> +		.regmap_size = 2,
>  	}, {

[ ... ]

> @@ -1432,6 +1834,7 @@ static const struct airoha_pinctrl_conf pinctrl_pcie_rst_od_conf[] = {
>  };
>  
>  static const struct airoha_pinctrl_match_data pinctrl_match_data = {
> +	.check_mux_conflicts = true,
>  	.chip_scu_compatible = "airoha,en7581-chip-scu",
>  	.pinctrl_name = KBUILD_MODNAME,
>  	.pinctrl_owner = THIS_MODULE,

[Severity: Medium]
Does enabling check_mux_conflicts prevent hsuart and hsuart_cts_rts from
being selected together?

hsuart_pins covers only the TX/RX pins (gpio15, gpio16) and clears
BIT(15) | BIT(16) in REG_FORCE_GPIO_EN, while hsuart_cts_rts_pins covers
only the CTS/RTS pins (gpio13, gpio14) and clears BIT(13) | BIT(14).
Configuring 4-wire HSUART with flow control therefore requires selecting
both groups, just like uart2 and uart2_cts_rts.

However, unlike uart2 (whose mask in REG_GPIO_PON_MODE is only
GPIO_UART2_MODE_MASK), hsuart includes GPIO_HSUART_CTS_RTS_MODE_MASK in
its mask with val = GPIO_HSUART_MODE_MASK, requiring the CTS/RTS bit to be
0, while hsuart_cts_rts requires that bit to be 1.  With
check_mux_conflicts enabled, airoha_pinmux_set_mux() ->
airoha_pinmux_check_conflicts() rejects selecting both groups with -EBUSY,
and selecting hsuart_cts_rts alone leaves the TX/RX pins unclaimed and
their force-GPIO bits uncleared.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261110094339.749110-1-zhengping.zhang@airoha.com?part=5

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

* Re: [PATCH 02/12] pinctrl: airoha: configure pin muxes on GPIO requests
  2026-11-10  9:43 ` [PATCH 02/12] pinctrl: airoha: configure pin muxes on GPIO requests Zhengping Zhang
@ 2026-11-10 10:14   ` sashiko-bot
  0 siblings, 0 replies; 17+ messages in thread
From: sashiko-bot @ 2026-11-10 10:14 UTC (permalink / raw)
  To: Zhengping Zhang; +Cc: linux-gpio, devicetree, robh, conor+dt

Thank you for your contribution! Sashiko AI review found 2 potential
issues to consider:
- [Medium] pinctrl: airoha: pinmux ownership bypass and mux_setting
  corruption with function_is_gpio()
- [Medium] pinctrl: airoha: false -EBUSY conflict in
  airoha_pinmux_check_conflicts()
--

commit 9a9749c74aba6ad54ceaf9a1debe606913f398d5
Author: Zhengping Zhang <zhengping.zhang@airoha.com>

pinctrl: airoha: configure pin muxes on GPIO requests

This commit adds a gpio_request_enable callback to configure pin muxes when
a GPIO is requested and introduces optional conflict detection for shared
mux bits across pin groups and GPIO owners.

> diff --git a/drivers/pinctrl/airoha/pinctrl-airoha.c b/drivers/pinctrl/airoha/pinctrl-airoha.c
> index 8dd0881bba4ad..25562e51ebbdc 100644
> --- a/drivers/pinctrl/airoha/pinctrl-airoha.c
> +++ b/drivers/pinctrl/airoha/pinctrl-airoha.c
> @@ -400,57 +400,236 @@ static int airoha_pinctrl_add_gpiochip(struct airoha_pinctrl *pinctrl,

[ ... ]

> +/* Shared mux bits can affect pads outside the requested pin group. */
> +static bool
> +airoha_pinmux_groups_conflict(const struct airoha_pinctrl_func_group *a,
> +			     const struct airoha_pinctrl_func_group *b)
> +{
> +	int i, j;
> +
> +	for (i = 0; i < a->regmap_size; i++) {
> +		for (j = 0; j < b->regmap_size; j++) {
> +			u32 mask;
>  
> -		group = &func->groups[i];
> -		if (strcmp(group->name, grp->grp.name))
> +			if ((a->regmap[i].mux == AIROHA_FUNC_MUX) !=
> +			    (b->regmap[j].mux == AIROHA_FUNC_MUX) ||
> +			    a->regmap[i].offset != b->regmap[j].offset)
> +				continue;
> +
> +			mask = a->regmap[i].mask & b->regmap[j].mask;
> +			if (mask & (a->regmap[i].val ^ b->regmap[j].val))
> +				return true;
> +		}
> +	}
> +
> +	return false;
> +}

[ ... ]

> +static int
> +airoha_pinmux_check_conflicts(struct pinctrl_dev *pctldev,
> +			     const struct airoha_pinctrl_func_group *group)
> +{
> +	unsigned int i;
> +
> +	for (i = 0; i < pctldev->desc->npins; i++) {
> +		const struct airoha_pinctrl_func_group *active;
> +		struct pinctrl_setting_mux setting;
> +		unsigned int number = pctldev->desc->pins[i].number;
> +		struct pin_desc *pin;
> +		bool claimed, gpio_owned;
> +
> +		pin = pin_desc_get(pctldev, number);
> +		if (!pin)
> +			continue;
> +
> +		scoped_guard(mutex, &pin->mux_lock) {
> +			claimed = pin->mux_usecount && pin->mux_setting;
> +			gpio_owned = !!pin->gpio_owner;
> +			if (claimed)
> +				setting = *pin->mux_setting;
> +		}
> +
> +		/* GPIO requests need no explicit DTS pinctrl state. */
> +		if (gpio_owned) {
> +			active = airoha_pinmux_get_gpio_group(pctldev, number);
> +			if (!active)
> +				return -EOPNOTSUPP;
> +			if (airoha_pinmux_groups_conflict(group, active))
> +				goto conflict;
> +		}
> +
> +		if (!claimed)
> +			continue;
> +		active = airoha_pinmux_get_func_group(pctldev, setting.func,
> +						    setting.group);
> +		if (!active)
> +			return -EINVAL;
> +		if (!airoha_pinmux_groups_conflict(group, active))
> +			continue;
> +
> +conflict:
> +		dev_err(pctldev->dev,
> +			"group %s conflicts with shared mux bits of group %s\n",
> +			group->name, active->name);
> +		return -EBUSY;
> +	}
> +
> +	return 0;
> +}

[Severity: Medium]
Does airoha_pinmux_check_conflicts() reject valid two-group HSUART
configurations (groups = "hsuart", "hsuart_cts_rts") with -EBUSY on SoCs
that enable check_mux_conflicts?

On AN7581 and AN7583, hsuart_pins contains only the TX/RX pins and
hsuart_cts_rts_pins contains only the CTS/RTS pins, so enabling HSUART with
hardware flow control requires selecting both groups. However, in
uart_func_group, the "hsuart" entry includes GPIO_HSUART_CTS_RTS_MODE_MASK
in regmap[0].mask with val = GPIO_HSUART_MODE_MASK, whereas
"hsuart_cts_rts" sets the same mask with val = GPIO_HSUART_MODE_MASK |
GPIO_HSUART_CTS_RTS_MODE_MASK. When pinctrl_commit_state() enables the
second group after claiming the first, airoha_pinmux_groups_conflict() sees
differing values on GPIO_HSUART_CTS_RTS_MODE_MASK and fails the state
transition with -EBUSY.

[ ... ]

> +static int airoha_pinmux_set_mux(struct pinctrl_dev *pctldev,
> +			       unsigned int selector, unsigned int group)
> +{
> +	struct airoha_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev);
> +	const struct airoha_pinctrl_func_group *config;
> +	int i, err;
> +
> +	config = airoha_pinmux_get_func_group(pctldev, selector, group);
> +	if (!config)
> +		return -EINVAL;
> +
> +	guard(mutex)(&pinctrl->mux_lock);
> +	if (pinctrl->check_mux_conflicts) {
> +		struct group_desc *grp;
> +
> +		/* The core permits GPIO-category muxes alongside GPIO owners. */
> +		grp = pinctrl_generic_get_group(pctldev, group);
> +		if (!pinmux_generic_function_is_gpio(pctldev, selector)) {
> +			for (i = 0; i < grp->grp.npins; i++) {
> +				struct pin_desc *pin;
> +
> +				pin = pin_desc_get(pctldev, grp->grp.pins[i]);
> +				if (!pin)
> +					return -EINVAL;
> +				scoped_guard(mutex, &pin->mux_lock) {
> +					if (pin->gpio_owner)
> +						return -EBUSY;
> +				}
> +			}
> +		}
> +
> +		err = airoha_pinmux_check_conflicts(pctldev, config);
> +		if (err)
> +			return err;
>  	}
>  
> -	return -EINVAL;
> +	dev_dbg(pctldev->dev, "enable function %s group %s\n",
> +		pinmux_generic_get_function_name(pctldev, selector),
> +		config->name);
> +
> +	return airoha_pinmux_apply_group(pinctrl, config);
>  }
>  
>  static int airoha_pinmux_set_direction(struct pinctrl_dev *pctrl_dev,
> @@ -468,6 +647,8 @@ static int airoha_pinmux_set_direction(struct pinctrl_dev *pctrl_dev,
>  }
>  
>  static const struct pinmux_ops airoha_pmxops = {
> +	.gpio_request_enable = airoha_gpio_request_enable,
> +	.function_is_gpio = pinmux_generic_function_is_gpio,

[Severity: Medium]
Can setting .function_is_gpio allow a second consumer to bypass pinmux
ownership and corrupt pin->mux_setting when a pin is already claimed by an
explicit GPIO-category pinctrl state?

When a pin's active pin->mux_setting has PINFUNCTION_FLAG_GPIO (via
PINCTRL_GPIO_FUNC_DESC), a second consumer calling pinmux_enable_setting()
on a group containing that pin causes pin_request() to set gpio_ok = true,
skip the mux_owner check, and increment pin->mux_usecount to 2:

drivers/pinctrl/pinmux.c:pin_request() {
    ...
	if (gpio_range || ops->strict) {
		if (desc->mux_usecount && !gpio_ok) {
			dev_err(pctldev->dev,
				"pin %s already requested by %s; cannot claim for %s\n",
				desc->name, desc->mux_owner, owner);
			goto out;
		}
    ...
}

pinmux_enable_setting() then overwrites pin->mux_setting with the new
setting before calling airoha_pinmux_set_mux(). Because
airoha_pinmux_set_mux() only checks pin->gpio_owner, if the pin has no GPIO
descriptor owner, airoha_pinmux_check_conflicts() sees the already
overwritten pin->mux_setting and overwrites the first device's hardware mux
without detecting the conflict. Conversely, if airoha_pinmux_set_mux()
returns -EBUSY, pinmux_enable_setting()'s error path clears
pin->mux_setting to NULL while pin_free() only decrements pin->mux_usecount
to 1, hiding the first owner's active mux from subsequent conflict checks
and preventing pinmux_disable_setting() from releasing the pin.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261110094339.749110-1-zhengping.zhang@airoha.com?part=2

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

end of thread, other threads:[~2026-11-10 10:14 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-10  9:43 [PATCH 00/12] pinctrl: airoha: configure GPIO muxes explicitly and fix pad mappings Zhengping Zhang
2026-11-10  9:43 ` [PATCH 01/12] pinctrl: airoha: fix setting of GPIO direction Zhengping Zhang
2026-11-10  9:53   ` sashiko-bot
2026-11-10  9:43 ` [PATCH 02/12] pinctrl: airoha: configure pin muxes on GPIO requests Zhengping Zhang
2026-11-10 10:14   ` sashiko-bot
2026-11-10  9:43 ` [PATCH 03/12] dt-bindings: pinctrl: airoha: describe all EN7581 GPIO mux groups Zhengping Zhang
2026-11-10  9:43 ` [PATCH 04/12] pinctrl: airoha: an7581: fix PHY LED GPIO group assignments Zhengping Zhang
2026-11-10  9:43 ` [PATCH 05/12] pinctrl: airoha: an7581: select force GPIO mode on GPIO requests Zhengping Zhang
2026-11-10 10:00   ` sashiko-bot
2026-11-10  9:43 ` [PATCH 06/12] dt-bindings: pinctrl: airoha: describe all AN7583 GPIO mux groups Zhengping Zhang
2026-11-10  9:43 ` [PATCH 07/12] pinctrl: airoha: an7583: fix SPI pin mux config Zhengping Zhang
2026-11-10  9:43 ` [PATCH 08/12] pinctrl: airoha: an7583: fix eMMC " Zhengping Zhang
2026-11-10  9:43 ` [PATCH 09/12] pinctrl: airoha: an7583: use force GPIO mode for GPIO requests Zhengping Zhang
2026-11-10  9:56   ` sashiko-bot
2026-11-10  9:43 ` [PATCH 10/12] dt-bindings: pinctrl: airoha: describe all EN7523 GPIO mux groups Zhengping Zhang
2026-11-10  9:43 ` [PATCH 11/12] pinctrl: airoha: en7523: use force GPIO mode for GPIO requests Zhengping Zhang
2026-11-10  9:43 ` [PATCH 12/12] MAINTAINERS: add myself as Airoha pinctrl co-maintainer Zhengping Zhang

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