mfd: Use completion interrupt for WM835x AUXADC
authorMark Brown <broonie@opensource.wolfsonmicro.com>
Tue, 23 Feb 2010 11:08:05 +0000 (11:08 +0000)
committerSamuel Ortiz <sameo@linux.intel.com>
Sun, 7 Mar 2010 21:17:33 +0000 (22:17 +0100)
Use the completion interrupt generated by the device rather than
polling for conversions to complete. As a backup we still check
the state of the AUXADC if we don't get a completion, mostly for
systems that don't have the WM8350 interrupt infrastructure hooked
up.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
drivers/mfd/wm8350-core.c
include/linux/mfd/wm8350/core.h

index 9a970bd6877587f9a40f01736280dd262c7ea32f..bd75807d5302e7f60649bd1b133ee1c75d5e77ba 100644 (file)
@@ -339,7 +339,6 @@ EXPORT_SYMBOL_GPL(wm8350_reg_unlock);
 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;
@@ -363,12 +362,13 @@ int wm8350_read_auxadc(struct wm8350 *wm8350, int channel, int scale, int vref)
        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 ((reg & WM8350_AUXADC_POLL) && --tries);
+       /* We ignore the result of the completion and just check for a
+        * conversion result, allowing us to soldier on if the IRQ
+        * infrastructure is not set up for the chip. */
+       wait_for_completion_timeout(&wm8350->auxadc_done, msecs_to_jiffies(5));
 
-       if (!tries)
+       reg = wm8350_reg_read(wm8350, WM8350_DIGITISER_CONTROL_1);
+       if (reg & WM8350_AUXADC_POLL)
                dev_err(wm8350->dev, "adc chn %d read timeout\n", channel);
        else
                result = wm8350_reg_read(wm8350,
@@ -385,6 +385,15 @@ int wm8350_read_auxadc(struct wm8350 *wm8350, int channel, int scale, int vref)
 }
 EXPORT_SYMBOL_GPL(wm8350_read_auxadc);
 
+static irqreturn_t wm8350_auxadc_irq(int irq, void *irq_data)
+{
+       struct wm8350 *wm8350 = irq_data;
+
+       complete(&wm8350->auxadc_done);
+
+       return IRQ_HANDLED;
+}
+
 /*
  * Cache is always host endian.
  */
@@ -682,11 +691,22 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq,
        }
 
        mutex_init(&wm8350->auxadc_mutex);
+       init_completion(&wm8350->auxadc_done);
 
        ret = wm8350_irq_init(wm8350, irq, pdata);
        if (ret < 0)
                goto err;
 
+       if (wm8350->irq_base) {
+               ret = request_threaded_irq(wm8350->irq_base +
+                                          WM8350_IRQ_AUXADC_DATARDY,
+                                          NULL, wm8350_auxadc_irq, 0,
+                                          "auxadc", wm8350);
+               if (ret < 0)
+                       dev_warn(wm8350->dev,
+                                "Failed to request AUXADC IRQ: %d\n", ret);
+       }
+
        if (pdata && pdata->init) {
                ret = pdata->init(wm8350);
                if (ret != 0) {
@@ -736,6 +756,9 @@ void wm8350_device_exit(struct wm8350 *wm8350)
        platform_device_unregister(wm8350->gpio.pdev);
        platform_device_unregister(wm8350->codec.pdev);
 
+       if (wm8350->irq_base)
+               free_irq(wm8350->irq_base + WM8350_IRQ_AUXADC_DATARDY, wm8350);
+
        wm8350_irq_exit(wm8350);
 
        kfree(wm8350->reg_cache);
index fae08aa654131997c5b4ea1a43dba3b81f634627..98fcc977e82be5acd0805d3474ef3e12f4b9fb3f 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/kernel.h>
 #include <linux/mutex.h>
 #include <linux/interrupt.h>
+#include <linux/completion.h>
 
 #include <linux/mfd/wm8350/audio.h>
 #include <linux/mfd/wm8350/gpio.h>
@@ -621,6 +622,7 @@ struct wm8350 {
        u16 *reg_cache;
 
        struct mutex auxadc_mutex;
+       struct completion auxadc_done;
 
        /* Interrupt handling */
        struct mutex irq_lock;