[PATCH 4/7] pinctrl: renesas: rzt2h: fix reading pin value in IRQ function
Cosmin Tanislav <[email protected]>
| Newsgroups | org.kernel.vger.linux-renesas-soc,org.kernel.vger.linux-gpio,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
rzt2h_gpio_get() only reports a level for pins in input or output mode and returns -EINVAL otherwise. When a pin is requested as an interrupt it is switched to IRQ function and its I/O mode is set to Hi-Z, so its value can no longer be read. gpiolib calls gpiod_get_value_cansleep() to determine the edge's direction when a line is watched with GPIO_V2_LINE_FLAG_EDGE_BOTH. Non-zero values are translated to a rising edge, zero to a falling edge. Since gpiod_get_value_cansleep() ends up calling rzt2h_gpio_get() which returns -EINVAL when the pin is in IRQ function, every edge is reported as rising. When using the IRQ function, the input buffers are enabled and the PINm registers reflect the live state of the input. Report the input level even when the pin is used as an IRQ. Cc: [email protected] Fixes: 829dde3369a9 ("pinctrl: renesas: rzt2h: Add GPIO IRQ chip to handle interrupts") Signed-off-by: Cosmin Tanislav <[email protected]> --- drivers/pinctrl/renesas/pinctrl-rzt2h.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/pinctrl/renesas/pinctrl-rzt2h.c b/drivers/pinctrl/renesas/pinctrl-rzt2h.c index 287cacbcb37b..b8d5b6af5be4 100644 --- a/drivers/pinctrl/renesas/pinctrl-rzt2h.c +++ b/drivers/pinctrl/renesas/pinctrl-rzt2h.c @@ -171,6 +171,23 @@ static int rzt2h_validate_pin(struct rzt2h_pinctrl *pctrl, unsigned int offset) return (pincfg & BIT(pin)) ? 0 : -EINVAL; } +static bool rzt2h_pin_mode_is_peripheral(struct rzt2h_pinctrl *pctrl, u8 port, u8 bit) +{ + return rzt2h_pinctrl_readb(pctrl, port, PMC(port)) & BIT(bit); +} + +static u8 rzt2h_pin_read_pfc(struct rzt2h_pinctrl *pctrl, u8 port, u8 pin) +{ + u64 reg64 = rzt2h_pinctrl_readq(pctrl, port, PFC(port)); + + return field_get(PFC_PIN_MASK(pin), reg64); +} + +static bool rzt2h_pin_read_input(struct rzt2h_pinctrl *pctrl, u8 port, u8 bit) +{ + return rzt2h_pinctrl_readb(pctrl, port, PIN(port)) & BIT(bit); +} + static u8 rzt2h_pin_read_pm(struct rzt2h_pinctrl *pctrl, u8 port, u8 pin) { u16 reg = rzt2h_pinctrl_readw(pctrl, port, PM(port)); @@ -847,6 +864,13 @@ static int rzt2h_gpio_get(struct gpio_chip *chip, unsigned int offset) u8 bit = RZT2H_PIN_ID_TO_PIN(offset); u16 reg; + if (rzt2h_pin_mode_is_peripheral(pctrl, port, bit)) { + if (rzt2h_pin_read_pfc(pctrl, port, bit) == PFC_FUNC_INTERRUPT) + return rzt2h_pin_read_input(pctrl, port, bit); + + return -EINVAL; + } + reg = rzt2h_pinctrl_readw(pctrl, port, PM(port)); reg = (reg >> (bit * 2)) & PM_MASK; if (reg & PM_INPUT) -- 2.55.0