diff options
| author | Michael Hennerich <michael.hennerich@analog.com> | 2018-08-13 09:57:44 -0400 |
|---|---|---|
| committer | Linus Walleij <linus.walleij@linaro.org> | 2018-08-29 04:54:38 -0400 |
| commit | 6537886cdc9a637711fd6da980dbb87c2c87c9aa (patch) | |
| tree | c9ea13144c1a80816de4d8ce6a2b9308eaaf4c13 | |
| parent | 5b394b2ddf0347bef56e50c69a58773c94343ff3 (diff) | |
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>
| -rw-r--r-- | drivers/gpio/gpio-adp5588.c | 24 |
1 files changed, 20 insertions, 4 deletions
diff --git a/drivers/gpio/gpio-adp5588.c b/drivers/gpio/gpio-adp5588.c index 3530ccd17e04..da9781a2ef4a 100644 --- a/drivers/gpio/gpio-adp5588.c +++ b/drivers/gpio/gpio-adp5588.c | |||
| @@ -41,6 +41,8 @@ struct adp5588_gpio { | |||
| 41 | uint8_t int_en[3]; | 41 | uint8_t int_en[3]; |
| 42 | uint8_t irq_mask[3]; | 42 | uint8_t irq_mask[3]; |
| 43 | uint8_t irq_stat[3]; | 43 | uint8_t irq_stat[3]; |
| 44 | uint8_t int_input_en[3]; | ||
| 45 | uint8_t int_lvl_cached[3]; | ||
| 44 | }; | 46 | }; |
| 45 | 47 | ||
| 46 | static int adp5588_gpio_read(struct i2c_client *client, u8 reg) | 48 | 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) | |||
| 173 | struct adp5588_gpio *dev = irq_data_get_irq_chip_data(d); | 175 | struct adp5588_gpio *dev = irq_data_get_irq_chip_data(d); |
| 174 | int i; | 176 | int i; |
| 175 | 177 | ||
| 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 | |||
| 177 | if (dev->int_en[i] ^ dev->irq_mask[i]) { | 194 | if (dev->int_en[i] ^ dev->irq_mask[i]) { |
| 178 | dev->int_en[i] = dev->irq_mask[i]; | 195 | dev->int_en[i] = dev->irq_mask[i]; |
| 179 | adp5588_gpio_write(dev->client, GPIO_INT_EN1 + i, | 196 | adp5588_gpio_write(dev->client, GPIO_INT_EN1 + i, |
| 180 | dev->int_en[i]); | 197 | dev->int_en[i]); |
| 181 | } | 198 | } |
| 199 | } | ||
| 182 | 200 | ||
| 183 | mutex_unlock(&dev->irq_lock); | 201 | mutex_unlock(&dev->irq_lock); |
| 184 | } | 202 | } |
| @@ -221,9 +239,7 @@ static int adp5588_irq_set_type(struct irq_data *d, unsigned int type) | |||
| 221 | else | 239 | else |
| 222 | return -EINVAL; | 240 | return -EINVAL; |
| 223 | 241 | ||
| 224 | adp5588_gpio_direction_input(&dev->gpio_chip, gpio); | 242 | dev->int_input_en[bank] |= bit; |
| 225 | adp5588_gpio_write(dev->client, GPIO_INT_LVL1 + bank, | ||
| 226 | dev->int_lvl[bank]); | ||
| 227 | 243 | ||
| 228 | return 0; | 244 | return 0; |
| 229 | } | 245 | } |
