summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2008-11-08 01:10:21 +0100
committerSamuel Ortiz <samuel@sortiz.org>2009-01-04 12:17:38 +0100
commit67488526349d043372d141c054f4dc6313780b3c (patch)
tree22db1f6609edd7945fb000b4a9c48e86aadf3dfb
parent0c8a601678960fbcc1c1185a283d6d107575810b (diff)
downloadop-kernel-dev-67488526349d043372d141c054f4dc6313780b3c.zip
op-kernel-dev-67488526349d043372d141c054f4dc6313780b3c.tar.gz
mfd: Add AUXADC support for WM8350
The auxiliary ADC in the WM8350 is shared between several subdevices so access to it needs to be arbitrated by the core driver. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Samuel Ortiz <sameo@openedhand.com>
-rw-r--r--drivers/mfd/wm8350-core.c51
-rw-r--r--include/linux/mfd/wm8350/comparator.h8
-rw-r--r--include/linux/mfd/wm8350/core.h2
3 files changed, 60 insertions, 1 deletions
diff --git a/drivers/mfd/wm8350-core.c b/drivers/mfd/wm8350-core.c
index c013afd..60439bd 100644
--- a/drivers/mfd/wm8350-core.c
+++ b/drivers/mfd/wm8350-core.c
@@ -63,7 +63,6 @@
*/
static DEFINE_MUTEX(io_mutex);
static DEFINE_MUTEX(reg_lock_mutex);
-static DEFINE_MUTEX(auxadc_mutex);
/* Perform a physical read from the device.
*/
@@ -1082,6 +1081,55 @@ int wm8350_unmask_irq(struct wm8350 *wm8350, int irq)
}
EXPORT_SYMBOL_GPL(wm8350_unmask_irq);
+int wm8350_read_auxadc(struct wm8350 *wm8350, int channel, int scale, int vref)
+{
+ u16 reg, result = 0;
+ int tries = 5;
+
+ if (channel < WM8350_AUXADC_AUX1 || channel > WM8350_AUXADC_TEMP)
+ return -EINVAL;
+ if (channel >= WM8350_AUXADC_USB && channel <= WM8350_AUXADC_TEMP
+ && (scale != 0 || vref != 0))
+ return -EINVAL;
+
+ mutex_lock(&wm8350->auxadc_mutex);
+
+ /* Turn on the ADC */
+ reg = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_5);
+ wm8350_reg_write(wm8350, WM8350_POWER_MGMT_5, reg | WM8350_AUXADC_ENA);
+
+ if (scale || vref) {
+ reg = scale << 13;
+ reg |= vref << 12;
+ wm8350_reg_write(wm8350, WM8350_AUX1_READBACK + channel, reg);
+ }
+
+ reg = wm8350_reg_read(wm8350, WM8350_DIGITISER_CONTROL_1);
+ reg |= 1 << channel | WM8350_AUXADC_POLL;
+ wm8350_reg_write(wm8350, WM8350_DIGITISER_CONTROL_1, reg);
+
+ do {
+ schedule_timeout_interruptible(1);
+ reg = wm8350_reg_read(wm8350, WM8350_DIGITISER_CONTROL_1);
+ } while (tries-- && (reg & WM8350_AUXADC_POLL));
+
+ if (!tries)
+ dev_err(wm8350->dev, "adc chn %d read timeout\n", channel);
+ else
+ result = wm8350_reg_read(wm8350,
+ WM8350_AUX1_READBACK + channel);
+
+ /* Turn off the ADC */
+ reg = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_5);
+ wm8350_reg_write(wm8350, WM8350_POWER_MGMT_5,
+ reg & ~WM8350_AUXADC_ENA);
+
+ mutex_unlock(&wm8350->auxadc_mutex);
+
+ return result & WM8350_AUXADC_DATA1_MASK;
+}
+EXPORT_SYMBOL_GPL(wm8350_read_auxadc);
+
/*
* Cache is always host endian.
*/
@@ -1239,6 +1287,7 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq,
}
}
+ mutex_init(&wm8350->auxadc_mutex);
mutex_init(&wm8350->irq_mutex);
INIT_WORK(&wm8350->irq_work, wm8350_irq_worker);
if (irq) {
diff --git a/include/linux/mfd/wm8350/comparator.h b/include/linux/mfd/wm8350/comparator.h
index 0537886..54bc5d0 100644
--- a/include/linux/mfd/wm8350/comparator.h
+++ b/include/linux/mfd/wm8350/comparator.h
@@ -164,4 +164,12 @@
#define WM8350_AUXADC_BATT 6
#define WM8350_AUXADC_TEMP 7
+struct wm8350;
+
+/*
+ * AUX ADC Readback
+ */
+int wm8350_read_auxadc(struct wm8350 *wm8350, int channel, int scale,
+ int vref);
+
#endif
diff --git a/include/linux/mfd/wm8350/core.h b/include/linux/mfd/wm8350/core.h
index 9490ec1..cc19005 100644
--- a/include/linux/mfd/wm8350/core.h
+++ b/include/linux/mfd/wm8350/core.h
@@ -573,6 +573,8 @@ struct wm8350 {
void *src);
u16 *reg_cache;
+ struct mutex auxadc_mutex;
+
/* Interrupt handling */
struct work_struct irq_work;
struct mutex irq_mutex; /* IRQ table mutex */
OpenPOWER on IntegriCloud