Skip to content

Commit 9a6ed4e

Browse files
TGSPgregkh
authored andcommitted
gpio: dwapb: mask/unmask IRQ when disable/enale it
commit 1cc3542 upstream. In the hardware implementation of the I2C HID driver based on DesignWare GPIO IRQ chip, when the user continues to use the I2C HID device in the suspend process, the I2C HID interrupt will be masked after the resume process is finished. This is because the disable_irq()/enable_irq() of the DesignWare GPIO driver does not synchronize the IRQ mask register state. In normal use of the I2C HID procedure, the GPIO IRQ irq_mask()/irq_unmask() functions are called in pairs. In case of an exception, i2c_hid_core_suspend() calls disable_irq() to disable the GPIO IRQ. With low probability, this causes irq_unmask() to not be called, which causes the GPIO IRQ to be masked and not unmasked in enable_irq(), raising an exception. Add synchronization to the masked register state in the dwapb_irq_enable()/dwapb_irq_disable() function. mask the GPIO IRQ before disabling it. After enabling the GPIO IRQ, unmask the IRQ. Fixes: 7779b34 ("gpio: add a driver for the Synopsys DesignWare APB GPIO block") Cc: stable@kernel.org Co-developed-by: Riwen Lu <luriwen@kylinos.cn> Signed-off-by: Riwen Lu <luriwen@kylinos.cn> Signed-off-by: xiongxin <xiongxin@kylinos.cn> Acked-by: Serge Semin <fancer.lancer@gmail.com> Reviewed-by: Andy Shevchenko <andy@kernel.org> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent add8973 commit 9a6ed4e

1 file changed

Lines changed: 8 additions & 4 deletions

File tree

drivers/gpio/gpio-dwapb.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -283,26 +283,30 @@ static void dwapb_irq_enable(struct irq_data *d)
283283
{
284284
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
285285
struct dwapb_gpio *gpio = to_dwapb_gpio(gc);
286+
irq_hw_number_t hwirq = irqd_to_hwirq(d);
286287
unsigned long flags;
287288
u32 val;
288289

289290
raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
290-
val = dwapb_read(gpio, GPIO_INTEN);
291-
val |= BIT(irqd_to_hwirq(d));
291+
val = dwapb_read(gpio, GPIO_INTEN) | BIT(hwirq);
292292
dwapb_write(gpio, GPIO_INTEN, val);
293+
val = dwapb_read(gpio, GPIO_INTMASK) & ~BIT(hwirq);
294+
dwapb_write(gpio, GPIO_INTMASK, val);
293295
raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
294296
}
295297

296298
static void dwapb_irq_disable(struct irq_data *d)
297299
{
298300
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
299301
struct dwapb_gpio *gpio = to_dwapb_gpio(gc);
302+
irq_hw_number_t hwirq = irqd_to_hwirq(d);
300303
unsigned long flags;
301304
u32 val;
302305

303306
raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
304-
val = dwapb_read(gpio, GPIO_INTEN);
305-
val &= ~BIT(irqd_to_hwirq(d));
307+
val = dwapb_read(gpio, GPIO_INTMASK) | BIT(hwirq);
308+
dwapb_write(gpio, GPIO_INTMASK, val);
309+
val = dwapb_read(gpio, GPIO_INTEN) & ~BIT(hwirq);
306310
dwapb_write(gpio, GPIO_INTEN, val);
307311
raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
308312
}

0 commit comments

Comments
 (0)