diff options
-rw-r--r-- | drivers/gpio/gpio-104-idi-48.c | 19 |
1 files changed, 9 insertions, 10 deletions
diff --git a/drivers/gpio/gpio-104-idi-48.c b/drivers/gpio/gpio-104-idi-48.c index b5c693409a58..296dbd4cadd9 100644 --- a/drivers/gpio/gpio-104-idi-48.c +++ b/drivers/gpio/gpio-104-idi-48.c @@ -36,6 +36,7 @@ MODULE_PARM_DESC(idi_48_irq, "ACCES 104-IDI-48 interrupt line number"); * struct idi_48_gpio - GPIO device private data structure * @chip: instance of the gpio_chip * @lock: synchronization lock to prevent I/O race conditions + * @ack_lock: synchronization lock to prevent IRQ handler race conditions * @irq_mask: input bits affected by interrupts * @base: base port address of the GPIO device * @extent: extent of port address region of the GPIO device @@ -45,6 +46,7 @@ MODULE_PARM_DESC(idi_48_irq, "ACCES 104-IDI-48 interrupt line number"); struct idi_48_gpio { struct gpio_chip chip; spinlock_t lock; + spinlock_t ack_lock; unsigned char irq_mask[6]; unsigned base; unsigned extent; @@ -89,15 +91,6 @@ static int idi_48_gpio_get(struct gpio_chip *chip, unsigned offset) static void idi_48_irq_ack(struct irq_data *data) { - struct gpio_chip *chip = irq_data_get_irq_chip_data(data); - struct idi_48_gpio *const idi48gpio = to_idi48gpio(chip); - unsigned long flags; - - spin_lock_irqsave(&idi48gpio->lock, flags); - - inb(idi48gpio->base + 7); - - spin_unlock_irqrestore(&idi48gpio->lock, flags); } static void idi_48_irq_mask(struct irq_data *data) @@ -192,6 +185,8 @@ static irqreturn_t idi_48_irq_handler(int irq, void *dev_id) unsigned long gpio; struct gpio_chip *const chip = &idi48gpio->chip; + spin_lock(&idi48gpio->ack_lock); + spin_lock(&idi48gpio->lock); cos_status = inb(idi48gpio->base + 7); @@ -199,8 +194,10 @@ static irqreturn_t idi_48_irq_handler(int irq, void *dev_id) spin_unlock(&idi48gpio->lock); /* IRQ Status (bit 6) is active low (0 = IRQ generated by device) */ - if (cos_status & BIT(6)) + if (cos_status & BIT(6)) { + spin_unlock(&idi48gpio->ack_lock); return IRQ_NONE; + } /* Bit 0-5 indicate which Change-Of-State boundary triggered the IRQ */ cos_status &= 0x3F; @@ -216,6 +213,8 @@ static irqreturn_t idi_48_irq_handler(int irq, void *dev_id) } } + spin_unlock(&idi48gpio->ack_lock); + return IRQ_HANDLED; } |