Skip to content

Commit 1cc3542

Browse files
TGSPBartosz Golaszewski
authored andcommitted
gpio: dwapb: mask/unmask IRQ when disable/enale it
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>
1 parent 1d656bd commit 1cc3542

File tree

1 file changed

+8
-4
lines changed

1 file changed

+8
-4
lines changed

drivers/gpio/gpio-dwapb.c

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

288289
raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
289-
val = dwapb_read(gpio, GPIO_INTEN);
290-
val |= BIT(irqd_to_hwirq(d));
290+
val = dwapb_read(gpio, GPIO_INTEN) | BIT(hwirq);
291291
dwapb_write(gpio, GPIO_INTEN, val);
292+
val = dwapb_read(gpio, GPIO_INTMASK) & ~BIT(hwirq);
293+
dwapb_write(gpio, GPIO_INTMASK, val);
292294
raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
293295
}
294296

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

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

0 commit comments

Comments
 (0)