diff options
| -rw-r--r-- | drivers/mfd/wm831x-core.c | 65 |
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 | */ |
| 323 | int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input) | 323 | int 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); |
