Skip to content

Commit 6537886

Browse files
mhennerichlinusw
authored andcommitted
gpio: adp5588: Fix sleep-in-atomic-context bug
This fixes: [BUG] gpio: gpio-adp5588: A possible sleep-in-atomic-context bug in adp5588_gpio_write() [BUG] gpio: gpio-adp5588: A possible sleep-in-atomic-context bug in adp5588_gpio_direction_input() Reported-by: Jia-Ju Bai <baijiaju1990@gmail.com> Signed-off-by: Michael Hennerich <michael.hennerich@analog.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
1 parent 5b394b2 commit 6537886

File tree

1 file changed

+20
-4
lines changed

1 file changed

+20
-4
lines changed

drivers/gpio/gpio-adp5588.c

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ struct adp5588_gpio {
4141
uint8_t int_en[3];
4242
uint8_t irq_mask[3];
4343
uint8_t irq_stat[3];
44+
uint8_t int_input_en[3];
45+
uint8_t int_lvl_cached[3];
4446
};
4547

4648
static int adp5588_gpio_read(struct i2c_client *client, u8 reg)
@@ -173,12 +175,28 @@ static void adp5588_irq_bus_sync_unlock(struct irq_data *d)
173175
struct adp5588_gpio *dev = irq_data_get_irq_chip_data(d);
174176
int i;
175177

176-
for (i = 0; i <= ADP5588_BANK(ADP5588_MAXGPIO); i++)
178+
for (i = 0; i <= ADP5588_BANK(ADP5588_MAXGPIO); i++) {
179+
if (dev->int_input_en[i]) {
180+
mutex_lock(&dev->lock);
181+
dev->dir[i] &= ~dev->int_input_en[i];
182+
dev->int_input_en[i] = 0;
183+
adp5588_gpio_write(dev->client, GPIO_DIR1 + i,
184+
dev->dir[i]);
185+
mutex_unlock(&dev->lock);
186+
}
187+
188+
if (dev->int_lvl_cached[i] != dev->int_lvl[i]) {
189+
dev->int_lvl_cached[i] = dev->int_lvl[i];
190+
adp5588_gpio_write(dev->client, GPIO_INT_LVL1 + i,
191+
dev->int_lvl[i]);
192+
}
193+
177194
if (dev->int_en[i] ^ dev->irq_mask[i]) {
178195
dev->int_en[i] = dev->irq_mask[i];
179196
adp5588_gpio_write(dev->client, GPIO_INT_EN1 + i,
180197
dev->int_en[i]);
181198
}
199+
}
182200

183201
mutex_unlock(&dev->irq_lock);
184202
}
@@ -221,9 +239,7 @@ static int adp5588_irq_set_type(struct irq_data *d, unsigned int type)
221239
else
222240
return -EINVAL;
223241

224-
adp5588_gpio_direction_input(&dev->gpio_chip, gpio);
225-
adp5588_gpio_write(dev->client, GPIO_INT_LVL1 + bank,
226-
dev->int_lvl[bank]);
242+
dev->int_input_en[bank] |= bit;
227243

228244
return 0;
229245
}

0 commit comments

Comments
 (0)