aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2011-06-02 14:18:52 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2011-07-31 17:28:20 -0400
commitc1a82780b41e78f31636c49279ce940afe60a453 (patch)
treea8769c072230d413c53fbfffa46d466965c8510f /drivers/mfd
parent5c05a8d1f0105ada3cb04be5b70686fc6b272619 (diff)
mfd: Read wm831x AUXADC conversion results before acknowledging interrupt
Ensure that there's no possibility of loosing an AUXADC interrupt by reading the conversion result in the IRQ handler when using interrupts. Otherwise it's possible that under very heavy load a new conversion could be initiated before the acknowledgement for a previous interrupt has happened. 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-core.c47
1 files changed, 31 insertions, 16 deletions
diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c
index 58f033b57efe..480abc18f9f3 100644
--- a/drivers/mfd/wm831x-core.c
+++ b/drivers/mfd/wm831x-core.c
@@ -376,6 +376,16 @@ int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input)
376 goto disable; 376 goto disable;
377 } 377 }
378 } 378 }
379
380 ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA);
381 if (ret < 0) {
382 dev_err(wm831x->dev,
383 "Failed to read AUXADC data: %d\n", ret);
384 goto disable;
385 }
386
387 wm831x->auxadc_data = ret;
388
379 } else { 389 } else {
380 /* If we are using interrupts then wait for the 390 /* If we are using interrupts then wait for the
381 * interrupt to complete. Use an extremely long 391 * interrupt to complete. Use an extremely long
@@ -390,23 +400,18 @@ int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input)
390 } 400 }
391 } 401 }
392 402
393 ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA); 403 src = ((wm831x->auxadc_data & WM831X_AUX_DATA_SRC_MASK)
394 if (ret < 0) { 404 >> WM831X_AUX_DATA_SRC_SHIFT) - 1;
395 dev_err(wm831x->dev, "Failed to read AUXADC data: %d\n", ret); 405
406 if (src == 14)
407 src = WM831X_AUX_CAL;
408
409 if (src != input) {
410 dev_err(wm831x->dev, "Data from source %d not %d\n",
411 src, input);
412 ret = -EINVAL;
396 } else { 413 } else {
397 src = ((ret & WM831X_AUX_DATA_SRC_MASK) 414 ret = wm831x->auxadc_data & WM831X_AUX_DATA_MASK;
398 >> WM831X_AUX_DATA_SRC_SHIFT) - 1;
399
400 if (src == 14)
401 src = WM831X_AUX_CAL;
402
403 if (src != input) {
404 dev_err(wm831x->dev, "Data from source %d not %d\n",
405 src, input);
406 ret = -EINVAL;
407 } else {
408 ret &= WM831X_AUX_DATA_MASK;
409 }
410 } 415 }
411 416
412disable: 417disable:
@@ -420,6 +425,16 @@ EXPORT_SYMBOL_GPL(wm831x_auxadc_read);
420static irqreturn_t wm831x_auxadc_irq(int irq, void *irq_data) 425static irqreturn_t wm831x_auxadc_irq(int irq, void *irq_data)
421{ 426{
422 struct wm831x *wm831x = irq_data; 427 struct wm831x *wm831x = irq_data;
428 int ret;
429
430 ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA);
431 if (ret < 0) {
432 dev_err(wm831x->dev,
433 "Failed to read AUXADC data: %d\n", ret);
434 wm831x->auxadc_data = 0xffff;
435 } else {
436 wm831x->auxadc_data = ret;
437 }
423 438
424 complete(&wm831x->auxadc_done); 439 complete(&wm831x->auxadc_done);
425 440