aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Hennerich <michael.hennerich@analog.com>2018-08-13 09:57:44 -0400
committerLinus Walleij <linus.walleij@linaro.org>2018-08-29 04:54:38 -0400
commit6537886cdc9a637711fd6da980dbb87c2c87c9aa (patch)
treec9ea13144c1a80816de4d8ce6a2b9308eaaf4c13
parent5b394b2ddf0347bef56e50c69a58773c94343ff3 (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.c24
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
46static int adp5588_gpio_read(struct i2c_client *client, u8 reg) 48static 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}