Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6537886c authored by Michael Hennerich's avatar Michael Hennerich Committed by Linus Walleij
Browse files

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: default avatarJia-Ju Bai <baijiaju1990@gmail.com>
Signed-off-by: default avatarMichael Hennerich <michael.hennerich@analog.com>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent 5b394b2d
Loading
Loading
Loading
Loading
+20 −4
Original line number Diff line number Diff line
@@ -41,6 +41,8 @@ struct adp5588_gpio {
	uint8_t int_en[3];
	uint8_t irq_mask[3];
	uint8_t irq_stat[3];
	uint8_t int_input_en[3];
	uint8_t int_lvl_cached[3];
};

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)
	struct adp5588_gpio *dev = irq_data_get_irq_chip_data(d);
	int i;

	for (i = 0; i <= ADP5588_BANK(ADP5588_MAXGPIO); i++)
	for (i = 0; i <= ADP5588_BANK(ADP5588_MAXGPIO); i++) {
		if (dev->int_input_en[i]) {
			mutex_lock(&dev->lock);
			dev->dir[i] &= ~dev->int_input_en[i];
			dev->int_input_en[i] = 0;
			adp5588_gpio_write(dev->client, GPIO_DIR1 + i,
					   dev->dir[i]);
			mutex_unlock(&dev->lock);
		}

		if (dev->int_lvl_cached[i] != dev->int_lvl[i]) {
			dev->int_lvl_cached[i] = dev->int_lvl[i];
			adp5588_gpio_write(dev->client, GPIO_INT_LVL1 + i,
					   dev->int_lvl[i]);
		}

		if (dev->int_en[i] ^ dev->irq_mask[i]) {
			dev->int_en[i] = dev->irq_mask[i];
			adp5588_gpio_write(dev->client, GPIO_INT_EN1 + i,
					   dev->int_en[i]);
		}
	}

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

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

	return 0;
}