summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2011-06-02 19:18:52 +0100
committerSamuel Ortiz <sameo@linux.intel.com>2011-07-31 23:28:20 +0200
commitc1a82780b41e78f31636c49279ce940afe60a453 (patch)
treea8769c072230d413c53fbfffa46d466965c8510f
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>
-rw-r--r--drivers/mfd/wm831x-core.c47
-rw-r--r--include/linux/mfd/wm831x/core.h1
2 files changed, 32 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)
goto disable;
}
}
+
+ ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA);
+ if (ret < 0) {
+ dev_err(wm831x->dev,
+ "Failed to read AUXADC data: %d\n", ret);
+ goto disable;
+ }
+
+ wm831x->auxadc_data = ret;
+
} else {
/* If we are using interrupts then wait for the
* interrupt to complete. Use an extremely long
@@ -390,23 +400,18 @@ int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input)
}
}
- ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA);
- if (ret < 0) {
- dev_err(wm831x->dev, "Failed to read AUXADC data: %d\n", ret);
+ src = ((wm831x->auxadc_data & WM831X_AUX_DATA_SRC_MASK)
+ >> WM831X_AUX_DATA_SRC_SHIFT) - 1;
+
+ if (src == 14)
+ src = WM831X_AUX_CAL;
+
+ if (src != input) {
+ dev_err(wm831x->dev, "Data from source %d not %d\n",
+ src, input);
+ ret = -EINVAL;
} else {
- src = ((ret & WM831X_AUX_DATA_SRC_MASK)
- >> WM831X_AUX_DATA_SRC_SHIFT) - 1;
-
- if (src == 14)
- src = WM831X_AUX_CAL;
-
- if (src != input) {
- dev_err(wm831x->dev, "Data from source %d not %d\n",
- src, input);
- ret = -EINVAL;
- } else {
- ret &= WM831X_AUX_DATA_MASK;
- }
+ ret = wm831x->auxadc_data & WM831X_AUX_DATA_MASK;
}
disable:
@@ -420,6 +425,16 @@ EXPORT_SYMBOL_GPL(wm831x_auxadc_read);
static irqreturn_t wm831x_auxadc_irq(int irq, void *irq_data)
{
struct wm831x *wm831x = irq_data;
+ int ret;
+
+ ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA);
+ if (ret < 0) {
+ dev_err(wm831x->dev,
+ "Failed to read AUXADC data: %d\n", ret);
+ wm831x->auxadc_data = 0xffff;
+ } else {
+ wm831x->auxadc_data = ret;
+ }
complete(&wm831x->auxadc_done);
diff --git a/include/linux/mfd/wm831x/core.h b/include/linux/mfd/wm831x/core.h
index 9564cf315276..592e4fd6ab3f 100644
--- a/include/linux/mfd/wm831x/core.h
+++ b/include/linux/mfd/wm831x/core.h
@@ -278,6 +278,7 @@ struct wm831x {
struct mutex auxadc_lock;
struct completion auxadc_done;
+ u16 auxadc_data;
/* The WM831x has a security key blocking access to certain
* registers. The mutex is taken by the accessors for locking