Commit ca7a71824ac957b1b9d3322656c05aad38d7275c

Authored by Mark Brown
Committed by Samuel Ortiz
1 parent 24c3047095

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;