Skip to content

Commit

Permalink
mfd: Use completion interrupt for WM831x AUXADC
Browse files Browse the repository at this point in the history
Use the completion interrupt generated by the device rather than
polling for conversions to complete. As a backup we still check
the status of the AUXADC if we don't get a completion, mostly for
systems that don't have the WM831x interrupt infrastructure hooked
up.

Also reduce the timeout for completion of conversions to 5ms from
the previous 10ms, the lower timeout should be sufficient.

Signed-off-by: Mark Brown <[email protected]>
Signed-off-by: Samuel Ortiz <[email protected]>
  • Loading branch information
broonie authored and Samuel Ortiz committed Mar 7, 2010
1 parent d19663a commit 473fe73
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 7 deletions.
36 changes: 29 additions & 7 deletions drivers/mfd/wm831x-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,6 @@ EXPORT_SYMBOL_GPL(wm831x_set_bits);
*/
int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input)
{
int tries = 10;
int ret, src;

mutex_lock(&wm831x->auxadc_lock);
Expand Down Expand Up @@ -349,13 +348,14 @@ int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input)
goto disable;
}

do {
msleep(1);
/* Ignore the result to allow us to soldier on without IRQ hookup */
wait_for_completion_timeout(&wm831x->auxadc_done, msecs_to_jiffies(5));

ret = wm831x_reg_read(wm831x, WM831X_AUXADC_CONTROL);
if (ret < 0)
ret = WM831X_AUX_CVT_ENA;
} while ((ret & WM831X_AUX_CVT_ENA) && --tries);
ret = wm831x_reg_read(wm831x, WM831X_AUXADC_CONTROL);
if (ret < 0) {
dev_err(wm831x->dev, "AUXADC status read failed: %d\n", ret);
goto disable;
}

if (ret & WM831X_AUX_CVT_ENA) {
dev_err(wm831x->dev, "Timed out reading AUXADC\n");
Expand Down Expand Up @@ -390,6 +390,15 @@ int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input)
}
EXPORT_SYMBOL_GPL(wm831x_auxadc_read);

static irqreturn_t wm831x_auxadc_irq(int irq, void *irq_data)
{
struct wm831x *wm831x = irq_data;

complete(&wm831x->auxadc_done);

return IRQ_HANDLED;
}

/**
* wm831x_auxadc_read_uv: Read a voltage from the WM831x AUXADC
*
Expand Down Expand Up @@ -1411,6 +1420,7 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
mutex_init(&wm831x->io_lock);
mutex_init(&wm831x->key_lock);
mutex_init(&wm831x->auxadc_lock);
init_completion(&wm831x->auxadc_done);
dev_set_drvdata(wm831x->dev, wm831x);

ret = wm831x_reg_read(wm831x, WM831X_PARENT_ID);
Expand Down Expand Up @@ -1523,6 +1533,16 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
if (ret != 0)
goto err;

if (wm831x->irq_base) {
ret = request_threaded_irq(wm831x->irq_base +
WM831X_IRQ_AUXADC_DATA,
NULL, wm831x_auxadc_irq, 0,
"auxadc", wm831x);
if (ret < 0)
dev_err(wm831x->dev, "AUXADC IRQ request failed: %d\n",
ret);
}

/* The core device is up, instantiate the subdevices. */
switch (parent) {
case WM8310:
Expand Down Expand Up @@ -1593,6 +1613,8 @@ static void wm831x_device_exit(struct wm831x *wm831x)
{
wm831x_otp_exit(wm831x);
mfd_remove_devices(wm831x->dev);
if (wm831x->irq_base)
free_irq(wm831x->irq_base + WM831X_IRQ_AUXADC_DATA, wm831x);
wm831x_irq_exit(wm831x);
kfree(wm831x);
}
Expand Down
2 changes: 2 additions & 0 deletions include/linux/mfd/wm831x/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#ifndef __MFD_WM831X_CORE_H__
#define __MFD_WM831X_CORE_H__

#include <linux/completion.h>
#include <linux/interrupt.h>

/*
Expand Down Expand Up @@ -261,6 +262,7 @@ struct wm831x {
int num_gpio;

struct mutex auxadc_lock;
struct completion auxadc_done;

/* The WM831x has a security key blocking access to certain
* registers. The mutex is taken by the accessors for locking
Expand Down

0 comments on commit 473fe73

Please sign in to comment.