[PATCH AUTOSEL 6.19-6.18] pinctrl: renesas: rzt2h: Allow .get_direction() for IRQ function GPIOs

Sasha Levin
2026-02-19T02:05:07Z

From: Cosmin Tanislav <cosmin-gabriel.tanislav.xa@renesas.com>

[ Upstream commit 49b039a61a314c18074c15a7047705399e1240e6 ]

Setting up an IRQ would normally be done in the .activate() and
.deactivate() ops of the IRQ domain, but for hierarchical IRQ domains
the .activate() and .deactivate() ops are overridden in the
gpiochip_hierarchy_setup_domain_ops() function.

As such, activating and deactivating need to be done in the .translate()
and .free() ops of the IRQ domain.

For RZ/T2H and RZ/N2H, interrupts go through the pin controller, into
the ICU, which level-translates them and forwards them to the GIC.

To use a GPIO as an interrupt it needs to be put into peripheral
function mode 0, which will connect it to the IRQ lines of the ICU.

The IRQ chip .child_to_parent_hwirq() callback is called as part of the
IRQ fwspec parsing logic (as part of irq_create_of_mapping()) which
happens before the IRQ is requested (as part of gpiochip_lock_as_irq()).

gpiochip_lock_as_irq() calls gpiod_get_direction() if the
.get_direction() callback is provided to ensure that the GPIO line is
set up as input.

In our case, IRQ function is separate from GPIO, and both cannot be true
at the same time.

Return GPIO_LINE_DIRECTION_IN even if pin is in IRQ function to allow
this setup to work.

Hold the spinlock to ensure atomicity between reading the PMC register
(which determines whether the pin is in GPIO mode or not) and reading
the function of the pin when it is not in GPIO mode.

Signed-off-by: Cosmin Tanislav <cosmin-gabriel.tanislav.xa@renesas.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Link: https://patch.msgid.link/20251205150234.2958140-3-cosmin-gabriel.tanislav.xa@renesas.com
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

Confirmed: The PFC register read pattern with `rzt2h_pinctrl_readq` and
the `PFC_MASK` at line 141 is consistent with what the fix does. The new
code reads `PFC(port)` and masks with `PFC_MASK`, which is the same
pattern used in the existing `rzt2h_pinctrl_set_pfc` function.

### Verification

- **Verified**: The driver `pinctrl-rzt2h.c` was introduced in commit
34d4d093077a5, first appearing in v6.18. Active stable trees v6.18.y
and v6.19.y contain this driver.
- **Verified**: `gpiochip_lock_as_irq()` at gpiolib.c:4088-4095 calls
`gpiod_get_direction()` and fails if it returns negative, confirming
the bug mechanism described in the commit message.
- **Verified**: The original `rzt2h_gpio_get_direction()` returns
`-EINVAL` unconditionally when PMC bit is set (line 496-497 of current
code), which would fail IRQ setup.
- **Verified**: `rzt2h_pinctrl_readq` is generated by macro at line 104
and already used for PFC reads (line 140), so no new functions are
needed.
- **Verified**: `PFC_MASK` is already defined (line 51: `GENMASK_ULL(5,
0)`), so the mask pattern is correct.
- **Verified**: The PFC function 0 being the IRQ function is consistent
with the hardware description (peripheral function mode 0 connects to
ICU IRQ lines, as stated in the commit message).
- **Verified**: The spinlock `pctrl->lock` is already used in other
functions (e.g., `rzt2h_gpio_set_direction` at line 475,
`rzt2h_pinctrl_set_pfc` at line 128), so adding it to `get_direction`
is consistent.
- **Verified**: No additional commits are needed as dependencies - the
code being modified exists in the base driver.
- **Unverified**: Whether the commit has been explicitly discussed on
linux-stable mailing list (did not search lore.kernel.org).

### Summary

**What the commit fixes**: GPIO pins on Renesas RZ/T2H and RZ/N2H SoCs
cannot be used as interrupt sources because the GPIO direction query
fails when the pin is in IRQ function mode, causing
`gpiochip_lock_as_irq()` to fail.

**Stable kernel criteria**:
- **Obviously correct**: Yes - the logic is clear and well-explained.
When a pin is in IRQ mode (peripheral function 0), reporting it as
input direction is the correct semantic.
- **Fixes a real bug**: Yes - GPIO IRQ functionality is broken without
this fix.
- **Small and contained**: Yes - ~20 lines in a single function in a
single driver file.
- **No new features**: Correct - this fixes existing GPIO/IRQ
interaction, not adding new functionality.
- **Reviewed**: Yes - reviewed by Geert Uytterhoeven (Renesas subsystem
maintainer).

**Risk vs benefit**: Very low risk (single driver, narrow hardware
scope, no architectural changes) vs. high benefit (enables GPIO IRQ
functionality on these SoCs).

**Concern**: The driver only exists in v6.18+ stable trees, limiting the
scope of backporting. No older stable trees are affected.

**YES**

drivers/pinctrl/renesas/pinctrl-rzt2h.c | 21 ++++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/drivers/pinctrl/renesas/pinctrl-rzt2h.c b/drivers/pinctrl/renesas/pinctrl-rzt2h.c
index 4826ff91cd906..40df706210119 100644
--- a/drivers/pinctrl/renesas/pinctrl-rzt2h.c
+++ b/drivers/pinctrl/renesas/pinctrl-rzt2h.c
@@ -51,6 +51,7 @@

#define PFC_MASK GENMASK_ULL(5, 0)
#define PFC_PIN_MASK(pin) (PFC_MASK << ((pin) * 8))
+#define PFC_FUNC_INTERRUPT 0

/*
* Use 16 lower bits [15:0] for pin identifier
@@ -486,6 +487,7 @@ static int rzt2h_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
struct rzt2h_pinctrl *pctrl = gpiochip_get_data(chip);
u8 port = RZT2H_PIN_ID_TO_PORT(offset);
u8 bit = RZT2H_PIN_ID_TO_PIN(offset);
+ u64 reg64;
u16 reg;
int ret;

@@ -493,8 +495,25 @@ static int rzt2h_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
if (ret)
return ret;

- if (rzt2h_pinctrl_readb(pctrl, port, PMC(port)) & BIT(bit))
+ guard(spinlock_irqsave)(&pctrl->lock);
+
+ if (rzt2h_pinctrl_readb(pctrl, port, PMC(port)) & BIT(bit)) {
+ /*
+ * When a GPIO is being requested as an IRQ, the pinctrl
+ * framework expects to be able to read the GPIO's direction.
+ * IRQ function is separate from GPIO, and enabling it takes the
+ * pin out of GPIO mode.
+ * At this point, .child_to_parent_hwirq() has already been
+ * called to enable the IRQ function.
+ * Default to input direction for IRQ function.
+ */
+ reg64 = rzt2h_pinctrl_readq(pctrl, port, PFC(port));
+ reg64 = (reg64 >> (bit * 8)) & PFC_MASK;
+ if (reg64 == PFC_FUNC_INTERRUPT)
+ return GPIO_LINE_DIRECTION_IN;
+
return -EINVAL;
+ }

reg = rzt2h_pinctrl_readw(pctrl, port, PM(port));
reg = (reg >> (bit * 2)) & PM_MASK;
--
2.51.0