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

gpio: pcf857x: handle only enabled irqs

Now pcf857x_irq() IRQ's dispatcher will try to run nested
IRQ handlers for each GPIO pin which state has changed.
Such IRQs are, actually, spurious and nested IRQ handlers
have to be called only for IRQs wich were enabled by users.
This is not critical issue - just /proc/interrupts
will display counters for unused IRQS:
399: 4 0 pcf857x 0 Edge
428: 1 0 pcf857x 13 Edge
430: 1 0 pcf857x 15 Edge

Hence, fix it by adding irq_enabled field in struct pcf857x to track
enabled GPIO IRQs and corresponding callbacks in pcf857x_irq_chip.

Similar functionality was presented in pcf857x driver, commit
21fd3cd1874a ('gpio: pcf857x: call the gpio user handler iff...')

and then it was removed by commit
a39294bdf4b0 ('gpio: pcf857x: Switch to use gpiolib irqchip...')

Cc: Geert Uytterhoeven <geert+renesas@glider.be>
Fixes: a39294bdf4b0 ('gpio: pcf857x: Switch to use gpiolib irqchip helpers')
Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

authored by

Grygorii Strashko and committed by
Linus Walleij
84f28998 f35bbf61

+35 -11
+35 -11
drivers/gpio/gpio-pcf857x.c
··· 92 92 unsigned out; /* software latch */ 93 93 unsigned status; /* current status */ 94 94 unsigned int irq_parent; 95 + unsigned irq_enabled; /* enabled irqs */ 95 96 96 97 int (*write)(struct i2c_client *client, unsigned data); 97 98 int (*read)(struct i2c_client *client); ··· 196 195 * interrupt source, just to avoid bad irqs 197 196 */ 198 197 199 - change = (gpio->status ^ status); 198 + change = (gpio->status ^ status) & gpio->irq_enabled; 200 199 for_each_set_bit(i, &change, gpio->chip.ngpio) 201 200 handle_nested_irq(irq_find_mapping(gpio->chip.irqdomain, i)); 202 201 gpio->status = status; ··· 211 210 */ 212 211 static void noop(struct irq_data *data) { } 213 212 214 - static unsigned int noop_ret(struct irq_data *data) 215 - { 216 - return 0; 217 - } 218 - 219 213 static int pcf857x_irq_set_wake(struct irq_data *data, unsigned int on) 220 214 { 221 215 struct pcf857x *gpio = irq_data_get_irq_chip_data(data); 216 + 222 217 int error = 0; 223 218 224 219 if (gpio->irq_parent) { ··· 226 229 gpio->irq_parent = 0; 227 230 } 228 231 } 229 - 230 232 return error; 233 + } 234 + 235 + static void pcf857x_irq_enable(struct irq_data *data) 236 + { 237 + struct pcf857x *gpio = irq_data_get_irq_chip_data(data); 238 + 239 + gpio->irq_enabled |= (1 << data->hwirq); 240 + } 241 + 242 + static void pcf857x_irq_disable(struct irq_data *data) 243 + { 244 + struct pcf857x *gpio = irq_data_get_irq_chip_data(data); 245 + 246 + gpio->irq_enabled &= ~(1 << data->hwirq); 247 + } 248 + 249 + static void pcf857x_irq_bus_lock(struct irq_data *data) 250 + { 251 + struct pcf857x *gpio = irq_data_get_irq_chip_data(data); 252 + 253 + mutex_lock(&gpio->lock); 254 + } 255 + 256 + static void pcf857x_irq_bus_sync_unlock(struct irq_data *data) 257 + { 258 + struct pcf857x *gpio = irq_data_get_irq_chip_data(data); 259 + 260 + mutex_unlock(&gpio->lock); 231 261 } 232 262 233 263 static struct irq_chip pcf857x_irq_chip = { 234 264 .name = "pcf857x", 235 - .irq_startup = noop_ret, 236 - .irq_shutdown = noop, 237 - .irq_enable = noop, 238 - .irq_disable = noop, 265 + .irq_enable = pcf857x_irq_enable, 266 + .irq_disable = pcf857x_irq_disable, 239 267 .irq_ack = noop, 240 268 .irq_mask = noop, 241 269 .irq_unmask = noop, 242 270 .irq_set_wake = pcf857x_irq_set_wake, 271 + .irq_bus_lock = pcf857x_irq_bus_lock, 272 + .irq_bus_sync_unlock = pcf857x_irq_bus_sync_unlock, 243 273 }; 244 274 245 275 /*-------------------------------------------------------------------------*/