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

Benjamin Larsson benjamin.larsson at genexis.eu
Fri Aug 14 12:38:22 PDT 2026


Hi.

On 09/08/2026 10:04, Ahmed Naseef wrote:
> The driver assumes that every one of the AIROHA_NUM_PINS GPIOs can raise
> an interrupt. That holds for the SoCs supported so far, but not for every
> member of the family: on EN7528 only GPIO0-GPIO15 are wired to the
> interrupt controller.
> 
> Without this the driver hands out interrupts for GPIOs that can never
> fire, and the interrupt handler reads status registers that are not
> backed by any pin.
> 
> Add a num_irq_pins field to the per-SoC match data and use it to bound
> the interrupt callbacks and to size the loop in the interrupt handler.
> Feed it to gpiolib through gpio_irq_chip::init_valid_mask as well, so
> that gpiod_to_irq() fails for a pin that cannot be an interrupt source
> instead of deferring the failure to request_irq().
> 
> Signed-off-by: Ahmed Naseef <naseefkm at gmail.com>
> ---
>   drivers/pinctrl/airoha/airoha-common.h  |  3 +++
>   drivers/pinctrl/airoha/pinctrl-airoha.c | 33 +++++++++++++++++++++----
>   drivers/pinctrl/airoha/pinctrl-an7563.c |  1 +
>   drivers/pinctrl/airoha/pinctrl-an7581.c |  1 +
>   drivers/pinctrl/airoha/pinctrl-an7583.c |  1 +
>   drivers/pinctrl/airoha/pinctrl-en7523.c |  1 +
>   6 files changed, 35 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/pinctrl/airoha/airoha-common.h b/drivers/pinctrl/airoha/airoha-common.h
> index c1acbfb7426e..16f7abcdfb83 100644
> --- a/drivers/pinctrl/airoha/airoha-common.h
> +++ b/drivers/pinctrl/airoha/airoha-common.h
> @@ -127,6 +127,7 @@ struct airoha_pinctrl {
>   
>   	struct gpio_chip gpiochip;
>   	struct airoha_gpiochip_regs *gpio_regs;
> +	unsigned int num_irq_pins;
>   };
>   
>   struct airoha_pinctrl_match_data {
> @@ -140,6 +141,8 @@ struct airoha_pinctrl_match_data {
>   	const struct airoha_pinctrl_func *funcs;
>   	const unsigned int num_funcs;
>   	const struct airoha_pinctrl_confs_info confs_info[AIROHA_PINCTRL_CONFS_MAX];
> +	/* number of GPIOs wired to the interrupt controller */
> +	const unsigned int num_irq_pins;
>   };
>   
>   int airoha_pinctrl_probe(struct platform_device *pdev);
> diff --git a/drivers/pinctrl/airoha/pinctrl-airoha.c b/drivers/pinctrl/airoha/pinctrl-airoha.c
> index f505a3f69c5d..52a768c859b7 100644
> --- a/drivers/pinctrl/airoha/pinctrl-airoha.c
> +++ b/drivers/pinctrl/airoha/pinctrl-airoha.c
> @@ -213,7 +213,7 @@ static void airoha_irq_unmask(struct irq_data *data)
>   	u32 mask = GENMASK(2 * offset + 1, 2 * offset);
>   	u32 val = BIT(2 * offset);
>   
> -	if (WARN_ON_ONCE(data->hwirq >= AIROHA_NUM_PINS))
> +	if (WARN_ON_ONCE(data->hwirq >= pinctrl->num_irq_pins))
>   		return;
>   
>   	gpiochip_enable_irq(gc, irqd_to_hwirq(data));
> @@ -249,7 +249,7 @@ static void airoha_irq_mask(struct irq_data *data)
>   	u8 index = data->hwirq / AIROHA_REG_GPIOCTRL_NUM_PIN;
>   	u32 mask = GENMASK(2 * offset + 1, 2 * offset);
>   
> -	if (data->hwirq >= AIROHA_NUM_PINS)
> +	if (data->hwirq >= pinctrl->num_irq_pins)
>   		return;
>   
>   	regmap_clear_bits(pinctrl->regmap, gpio_regs->level[index], mask);
> @@ -265,7 +265,7 @@ static void airoha_irq_ack(struct irq_data *data)
>   	u8 offset = data->hwirq % AIROHA_PIN_BANK_SIZE;
>   	u8 index = data->hwirq / AIROHA_PIN_BANK_SIZE;
>   
> -	if (data->hwirq >= AIROHA_NUM_PINS)
> +	if (data->hwirq >= pinctrl->num_irq_pins)
>   		return;
>   
>   	regmap_write(pinctrl->regmap, gpio_regs->status[index], BIT(offset));
> @@ -273,7 +273,10 @@ static void airoha_irq_ack(struct irq_data *data)
>   
>   static int airoha_irq_type(struct irq_data *data, unsigned int type)
>   {
> -	if (data->hwirq >= AIROHA_NUM_PINS)
> +	struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
> +	struct airoha_pinctrl *pinctrl = gpiochip_get_data(gc);
> +
> +	if (data->hwirq >= pinctrl->num_irq_pins)
>   		return -EINVAL;
>   
>   	if (type == IRQ_TYPE_NONE) {
> @@ -304,9 +307,11 @@ static irqreturn_t airoha_irq_handler(int irq, void *data)
>   {
>   	struct airoha_pinctrl *pinctrl = data;
>   	bool handled = false;
> +	unsigned int nbanks;
>   	int i;
>   
> -	for (i = 0; i < ARRAY_SIZE(irq_status_regs); i++) {
> +	nbanks = DIV_ROUND_UP(pinctrl->num_irq_pins, AIROHA_PIN_BANK_SIZE);
> +	for (i = 0; i < nbanks; i++) {
>   		struct gpio_irq_chip *girq = &pinctrl->gpiochip.irq;
>   		u32 regmap;
>   		unsigned long status;
> @@ -340,6 +345,22 @@ static const struct irq_chip airoha_gpio_irq_chip = {
>   	GPIOCHIP_IRQ_RESOURCE_HELPERS,
>   };
>   
> +/*
> + * Mark the GPIOs that are not wired to the interrupt controller as not
> + * valid, so that gpiod_to_irq() fails for them with -ENXIO instead of
> + * handing out an interrupt that can never fire.
> + */
> +static void airoha_gpio_init_valid_mask(struct gpio_chip *gc,
> +					unsigned long *valid_mask,
> +					unsigned int ngpios)
> +{
> +	struct airoha_pinctrl *pinctrl = gpiochip_get_data(gc);
> +	unsigned int num_irq_pins = pinctrl->num_irq_pins;
> +
> +	if (num_irq_pins < ngpios)
> +		bitmap_clear(valid_mask, num_irq_pins, ngpios - num_irq_pins);
> +}

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

Either way:
Reviewed-by: Benjamin Larsson <benjamin.larsson at genexis.eu>

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




More information about the Linux-mediatek mailing list