aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2011-06-02 14:18:47 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2011-07-31 17:28:19 -0400
commitca7a71824ac957b1b9d3322656c05aad38d7275c (patch)
treeff89c76b4cda114343c01f332aa28fb80095f3db /drivers/mfd
parent24c3047095fa3954f114bfff2e37b8fcbb216396 (diff)
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>
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/wm831x-irq.c24
1 files changed, 18 insertions, 6 deletions
diff --git a/drivers/mfd/wm831x-irq.c b/drivers/mfd/wm831x-irq.c
index 42b928ec891e..b23d8d5ee96c 100644
--- a/drivers/mfd/wm831x-irq.c
+++ b/drivers/mfd/wm831x-irq.c
@@ -348,6 +348,15 @@ static void wm831x_irq_sync_unlock(struct irq_data *data)
348 struct wm831x *wm831x = irq_data_get_irq_chip_data(data); 348 struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
349 int i; 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 for (i = 0; i < ARRAY_SIZE(wm831x->irq_masks_cur); i++) { 360 for (i = 0; i < ARRAY_SIZE(wm831x->irq_masks_cur); i++) {
352 /* If there's been a change in the mask write it back 361 /* If there's been a change in the mask write it back
353 * to the hardware. */ 362 * to the hardware. */
@@ -387,7 +396,7 @@ static void wm831x_irq_disable(struct irq_data *data)
387static int wm831x_irq_set_type(struct irq_data *data, unsigned int type) 396static int wm831x_irq_set_type(struct irq_data *data, unsigned int type)
388{ 397{
389 struct wm831x *wm831x = irq_data_get_irq_chip_data(data); 398 struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
390 int val, irq; 399 int irq;
391 400
392 irq = data->irq - wm831x->irq_base; 401 irq = data->irq - wm831x->irq_base;
393 402
@@ -399,22 +408,25 @@ static int wm831x_irq_set_type(struct irq_data *data, unsigned int type)
399 return -EINVAL; 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 switch (type) { 415 switch (type) {
403 case IRQ_TYPE_EDGE_BOTH: 416 case IRQ_TYPE_EDGE_BOTH:
404 val = WM831X_GPN_INT_MODE; 417 wm831x->gpio_update[irq] = 0x10000 | WM831X_GPN_INT_MODE;
405 break; 418 break;
406 case IRQ_TYPE_EDGE_RISING: 419 case IRQ_TYPE_EDGE_RISING:
407 val = WM831X_GPN_POL; 420 wm831x->gpio_update[irq] = 0x10000 | WM831X_GPN_POL;
408 break; 421 break;
409 case IRQ_TYPE_EDGE_FALLING: 422 case IRQ_TYPE_EDGE_FALLING:
410 val = 0; 423 wm831x->gpio_update[irq] = 0x10000;
411 break; 424 break;
412 default: 425 default:
413 return -EINVAL; 426 return -EINVAL;
414 } 427 }
415 428
416 return wm831x_set_bits(wm831x, WM831X_GPIO1_CONTROL + irq, 429 return 0;
417 WM831X_GPN_INT_MODE | WM831X_GPN_POL, val);
418} 430}
419 431
420static struct irq_chip wm831x_irq_chip = { 432static struct irq_chip wm831x_irq_chip = {