aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2010-04-02 11:31:03 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2010-05-27 19:37:35 -0400
commit7cc1392aabc31d2af9bd3cc5febbd91977452181 (patch)
treea45186a5730335727373890e023ac2a60b2b237f /drivers
parent800e69fbd2faea906cabd10ddb77e36410f2bd9c (diff)
mfd: Improve WM831x AUXADC completion handling
Currently completion of WM831x AUXADC conversions is monitored by checking for convertor enable. Due to the mechanism used to ensure data corruption is avoided when reading AUXADC data there may under heavy I/O be a window where this bit has cleared but the conversion results have not been updated. Data availability is only guaranteed after the AUXADC data interrupt has been asserted. Avoid this by always using the interrupt to detect completion. If the chip IRQ is not set up then we poll the IRQ status register for up to 5ms. If it is set up then we rely on the data done interrupt with a vastly increased timeout, failing the conversion if the interrupt is not generated. This also saves a register read when using interrupts. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mfd/wm831x-core.c65
1 files changed, 48 insertions, 17 deletions
diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c
index f2ab025ad97a..da00ca9e0c71 100644
--- a/drivers/mfd/wm831x-core.c
+++ b/drivers/mfd/wm831x-core.c
@@ -322,7 +322,11 @@ EXPORT_SYMBOL_GPL(wm831x_set_bits);
322 */ 322 */
323int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input) 323int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input)
324{ 324{
325 int ret, src; 325 int ret, src, irq_masked, timeout;
326
327 /* Are we using the interrupt? */
328 irq_masked = wm831x_reg_read(wm831x, WM831X_INTERRUPT_STATUS_1_MASK);
329 irq_masked &= WM831X_AUXADC_DATA_EINT;
326 330
327 mutex_lock(&wm831x->auxadc_lock); 331 mutex_lock(&wm831x->auxadc_lock);
328 332
@@ -342,6 +346,9 @@ int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input)
342 goto out; 346 goto out;
343 } 347 }
344 348
349 /* Clear any notification from a very late arriving interrupt */
350 try_wait_for_completion(&wm831x->auxadc_done);
351
345 ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL, 352 ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL,
346 WM831X_AUX_CVT_ENA, WM831X_AUX_CVT_ENA); 353 WM831X_AUX_CVT_ENA, WM831X_AUX_CVT_ENA);
347 if (ret < 0) { 354 if (ret < 0) {
@@ -349,22 +356,46 @@ int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input)
349 goto disable; 356 goto disable;
350 } 357 }
351 358
352 /* If an interrupt arrived late clean up after it */ 359 if (irq_masked) {
353 try_wait_for_completion(&wm831x->auxadc_done); 360 /* If we're not using interrupts then poll the
354 361 * interrupt status register */
355 /* Ignore the result to allow us to soldier on without IRQ hookup */ 362 timeout = 5;
356 wait_for_completion_timeout(&wm831x->auxadc_done, msecs_to_jiffies(5)); 363 while (timeout) {
357 364 msleep(1);
358 ret = wm831x_reg_read(wm831x, WM831X_AUXADC_CONTROL); 365
359 if (ret < 0) { 366 ret = wm831x_reg_read(wm831x,
360 dev_err(wm831x->dev, "AUXADC status read failed: %d\n", ret); 367 WM831X_INTERRUPT_STATUS_1);
361 goto disable; 368 if (ret < 0) {
362 } 369 dev_err(wm831x->dev,
363 370 "ISR 1 read failed: %d\n", ret);
364 if (ret & WM831X_AUX_CVT_ENA) { 371 goto disable;
365 dev_err(wm831x->dev, "Timed out reading AUXADC\n"); 372 }
366 ret = -EBUSY; 373
367 goto disable; 374 /* Did it complete? */
375 if (ret & WM831X_AUXADC_DATA_EINT) {
376 wm831x_reg_write(wm831x,
377 WM831X_INTERRUPT_STATUS_1,
378 WM831X_AUXADC_DATA_EINT);
379 break;
380 } else {
381 dev_err(wm831x->dev,
382 "AUXADC conversion timeout\n");
383 ret = -EBUSY;
384 goto disable;
385 }
386 }
387 } else {
388 /* If we are using interrupts then wait for the
389 * interrupt to complete. Use an extremely long
390 * timeout to handle situations with heavy load where
391 * the notification of the interrupt may be delayed by
392 * threaded IRQ handling. */
393 if (!wait_for_completion_timeout(&wm831x->auxadc_done,
394 msecs_to_jiffies(500))) {
395 dev_err(wm831x->dev, "Timed out waiting for AUXADC\n");
396 ret = -EBUSY;
397 goto disable;
398 }
368 } 399 }
369 400
370 ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA); 401 ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA);