Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

gpio: cadence: Add support for edge-triggered interrupts

The Cadence GPIO controller (CDNS IP6508) supports edge-triggered
interrupts (rising, falling, and both) via IRQ_TYPE, IRQ_VALUE,
and IRQ_ANY_EDGE registers. This commit enables support for these
modes in cdns_gpio_irq_set_type().

Although the interrupt status register is cleared on read and lacks
per-pin acknowledgment, the driver already handles this safely by
reading the ISR once and dispatching all pending interrupts immediately.
This allows edge IRQs to be used reliably in controlled environments.

Signed-off-by: Tzu-Hao Wei <twei@axiado.com>
Reviewed-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Swark Yang <syang@axiado.com>
Link: https://lore.kernel.org/r/20260109-axiado-ax3000-cadence-gpio-support-v2-2-fc1e28edf68a@axiado.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>

authored by

Tzu-Hao Wei and committed by
Bartosz Golaszewski
43f37d44 ea5b4c68

+16 -4
+16 -4
drivers/gpio/gpio-cadence.c
··· 98 98 struct cdns_gpio_chip *cgpio = gpiochip_get_data(chip); 99 99 u32 int_value; 100 100 u32 int_type; 101 + u32 int_any; 101 102 u32 mask = BIT(d->hwirq); 102 103 int ret = 0; 103 104 ··· 106 105 107 106 int_value = ioread32(cgpio->regs + CDNS_GPIO_IRQ_VALUE) & ~mask; 108 107 int_type = ioread32(cgpio->regs + CDNS_GPIO_IRQ_TYPE) & ~mask; 109 - 110 108 /* 111 - * The GPIO controller doesn't have an ACK register. 112 - * All interrupt statuses are cleared on a status register read. 113 - * Don't support edge interrupts for now. 109 + * Interrupt polarity and trigger behaviour is configured like this: 110 + * 111 + * (type, value) 112 + * (0, 0) = Falling edge triggered 113 + * (0, 1) = Rising edge triggered 114 + * (1, 0) = Low level triggered 115 + * (1, 1) = High level triggered 114 116 */ 117 + int_any = ioread32(cgpio->regs + CDNS_GPIO_IRQ_ANY_EDGE) & ~mask; 115 118 116 119 if (type == IRQ_TYPE_LEVEL_HIGH) { 117 120 int_type |= mask; 118 121 int_value |= mask; 119 122 } else if (type == IRQ_TYPE_LEVEL_LOW) { 120 123 int_type |= mask; 124 + } else if (type == IRQ_TYPE_EDGE_RISING) { 125 + int_value |= mask; 126 + } else if (type == IRQ_TYPE_EDGE_FALLING) { 127 + /* edge trigger, int_value remains cleared for falling */ 128 + } else if (type == IRQ_TYPE_EDGE_BOTH) { 129 + int_any |= mask; 121 130 } else { 122 131 return -EINVAL; 123 132 } 124 133 125 134 iowrite32(int_value, cgpio->regs + CDNS_GPIO_IRQ_VALUE); 126 135 iowrite32(int_type, cgpio->regs + CDNS_GPIO_IRQ_TYPE); 136 + iowrite32(int_any, cgpio->regs + CDNS_GPIO_IRQ_ANY_EDGE); 127 137 128 138 return ret; 129 139 }