staging:iio:ad7780: Use common Sigma Delta library
authorLars-Peter Clausen <lars@metafoo.de>
Fri, 10 Aug 2012 16:36:00 +0000 (17:36 +0100)
committerJonathan Cameron <jic23@kernel.org>
Mon, 27 Aug 2012 16:53:24 +0000 (17:53 +0100)
Convert the ad7780 driver to make use of the new common code for devices from
the Analog Devices Sigma Delta family.

As a bonus the ad7780 driver gains support for buffered mode. Although this is a
bit tricky. The ad7780 reports in the lower 4 unused bits of the data word the
internal gain used. The driver will update the scale attribute value depending
on the gain accordingly, but obviously this will only work if the gain does not
change while sampling. This is not perfect, but since we store the raw value in
the buffer an application which is aware of this can extract the gain factor
from the buffer as well an apply it accordingly.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
drivers/staging/iio/adc/Kconfig
drivers/staging/iio/adc/ad7780.c

index 845fb6c70ca340053c003cd5b0bfb1e85eeabb23..d0eb27be381c53135212afe0941b6c4d32ba9e63 100644 (file)
@@ -99,6 +99,7 @@ config AD7780
        tristate "Analog Devices AD7780 AD7781 ADC driver"
        depends on SPI
        depends on GPIOLIB
+       select AD_SIGMA_DELTA
        help
          Say yes here to build support for Analog Devices
          AD7780 and AD7781 SPI analog to digital converters (ADC).
index 19ee49c95de49725e4dfdb62c0e4805a9215cce4..853f8b16b4effca80908852eb7d1a7fe496d38ee 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
+#include <linux/iio/adc/ad_sigma_delta.h>
 
 #include "ad7780.h"
 
@@ -37,20 +38,13 @@ struct ad7780_chip_info {
 };
 
 struct ad7780_state {
-       struct spi_device               *spi;
        const struct ad7780_chip_info   *chip_info;
        struct regulator                *reg;
-       struct ad7780_platform_data     *pdata;
-       wait_queue_head_t               wq_data_avail;
-       bool                            done;
+       int                             powerdown_gpio;
+       unsigned int    gain;
        u16                             int_vref_mv;
-       struct spi_transfer             xfer;
-       struct spi_message              msg;
-       /*
-        * DMA (thus cache coherency maintenance) requires the
-        * transfer buffers to live in their own cache lines.
-        */
-       unsigned int                    data ____cacheline_aligned;
+
+       struct ad_sigma_delta sd;
 };
 
 enum ad7780_supported_device_ids {
@@ -58,28 +52,30 @@ enum ad7780_supported_device_ids {
        ID_AD7781,
 };
 
-static int ad7780_read(struct ad7780_state *st, int *val)
+static struct ad7780_state *ad_sigma_delta_to_ad7780(struct ad_sigma_delta *sd)
 {
-       int ret;
-
-       spi_bus_lock(st->spi->master);
-
-       enable_irq(st->spi->irq);
-       st->done = false;
-       gpio_set_value(st->pdata->gpio_pdrst, 1);
+       return container_of(sd, struct ad7780_state, sd);
+}
 
-       ret = wait_event_interruptible(st->wq_data_avail, st->done);
-       disable_irq_nosync(st->spi->irq);
-       if (ret)
-               goto out;
+static int ad7780_set_mode(struct ad_sigma_delta *sigma_delta,
+       enum ad_sigma_delta_mode mode)
+{
+       struct ad7780_state *st = ad_sigma_delta_to_ad7780(sigma_delta);
+       unsigned val;
+
+       switch (mode) {
+       case AD_SD_MODE_SINGLE:
+       case AD_SD_MODE_CONTINUOUS:
+               val = 1;
+               break;
+       default:
+               val = 0;
+               break;
+       }
 
-       ret = spi_sync_locked(st->spi, &st->msg);
-       *val = be32_to_cpu(st->data);
-out:
-       gpio_set_value(st->pdata->gpio_pdrst, 0);
-       spi_bus_unlock(st->spi->master);
+       gpio_set_value(st->powerdown_gpio, val);
 
-       return ret;
+       return 0;
 }
 
 static int ad7780_read_raw(struct iio_dev *indio_dev,
@@ -89,89 +85,57 @@ static int ad7780_read_raw(struct iio_dev *indio_dev,
                           long m)
 {
        struct ad7780_state *st = iio_priv(indio_dev);
-       struct iio_chan_spec channel = st->chip_info->channel;
-       int ret, smpl = 0;
        unsigned long scale_uv;
 
        switch (m) {
        case IIO_CHAN_INFO_RAW:
-               mutex_lock(&indio_dev->mlock);
-               ret = ad7780_read(st, &smpl);
-               mutex_unlock(&indio_dev->mlock);
-
-               if (ret < 0)
-                       return ret;
-
-               if ((smpl & AD7780_ERR) ||
-                       !((smpl & AD7780_PAT0) && !(smpl & AD7780_PAT1)))
-                       return -EIO;
-
-               *val = (smpl >> channel.scan_type.shift) &
-                       ((1 << (channel.scan_type.realbits)) - 1);
-               *val -= (1 << (channel.scan_type.realbits - 1));
-
-               if (!(smpl & AD7780_GAIN))
-                       *val *= 128;
-
-               return IIO_VAL_INT;
+               return ad_sigma_delta_single_conversion(indio_dev, chan, val);
        case IIO_CHAN_INFO_SCALE:
-               scale_uv = (st->int_vref_mv * 100000)
-                       >> (channel.scan_type.realbits - 1);
+               scale_uv = (st->int_vref_mv * 100000 * st->gain)
+                       >> (chan->scan_type.realbits - 1);
                *val =  scale_uv / 100000;
                *val2 = (scale_uv % 100000) * 10;
                return IIO_VAL_INT_PLUS_MICRO;
+       case IIO_CHAN_INFO_OFFSET:
+               *val -= (1 << (chan->scan_type.realbits - 1));
+               return IIO_VAL_INT;
        }
+
        return -EINVAL;
 }
 
+static int ad7780_postprocess_sample(struct ad_sigma_delta *sigma_delta,
+       unsigned int raw_sample)
+{
+       struct ad7780_state *st = ad_sigma_delta_to_ad7780(sigma_delta);
+
+       if ((raw_sample & AD7780_ERR) ||
+               !((raw_sample & AD7780_PAT0) && !(raw_sample & AD7780_PAT1)))
+               return -EIO;
+
+       if (raw_sample & AD7780_GAIN)
+               st->gain = 1;
+       else
+               st->gain = 128;
+
+       return 0;
+}
+
+static const struct ad_sigma_delta_info ad7780_sigma_delta_info = {
+       .set_mode = ad7780_set_mode,
+       .postprocess_sample = ad7780_postprocess_sample,
+       .has_registers = false,
+};
+
 static const struct ad7780_chip_info ad7780_chip_info_tbl[] = {
        [ID_AD7780] = {
-               .channel = {
-                       .type = IIO_VOLTAGE,
-                       .indexed = 1,
-                       .channel = 0,
-                       .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-                       IIO_CHAN_INFO_SCALE_SHARED_BIT |
-                       IIO_CHAN_INFO_OFFSET_SHARED_BIT,
-                       .scan_type = {
-                               .sign = 'u',
-                               .realbits = 24,
-                               .storagebits = 32,
-                               .shift = 8,
-                       },
-               },
+               .channel = AD_SD_CHANNEL(1, 0, 0, 24, 32, 8),
        },
        [ID_AD7781] = {
-               .channel = {
-                       .type = IIO_VOLTAGE,
-                       .indexed = 1,
-                       .channel = 0,
-                       .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-                       IIO_CHAN_INFO_SCALE_SHARED_BIT |
-                       IIO_CHAN_INFO_OFFSET_SHARED_BIT,
-                       .scan_type = {
-                               .sign = 'u',
-                               .realbits = 20,
-                               .storagebits = 32,
-                               .shift = 12,
-                       },
-               },
+               .channel = AD_SD_CHANNEL(1, 0, 0, 20, 32, 12),
        },
 };
 
-/**
- *  Interrupt handler
- */
-static irqreturn_t ad7780_interrupt(int irq, void *dev_id)
-{
-       struct ad7780_state *st = dev_id;
-
-       st->done = true;
-       wake_up_interruptible(&st->wq_data_avail);
-
-       return IRQ_HANDLED;
-};
-
 static const struct iio_info ad7780_info = {
        .read_raw = &ad7780_read_raw,
        .driver_module = THIS_MODULE,
@@ -194,6 +158,9 @@ static int __devinit ad7780_probe(struct spi_device *spi)
                return -ENOMEM;
 
        st = iio_priv(indio_dev);
+       st->gain = 1;
+
+       ad_sd_init(&st->sd, indio_dev, spi, &ad7780_sigma_delta_info);
 
        st->reg = regulator_get(&spi->dev, "vcc");
        if (!IS_ERR(st->reg)) {
@@ -207,7 +174,7 @@ static int __devinit ad7780_probe(struct spi_device *spi)
        st->chip_info =
                &ad7780_chip_info_tbl[spi_get_device_id(spi)->driver_data];
 
-       st->pdata = pdata;
+       st->powerdown_gpio = pdata->gpio_pdrst;
 
        if (pdata && pdata->vref_mv)
                st->int_vref_mv = pdata->vref_mv;
@@ -217,7 +184,6 @@ static int __devinit ad7780_probe(struct spi_device *spi)
                dev_warn(&spi->dev, "reference voltage unspecified\n");
 
        spi_set_drvdata(spi, indio_dev);
-       st->spi = spi;
 
        indio_dev->dev.parent = &spi->dev;
        indio_dev->name = spi_get_device_id(spi)->name;
@@ -226,40 +192,27 @@ static int __devinit ad7780_probe(struct spi_device *spi)
        indio_dev->num_channels = 1;
        indio_dev->info = &ad7780_info;
 
-       init_waitqueue_head(&st->wq_data_avail);
-
-       /* Setup default message */
-
-       st->xfer.rx_buf = &st->data;
-       st->xfer.len = st->chip_info->channel.scan_type.storagebits / 8;
-
-       spi_message_init(&st->msg);
-       spi_message_add_tail(&st->xfer, &st->msg);
-
-       ret = gpio_request_one(st->pdata->gpio_pdrst, GPIOF_OUT_INIT_LOW,
+       ret = gpio_request_one(pdata->gpio_pdrst, GPIOF_OUT_INIT_LOW,
                               "AD7780 /PDRST");
        if (ret) {
                dev_err(&spi->dev, "failed to request GPIO PDRST\n");
                goto error_disable_reg;
        }
 
-       ret = request_irq(spi->irq, ad7780_interrupt,
-               IRQF_TRIGGER_FALLING, spi_get_device_id(spi)->name, st);
+       ret = ad_sd_setup_buffer_and_trigger(indio_dev);
        if (ret)
                goto error_free_gpio;
 
-       disable_irq(spi->irq);
-
        ret = iio_device_register(indio_dev);
        if (ret)
-               goto error_free_irq;
+               goto error_cleanup_buffer_and_trigger;
 
        return 0;
 
-error_free_irq:
-       free_irq(spi->irq, st);
+error_cleanup_buffer_and_trigger:
+       ad_sd_cleanup_buffer_and_trigger(indio_dev);
 error_free_gpio:
-       gpio_free(st->pdata->gpio_pdrst);
+       gpio_free(pdata->gpio_pdrst);
 error_disable_reg:
        if (!IS_ERR(st->reg))
                regulator_disable(st->reg);
@@ -278,8 +231,9 @@ static int ad7780_remove(struct spi_device *spi)
        struct ad7780_state *st = iio_priv(indio_dev);
 
        iio_device_unregister(indio_dev);
-       free_irq(spi->irq, st);
-       gpio_free(st->pdata->gpio_pdrst);
+       ad_sd_cleanup_buffer_and_trigger(indio_dev);
+
+       gpio_free(st->powerdown_gpio);
        if (!IS_ERR(st->reg)) {
                regulator_disable(st->reg);
                regulator_put(st->reg);