staging:iio:ad7780: Use common Sigma Delta library

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>
This commit is contained in:
Lars-Peter Clausen 2012-08-10 17:36:00 +01:00 коммит произвёл Jonathan Cameron
Родитель af3008485e
Коммит 32e0e7e08c
2 изменённых файлов: 73 добавлений и 118 удалений

Просмотреть файл

@ -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).

Просмотреть файл

@ -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;
return container_of(sd, struct ad7780_state, sd);
}
spi_bus_lock(st->spi->master);
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;
enable_irq(st->spi->irq);
st->done = false;
gpio_set_value(st->pdata->gpio_pdrst, 1);
switch (mode) {
case AD_SD_MODE_SINGLE:
case AD_SD_MODE_CONTINUOUS:
val = 1;
break;
default:
val = 0;
break;
}
ret = wait_event_interruptible(st->wq_data_avail, st->done);
disable_irq_nosync(st->spi->irq);
if (ret)
goto out;
gpio_set_value(st->powerdown_gpio, val);
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);
return ret;
return 0;
}
static int ad7780_read_raw(struct iio_dev *indio_dev,
@ -89,87 +85,55 @@ 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 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,
},
},
},
[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,
},
},
},
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,
};
/**
* 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 ad7780_chip_info ad7780_chip_info_tbl[] = {
[ID_AD7780] = {
.channel = AD_SD_CHANNEL(1, 0, 0, 24, 32, 8),
},
[ID_AD7781] = {
.channel = AD_SD_CHANNEL(1, 0, 0, 20, 32, 12),
},
};
static const struct iio_info ad7780_info = {
@ -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);