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 | } |