Commit ca7a71824ac957b1b9d3322656c05aad38d7275c
Committed by
Samuel Ortiz
1 parent
24c3047095
Exists in
master
and in
38 other branches
mfd: Fix bus lock interaction for WM831x IRQ set_type() operation
The WM831x IRQ set_type() operation is doing a direct register write when called but since set_type() is called with the bus lock held this isn't legal and could cause deadlocks in the IRQ core. Fix this by posting the updates into an array and syncing in the bus_sync_unlock() callback. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Showing 2 changed files with 22 additions and 6 deletions Side-by-side Diff
drivers/mfd/wm831x-irq.c
... | ... | @@ -348,6 +348,15 @@ |
348 | 348 | struct wm831x *wm831x = irq_data_get_irq_chip_data(data); |
349 | 349 | int i; |
350 | 350 | |
351 | + for (i = 0; i < ARRAY_SIZE(wm831x->gpio_update); i++) { | |
352 | + if (wm831x->gpio_update[i]) { | |
353 | + wm831x_set_bits(wm831x, WM831X_GPIO1_CONTROL + i, | |
354 | + WM831X_GPN_INT_MODE | WM831X_GPN_POL, | |
355 | + wm831x->gpio_update[i]); | |
356 | + wm831x->gpio_update[i] = 0; | |
357 | + } | |
358 | + } | |
359 | + | |
351 | 360 | for (i = 0; i < ARRAY_SIZE(wm831x->irq_masks_cur); i++) { |
352 | 361 | /* If there's been a change in the mask write it back |
353 | 362 | * to the hardware. */ |
... | ... | @@ -387,7 +396,7 @@ |
387 | 396 | static int wm831x_irq_set_type(struct irq_data *data, unsigned int type) |
388 | 397 | { |
389 | 398 | struct wm831x *wm831x = irq_data_get_irq_chip_data(data); |
390 | - int val, irq; | |
399 | + int irq; | |
391 | 400 | |
392 | 401 | irq = data->irq - wm831x->irq_base; |
393 | 402 | |
394 | 403 | |
395 | 404 | |
396 | 405 | |
397 | 406 | |
... | ... | @@ -399,22 +408,25 @@ |
399 | 408 | return -EINVAL; |
400 | 409 | } |
401 | 410 | |
411 | + /* We set the high bit to flag that we need an update; don't | |
412 | + * do the update here as we can be called with the bus lock | |
413 | + * held. | |
414 | + */ | |
402 | 415 | switch (type) { |
403 | 416 | case IRQ_TYPE_EDGE_BOTH: |
404 | - val = WM831X_GPN_INT_MODE; | |
417 | + wm831x->gpio_update[irq] = 0x10000 | WM831X_GPN_INT_MODE; | |
405 | 418 | break; |
406 | 419 | case IRQ_TYPE_EDGE_RISING: |
407 | - val = WM831X_GPN_POL; | |
420 | + wm831x->gpio_update[irq] = 0x10000 | WM831X_GPN_POL; | |
408 | 421 | break; |
409 | 422 | case IRQ_TYPE_EDGE_FALLING: |
410 | - val = 0; | |
423 | + wm831x->gpio_update[irq] = 0x10000; | |
411 | 424 | break; |
412 | 425 | default: |
413 | 426 | return -EINVAL; |
414 | 427 | } |
415 | 428 | |
416 | - return wm831x_set_bits(wm831x, WM831X_GPIO1_CONTROL + irq, | |
417 | - WM831X_GPN_INT_MODE | WM831X_GPN_POL, val); | |
429 | + return 0; | |
418 | 430 | } |
419 | 431 | |
420 | 432 | static struct irq_chip wm831x_irq_chip = { |
include/linux/mfd/wm831x/core.h
... | ... | @@ -237,6 +237,7 @@ |
237 | 237 | struct regulator_dev; |
238 | 238 | |
239 | 239 | #define WM831X_NUM_IRQ_REGS 5 |
240 | +#define WM831X_NUM_GPIO_REGS 16 | |
240 | 241 | |
241 | 242 | enum wm831x_parent { |
242 | 243 | WM8310 = 0x8310, |
... | ... | @@ -271,6 +272,9 @@ |
271 | 272 | unsigned charger_irq_wake:1; /* Are charger IRQs a wake source? */ |
272 | 273 | |
273 | 274 | int num_gpio; |
275 | + | |
276 | + /* Used by the interrupt controller code to post writes */ | |
277 | + int gpio_update[WM831X_NUM_GPIO_REGS]; | |
274 | 278 | |
275 | 279 | struct mutex auxadc_lock; |
276 | 280 | struct completion auxadc_done; |