Skip to content

Commit

Permalink
gpio: pcf857x: handle only enabled irqs
Browse files Browse the repository at this point in the history
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
21fd3cd ('gpio: pcf857x: call the gpio user handler iff...')

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

Cc: Geert Uytterhoeven <geert+renesas@glider.be>
Fixes: a39294b ('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>
  • Loading branch information
Grygorii Strashko authored and Linus Walleij committed Jun 16, 2015
1 parent f35bbf6 commit 84f2899
Showing 1 changed file with 35 additions and 11 deletions.
46 changes: 35 additions & 11 deletions drivers/gpio/gpio-pcf857x.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ struct pcf857x {
unsigned out; /* software latch */
unsigned status; /* current status */
unsigned int irq_parent;
unsigned irq_enabled; /* enabled irqs */

int (*write)(struct i2c_client *client, unsigned data);
int (*read)(struct i2c_client *client);
Expand Down Expand Up @@ -195,7 +196,7 @@ static irqreturn_t pcf857x_irq(int irq, void *data)
* interrupt source, just to avoid bad irqs
*/

change = (gpio->status ^ status);
change = (gpio->status ^ status) & gpio->irq_enabled;
for_each_set_bit(i, &change, gpio->chip.ngpio)
handle_nested_irq(irq_find_mapping(gpio->chip.irqdomain, i));
gpio->status = status;
Expand All @@ -210,14 +211,10 @@ static irqreturn_t pcf857x_irq(int irq, void *data)
*/
static void noop(struct irq_data *data) { }

static unsigned int noop_ret(struct irq_data *data)
{
return 0;
}

static int pcf857x_irq_set_wake(struct irq_data *data, unsigned int on)
{
struct pcf857x *gpio = irq_data_get_irq_chip_data(data);

int error = 0;

if (gpio->irq_parent) {
Expand All @@ -229,20 +226,47 @@ static int pcf857x_irq_set_wake(struct irq_data *data, unsigned int on)
gpio->irq_parent = 0;
}
}

return error;
}

static void pcf857x_irq_enable(struct irq_data *data)
{
struct pcf857x *gpio = irq_data_get_irq_chip_data(data);

gpio->irq_enabled |= (1 << data->hwirq);
}

static void pcf857x_irq_disable(struct irq_data *data)
{
struct pcf857x *gpio = irq_data_get_irq_chip_data(data);

gpio->irq_enabled &= ~(1 << data->hwirq);
}

static void pcf857x_irq_bus_lock(struct irq_data *data)
{
struct pcf857x *gpio = irq_data_get_irq_chip_data(data);

mutex_lock(&gpio->lock);
}

static void pcf857x_irq_bus_sync_unlock(struct irq_data *data)
{
struct pcf857x *gpio = irq_data_get_irq_chip_data(data);

mutex_unlock(&gpio->lock);
}

static struct irq_chip pcf857x_irq_chip = {
.name = "pcf857x",
.irq_startup = noop_ret,
.irq_shutdown = noop,
.irq_enable = noop,
.irq_disable = noop,
.irq_enable = pcf857x_irq_enable,
.irq_disable = pcf857x_irq_disable,
.irq_ack = noop,
.irq_mask = noop,
.irq_unmask = noop,
.irq_set_wake = pcf857x_irq_set_wake,
.irq_bus_lock = pcf857x_irq_bus_lock,
.irq_bus_sync_unlock = pcf857x_irq_bus_sync_unlock,
};

/*-------------------------------------------------------------------------*/
Expand Down

0 comments on commit 84f2899

Please sign in to comment.