From: Jonathan Cameron <jic23@kernel.org>
To: Lars-Peter Clausen <lars@metafoo.de>
Cc: Jonathan Cameron <jic23@cam.ac.uk>,
linux-iio@vger.kernel.org, drivers@analog.com
Subject: Re: [PATCH 16/22] iio:adc: Add common code for ADI Sigma Delta devices
Date: Tue, 14 Aug 2012 21:19:29 +0100 [thread overview]
Message-ID: <502AB2D1.3060000@kernel.org> (raw)
In-Reply-To: <1344616596-8026-16-git-send-email-lars@metafoo.de>
On 08/10/2012 05:36 PM, Lars-Peter Clausen wrote:
> Most devices from the Analog Devices Sigma Delta family use a similar scheme for
> communication with the device. This includes register access, as well as trigger
> handling. But each device sub-family has different features and different
> register layouts (some even have no registers at all) and thus it is impractical
> to try to support all of the devices by the same driver. This patch adds a
> common base library for Sigma Delta converter devices. It will be used by
> individual drivers.
>
> This code is mostly based on the three existing Sigma Delta drivers the AD7192,
> AD7780 and AD7793, but has been improved for more robustness and flexibility.
>
Lars-Peter.
One obvious bug below. I've fixed this up too, please verify the fixed version
in the togreg-postfixes branch.
> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
> ---
> drivers/iio/adc/Kconfig | 5 +
> drivers/iio/adc/Makefile | 1 +
> drivers/iio/adc/ad_sigma_delta.c | 557 ++++++++++++++++++++++++++++++++
> include/linux/iio/adc/ad_sigma_delta.h | 173 ++++++++++
> 4 files changed, 736 insertions(+)
> create mode 100644 drivers/iio/adc/ad_sigma_delta.c
> create mode 100644 include/linux/iio/adc/ad_sigma_delta.h
>
> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
> index 8a78b4f..a2c5071 100644
> --- a/drivers/iio/adc/Kconfig
> +++ b/drivers/iio/adc/Kconfig
> @@ -3,6 +3,11 @@
> #
> menu "Analog to digital converters"
>
> +config AD_SIGMA_DELTA
> + tristate
> + select IIO_BUFFER
> + select IIO_TRIGGERED_BUFFER
> +
> config AD7266
> tristate "Analog Devices AD7265/AD7266 ADC driver"
> depends on SPI_MASTER
> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
> index 52eec25..5989356 100644
> --- a/drivers/iio/adc/Makefile
> +++ b/drivers/iio/adc/Makefile
> @@ -2,5 +2,6 @@
> # Makefile for IIO ADC drivers
> #
>
> +obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o
> obj-$(CONFIG_AD7266) += ad7266.o
> obj-$(CONFIG_AT91_ADC) += at91_adc.o
> diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c
> new file mode 100644
> index 0000000..555feb7
> --- /dev/null
> +++ b/drivers/iio/adc/ad_sigma_delta.c
> @@ -0,0 +1,557 @@
> +/*
> + * Support code for Analog Devices Sigma-Delta ADCs
> + *
> + * Copyright 2012 Analog Devices Inc.
> + * Author: Lars-Peter Clausen <lars@metafoo.de>
> + *
> + * Licensed under the GPL-2.
> + */
> +
> +#include <linux/interrupt.h>
> +#include <linux/device.h>
> +#include <linux/kernel.h>
> +#include <linux/slab.h>
> +#include <linux/spi/spi.h>
> +#include <linux/err.h>
> +#include <linux/module.h>
> +
> +#include <linux/iio/iio.h>
> +#include <linux/iio/sysfs.h>
> +#include <linux/iio/buffer.h>
> +#include <linux/iio/trigger.h>
> +#include <linux/iio/trigger_consumer.h>
> +#include <linux/iio/triggered_buffer.h>
> +#include <linux/iio/adc/ad_sigma_delta.h>
> +
> +#include <asm/unaligned.h>
> +
> +
> +#define AD_SD_COMM_CHAN_MASK 0x3
> +
> +#define AD_SD_REG_COMM 0x00
> +#define AD_SD_REG_DATA 0x03
> +
> +/**
> + * ad_sd_set_comm() - Set communications register
> + *
> + * @sigma_delta: The sigma delta device
> + * @comm: New value for the communications register
> + */
> +void ad_sd_set_comm(struct ad_sigma_delta *sigma_delta, uint8_t comm)
> +{
> + /* Some variants use the lower two bits of the communications register
> + * to select the channel */
> + sigma_delta->comm = comm & AD_SD_COMM_CHAN_MASK;
> +}
> +EXPORT_SYMBOL_GPL(ad_sd_set_comm);
> +
> +/**
> + * ad_sd_write_reg() - Write a register
> + *
> + * @sigma_delta: The sigma delta device
> + * @reg: Address of the register
> + * @size: Size of the register (0-3)
> + * @val: Value to write to the register
> + *
> + * Returns 0 on success, an error code otherwise.
> + **/
> +int ad_sd_write_reg(struct ad_sigma_delta *sigma_delta, unsigned int reg,
> + unsigned int size, unsigned int val)
> +{
> + uint8_t *data = sigma_delta->data;
> + struct spi_transfer t = {
> + .tx_buf = data,
> + .len = size + 1,
> + .cs_change = sigma_delta->bus_locked,
> + };
> + struct spi_message m;
> + int ret;
> +
> + data[0] = (reg << sigma_delta->info->addr_shift) | sigma_delta->comm;
> +
> + switch (size) {
> + case 3:
> + data[1] = val >> 16;
> + data[2] = val >> 8;
> + data[3] = val;
> + break;
> + case 2:
> + put_unaligned_be16(val, &data[1]);
> + break;
> + case 1:
> + data[1] = val;
> + break;
> + case 0:
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + spi_message_init(&m);
> + spi_message_add_tail(&t, &m);
> +
> + if (sigma_delta->bus_locked)
> + ret = spi_sync_locked(sigma_delta->spi, &m);
> + else
> + ret = spi_sync(sigma_delta->spi, &m);
> +
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(ad_sd_write_reg);
> +
> +static int ad_sd_read_reg_raw(struct ad_sigma_delta *sigma_delta,
> + unsigned int reg, unsigned int size, uint8_t *val)
> +{
> + uint8_t *data = sigma_delta->data;
> + int ret;
> + struct spi_transfer t[] = {
> + {
> + .tx_buf = data,
> + .len = 1,
> + }, {
> + .rx_buf = val,
> + .len = size,
> + .cs_change = sigma_delta->bus_locked,
> + },
> + };
> + struct spi_message m;
> +
> + spi_message_init(&m);
> +
> + if (sigma_delta->info->has_registers) {
> + data[0] = reg << sigma_delta->info->addr_shift;
> + data[0] |= sigma_delta->info->read_mask;
> + spi_message_add_tail(&t[0], &m);
> + }
> + spi_message_add_tail(&t[1], &m);
> +
> + if (sigma_delta->bus_locked)
> + ret = spi_sync_locked(sigma_delta->spi, &m);
> + else
> + ret = spi_sync(sigma_delta->spi, &m);
> +
> + return ret;
> +}
> +
> +/**
> + * ad_sd_read_reg() - Read a register
> + *
> + * @sigma_delta: The sigma delta device
> + * @reg: Address of the register
> + * @size: Size of the register (1-4)
> + * @val: Read value
> + *
> + * Returns 0 on success, an error code otherwise.
> + **/
> +int ad_sd_read_reg(struct ad_sigma_delta *sigma_delta,
> + unsigned int reg, unsigned int size, unsigned int *val)
> +{
> + int ret;
> +
> + ret = ad_sd_read_reg_raw(sigma_delta, reg, size, sigma_delta->data);
> + if (ret < 0)
> + goto out;
> +
> + switch (size) {
> + case 4:
> + *val = get_unaligned_be32(sigma_delta->data);
> + break;
> + case 3:
> + *val = (sigma_delta->data[0] << 16) |
> + (sigma_delta->data[1] << 8) |
> + sigma_delta->data[2];
> + break;
> + case 2:
> + *val = get_unaligned_be16(sigma_delta->data);
> + break;
> + case 1:
> + *val = sigma_delta->data[0];
> + break;
> + default:
> + ret = -EINVAL;
> + break;
> + }
> +
> +out:
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(ad_sd_read_reg);
> +
> +static int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta,
> + unsigned int mode, unsigned int channel)
> +{
> + int ret;
> +
> + ret = ad_sigma_delta_set_channel(sigma_delta, channel);
> + if (ret)
> + return ret;
> +
> + spi_bus_lock(sigma_delta->spi->master);
> + sigma_delta->bus_locked = true;
> + INIT_COMPLETION(sigma_delta->completion);
> +
> + ret = ad_sigma_delta_set_mode(sigma_delta, mode);
> + if (ret < 0)
> + goto out;
> +
> + sigma_delta->irq_dis = false;
> + enable_irq(sigma_delta->spi->irq);
> + ret = wait_for_completion_timeout(&sigma_delta->completion, 2*HZ);
> + if (ret == 0) {
> + sigma_delta->irq_dis = true;
> + disable_irq_nosync(sigma_delta->spi->irq);
> + ret = -EIO;
> + } else {
> + ret = 0;
> + }
> +out:
> + sigma_delta->bus_locked = false;
> + spi_bus_unlock(sigma_delta->spi->master);
> + ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
> +
> + return ret;
> +}
> +
> +/**
> + * ad_sd_calibrate_all() - Performs channel calibration
> + * @sigma_delta: The sigma delta device
> + * @cb: Array of channels and calibration type to perform
> + * @n: Number of items in cb
> + *
> + * Returns 0 on success, an error code otherwise.
> + **/
> +int ad_sd_calibrate_all(struct ad_sigma_delta *sigma_delta,
> + const struct ad_sd_calib_data *cb, unsigned int n)
> +{
> + unsigned int i;
> + int ret;
> +
> + for (i = 0; i < n; i++) {
> + ret = ad_sd_calibrate(sigma_delta, cb[i].mode, cb[i].channel);
> + if (ret)
> + return ret;
> + }
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(ad_sd_calibrate_all);
> +
> +/**
> + * ad_sigma_delta_single_conversion() - Performs a single data conversion
> + * @indio_dev: The IIO device
> + * @chan: The conversion is done for this channel
> + * @val: Pointer to the location where to store the read value
> + *
> + * Returns: 0 on success, an error value otherwise.
> + */
> +int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev,
> + const struct iio_chan_spec *chan, int *val)
> +{
> + struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
> + unsigned int sample, raw_sample;
> + int ret = 0;
> +
> + if (iio_buffer_enabled(indio_dev))
> + return -EBUSY;
> +
> + mutex_lock(&indio_dev->mlock);
> + ad_sigma_delta_set_channel(sigma_delta, chan->address);
> +
> + spi_bus_lock(sigma_delta->spi->master);
> + sigma_delta->bus_locked = true;
> + INIT_COMPLETION(sigma_delta->completion);
> +
> + ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_SINGLE);
> +
> + sigma_delta->irq_dis = false;
> + enable_irq(sigma_delta->spi->irq);
> + ret = wait_for_completion_interruptible_timeout(
> + &sigma_delta->completion, HZ);
> +
> + sigma_delta->bus_locked = false;
> + spi_bus_unlock(sigma_delta->spi->master);
> +
> + if (ret == 0)
> + ret = -EIO;
> + if (ret < 0)
> + goto out;
> +
> + ret = ad_sd_read_reg(sigma_delta, AD_SD_REG_DATA,
> + DIV_ROUND_UP(chan->scan_type.realbits + chan->scan_type.shift, 8),
> + &raw_sample);
> +
> +out:
> + if (!sigma_delta->irq_dis) {
> + disable_irq_nosync(sigma_delta->spi->irq);
> + sigma_delta->irq_dis = true;
> + }
> +
> + ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
> + mutex_unlock(&indio_dev->mlock);
> +
> + if (ret)
> + return ret;
> +
> + sample = raw_sample >> chan->scan_type.shift;
> + sample &= (1 << chan->scan_type.realbits) - 1;
> + *val = sample;
> +
> + ret = ad_sigma_delta_postprocess_sample(sigma_delta, raw_sample);
> + if (ret)
> + return ret;
> +
> + return IIO_VAL_INT;
> +}
> +EXPORT_SYMBOL_GPL(ad_sigma_delta_single_conversion);
> +
> +static int ad_sd_buffer_postenable(struct iio_dev *indio_dev)
> +{
> + struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
> + unsigned int channel;
> + int ret;
> +
> + ret = iio_triggered_buffer_postenable(indio_dev);
> + if (ret < 0)
> + return ret;
> +
> + channel = find_first_bit(indio_dev->active_scan_mask,
> + indio_dev->masklength);
> + ret = ad_sigma_delta_set_channel(sigma_delta,
> + indio_dev->channels[channel].address);
> + if (ret)
> + goto err_predisable;
> +
> + spi_bus_lock(sigma_delta->spi->master);
> + sigma_delta->bus_locked = true;
> + ret = ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_CONTINUOUS);
> + if (ret)
> + goto err_unlock;
> +
> + sigma_delta->irq_dis = false;
> + enable_irq(sigma_delta->spi->irq);
> +
> + return 0;
> +
> +err_unlock:
> + spi_bus_unlock(sigma_delta->spi->master);
> +err_predisable:
> +
> + return ret;
> +}
> +
> +static int ad_sd_buffer_postdisable(struct iio_dev *indio_dev)
> +{
> + struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
> +
> + INIT_COMPLETION(sigma_delta->completion);
> + wait_for_completion_timeout(&sigma_delta->completion, HZ);
> +
> + if (!sigma_delta->irq_dis) {
> + disable_irq_nosync(sigma_delta->spi->irq);
> + sigma_delta->irq_dis = true;
> + }
> +
> + ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
> +
> + sigma_delta->bus_locked = false;
> + return spi_bus_unlock(sigma_delta->spi->master);
> +}
> +
> +static irqreturn_t ad_sd_trigger_handler(int irq, void *p)
> +{
> + struct iio_poll_func *pf = p;
> + struct iio_dev *indio_dev = pf->indio_dev;
> + struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
> + unsigned int reg_size;
> + uint8_t data[16];
> + int ret;
> +
> + memset(data, 0x00, 16);
> +
> + /* Guaranteed to be aligned with 8 byte boundary */
> + if (indio_dev->scan_timestamp)
> + ((s64 *)data)[1] = pf->timestamp;
> +
> + reg_size = indio_dev->channels[0].scan_type.realbits +
> + indio_dev->channels[0].scan_type.shift;
> + reg_size = DIV_ROUND_UP(reg_size, 8);
> +
> + switch (reg_size) {
> + case 4:
> + case 2:
> + case 1:
> + ret = ad_sd_read_reg_raw(sigma_delta, AD_SD_REG_DATA,
> + reg_size, &data[0]);
> + break;
> + case 3:
> + /* We store 24 bit samples in a 32 bit word. Keep the upper
> + * byte set to zero. */
> + ret = ad_sd_read_reg_raw(sigma_delta, AD_SD_REG_DATA,
> + reg_size, &data[1]);
> + break;
> + }
> +
> + iio_push_to_buffer(indio_dev->buffer, (uint8_t *)data, pf->timestamp);
> +
> + iio_trigger_notify_done(indio_dev->trig);
> + sigma_delta->irq_dis = false;
> + enable_irq(sigma_delta->spi->irq);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static const struct iio_buffer_setup_ops ad_sd_buffer_setup_ops = {
> + .preenable = &iio_sw_buffer_preenable,
> + .postenable = &ad_sd_buffer_postenable,
> + .predisable = &iio_triggered_buffer_predisable,
> + .postdisable = &ad_sd_buffer_postdisable,
> + .validate_scan_mask = &iio_validate_scan_mask_onehot,
> +};
> +
> +static irqreturn_t ad_sd_data_rdy_trig_poll(int irq, void *private)
> +{
> + struct ad_sigma_delta *sigma_delta = private;
> +
> + complete(&sigma_delta->completion);
> + disable_irq_nosync(irq);
> + sigma_delta->irq_dis = true;
> + iio_trigger_poll(sigma_delta->trig, iio_get_time_ns());
> +
> + return IRQ_HANDLED;
> +}
> +
> +/**
> + * ad_sd_validate_trigger() - validate_trigger callback for ad_sigma_delta devices
> + * @indio_dev: The IIO device
> + * @trig: The new trigger
> + *
> + * Returns: 0 if the 'trig' matches the trigger registered by the ad_sigma_delta
> + * device, -EINVAL otherwise.
> + */
> +int ad_sd_validate_trigger(struct iio_dev *indio_dev, struct iio_trigger *trig)
> +{
> + struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
> +
> + if (sigma_delta->trig != trig)
> + return -EINVAL;
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(ad_sd_validate_trigger);
> +
> +static const struct iio_trigger_ops ad_sd_trigger_ops = {
> + .owner = THIS_MODULE,
> +};
> +
> +static int ad_sd_probe_trigger(struct iio_dev *indio_dev)
> +{
> + struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
> + int ret;
> +
> + sigma_delta->trig = iio_trigger_alloc("%s-dev%d", indio_dev->name,
> + indio_dev->id);
> + if (sigma_delta->trig == NULL) {
> + ret = -ENOMEM;
> + goto error_ret;
> + }
> + sigma_delta->trig->ops = &ad_sd_trigger_ops;
> + init_completion(&sigma_delta->completion);
> +
> + ret = request_irq(sigma_delta->spi->irq,
> + ad_sd_data_rdy_trig_poll,
> + IRQF_TRIGGER_LOW,
> + indio_dev->name,
> + sigma_delta);
> + if (ret)
> + goto error_free_trig;
> +
> + if (!sigma_delta->irq_dis) {
> + sigma_delta->irq_dis = true;
> + disable_irq_nosync(sigma_delta->spi->irq);
> + }
> + sigma_delta->trig->dev.parent = &sigma_delta->spi->dev;
> + sigma_delta->trig->private_data = sigma_delta;
> +
> + ret = iio_trigger_register(sigma_delta->trig);
> + if (ret)
> + goto error_free_irq;
> +
> + /* select default trigger */
> + indio_dev->trig = sigma_delta->trig;
> +
> + return 0;
> +
> +error_free_irq:
> + free_irq(sigma_delta->spi->irq, sigma_delta);
> +error_free_trig:
> + iio_trigger_free(sigma_delta->trig);
> +error_ret:
> + return ret;
> +}
> +
> +static void ad_sd_remove_trigger(struct iio_dev *indio_dev)
> +{
> + struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
> +
> + iio_trigger_unregister(sigma_delta->trig);
> + free_irq(sigma_delta->spi->irq, sigma_delta);
> + iio_trigger_free(sigma_delta->trig);
> +}
> +
> +/**
> + * ad_sd_setup_buffer_and_trigger() -
> + * @indio_dev: The IIO device
> + */
> +int ad_sd_setup_buffer_and_trigger(struct iio_dev *indio_dev)
> +{
> + int ret;
> +
> + ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
> + &ad_sd_trigger_handler, &ad_sd_buffer_setup_ops);
> + if (ret)
> + return ret;
> +
> + ret = ad_sd_probe_trigger(indio_dev);
> + if (ret) {
> + iio_triggered_buffer_cleanup(indio_dev);
> + return ret;
> + }
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(ad_sd_setup_buffer_and_trigger);
> +
> +/**
> + * ad_sd_cleanup_buffer_and_trigger() -
> + * @indio_dev: The IIO device
> + */
> +void ad_sd_cleanup_buffer_and_trigger(struct iio_dev *indio_dev)
> +{
> + ad_sd_remove_trigger(indio_dev);
> + iio_triggered_buffer_cleanup(indio_dev);
> +}
> +EXPORT_SYMBOL_GPL(ad_sd_cleanup_buffer_and_trigger);
> +
> +/**
> + * ad_sd_init() - Initializes a ad_sigma_delta struct
> + * @sigma_delta: The ad_sigma_delta device
> + * @indio_dev: The IIO device which the Sigma Delta device is used for
> + * @spi: The SPI device for the ad_sigma_delta device
> + * @info: Device specific callbacks and options
> + *
> + * This function needs to be called before any other operations are performed on
> + * the ad_sigma_delta struct.
> + */
> +int ad_sd_init(struct ad_sigma_delta *sigma_delta, struct iio_dev *indio_dev,
> + struct spi_device *spi, const struct ad_sigma_delta_info *info)
> +{
> + sigma_delta->spi = spi;
> + sigma_delta->info = info;
> + iio_device_set_drvdata(indio_dev, sigma_delta);
> +
> + return 0;
> +}
EXPORT_SYMBOL_GPL(ad_sd_init);
> +
> +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
> +MODULE_DESCRIPTION("Analog Devices Sigma-Delta ADCs");
> +MODULE_LICENSE("GPL v2");
> diff --git a/include/linux/iio/adc/ad_sigma_delta.h b/include/linux/iio/adc/ad_sigma_delta.h
> new file mode 100644
> index 0000000..2e4eab9
> --- /dev/null
> +++ b/include/linux/iio/adc/ad_sigma_delta.h
> @@ -0,0 +1,173 @@
> +/*
> + * Support code for Analog Devices Sigma-Delta ADCs
> + *
> + * Copyright 2012 Analog Devices Inc.
> + * Author: Lars-Peter Clausen <lars@metafoo.de>
> + *
> + * Licensed under the GPL-2.
> + */
> +#ifndef __AD_SIGMA_DELTA_H__
> +#define __AD_SIGMA_DELTA_H__
> +
> +enum ad_sigma_delta_mode {
> + AD_SD_MODE_CONTINUOUS = 0,
> + AD_SD_MODE_SINGLE = 1,
> + AD_SD_MODE_IDLE = 2,
> + AD_SD_MODE_POWERDOWN = 3,
> +};
> +
> +/**
> + * struct ad_sigma_delta_calib_data - Calibration data for Sigma Delta devices
> + * @mode: Calibration mode.
> + * @channel: Calibration channel.
> + */
> +struct ad_sd_calib_data {
> + unsigned int mode;
> + unsigned int channel;
> +};
> +
> +struct ad_sigma_delta;
> +struct iio_dev;
> +
> +/**
> + * struct ad_sigma_delta_info - Sigma Delta driver specific callbacks and options
> + * @set_channel: Will be called to select the current channel, may be NULL.
> + * @set_mode: Will be called to select the current mode, may be NULL.
> + * @postprocess_sample: Is called for each sampled data word, can be used to
> + * modify or drop the sample data, it, may be NULL.
> + * @has_registers: true if the device has writable and readable registers, false
> + * if there is just one read-only sample data shift register.
> + * @addr_shift: Shift of the register address in the communications register.
> + * @read_mask: Mask for the communications register having the read bit set.
> + */
> +struct ad_sigma_delta_info {
> + int (*set_channel)(struct ad_sigma_delta *, unsigned int channel);
> + int (*set_mode)(struct ad_sigma_delta *, enum ad_sigma_delta_mode mode);
> + int (*postprocess_sample)(struct ad_sigma_delta *, unsigned int raw_sample);
> + bool has_registers;
> + unsigned int addr_shift;
> + unsigned int read_mask;
> +};
> +
> +/**
> + * struct ad_sigma_delta - Sigma Delta device struct
> + * @spi: The spi device associated with the Sigma Delta device.
> + * @trig: The IIO trigger associated with the Sigma Delta device.
> + *
> + * Most of the fields are private to the sigma delta library code and should not
> + * be accessed by individual drivers.
> + */
> +struct ad_sigma_delta {
> + struct spi_device *spi;
> + struct iio_trigger *trig;
> +
> +/* private: */
> + struct completion completion;
> + bool irq_dis;
> +
> + bool bus_locked;
> +
> + uint8_t comm;
> +
> + const struct ad_sigma_delta_info *info;
> +
> + /*
> + * DMA (thus cache coherency maintenance) requires the
> + * transfer buffers to live in their own cache lines.
> + */
> + uint8_t data[4] ____cacheline_aligned;
> +};
> +
> +static inline int ad_sigma_delta_set_channel(struct ad_sigma_delta *sd,
> + unsigned int channel)
> +{
> + if (sd->info->set_channel)
> + return sd->info->set_channel(sd, channel);
> +
> + return 0;
> +}
> +
> +static inline int ad_sigma_delta_set_mode(struct ad_sigma_delta *sd,
> + unsigned int mode)
> +{
> + if (sd->info->set_mode)
> + return sd->info->set_mode(sd, mode);
> +
> + return 0;
> +}
> +
> +static inline int ad_sigma_delta_postprocess_sample(struct ad_sigma_delta *sd,
> + unsigned int raw_sample)
> +{
> + if (sd->info->postprocess_sample)
> + return sd->info->postprocess_sample(sd, raw_sample);
> +
> + return 0;
> +}
> +
> +void ad_sd_set_comm(struct ad_sigma_delta *sigma_delta, uint8_t comm);
> +int ad_sd_write_reg(struct ad_sigma_delta *sigma_delta, unsigned int reg,
> + unsigned int size, unsigned int val);
> +int ad_sd_read_reg(struct ad_sigma_delta *sigma_delta, unsigned int reg,
> + unsigned int size, unsigned int *val);
> +
> +int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev,
> + const struct iio_chan_spec *chan, int *val);
> +int ad_sd_calibrate_all(struct ad_sigma_delta *sigma_delta,
> + const struct ad_sd_calib_data *cd, unsigned int n);
> +int ad_sd_init(struct ad_sigma_delta *sigma_delta, struct iio_dev *indio_dev,
> + struct spi_device *spi, const struct ad_sigma_delta_info *info);
> +
> +int ad_sd_setup_buffer_and_trigger(struct iio_dev *indio_dev);
> +void ad_sd_cleanup_buffer_and_trigger(struct iio_dev *indio_dev);
> +
> +int ad_sd_validate_trigger(struct iio_dev *indio_dev, struct iio_trigger *trig);
> +
> +#define __AD_SD_CHANNEL(_si, _channel1, _channel2, _address, _bits, \
> + _storagebits, _shift, _extend_name, _type) \
> + { \
> + .type = (_type), \
> + .differential = (_channel2 == -1 ? 0 : 1), \
> + .indexed = 1, \
> + .channel = (_channel1), \
> + .channel2 = (_channel2), \
> + .address = (_address), \
> + .extend_name = (_extend_name), \
> + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
> + IIO_CHAN_INFO_SCALE_SHARED_BIT | \
> + IIO_CHAN_INFO_OFFSET_SEPARATE_BIT, \
> + .scan_index = (_si), \
> + .scan_type = { \
> + .sign = 'u', \
> + .realbits = (_bits), \
> + .storagebits = (_storagebits), \
> + .shift = (_shift), \
> + .endianness = IIO_BE, \
> + }, \
> + }
> +
> +#define AD_SD_DIFF_CHANNEL(_si, _channel1, _channel2, _address, _bits, \
> + _storagebits, _shift) \
> + __AD_SD_CHANNEL(_si, _channel1, _channel2, _address, _bits, \
> + _storagebits, _shift, NULL, IIO_VOLTAGE)
> +
> +#define AD_SD_SHORTED_CHANNEL(_si, _channel, _address, _bits, \
> + _storagebits, _shift) \
> + __AD_SD_CHANNEL(_si, _channel, _channel, _address, _bits, \
> + _storagebits, _shift, "shorted", IIO_VOLTAGE)
> +
> +#define AD_SD_CHANNEL(_si, _channel, _address, _bits, \
> + _storagebits, _shift) \
> + __AD_SD_CHANNEL(_si, _channel, -1, _address, _bits, \
> + _storagebits, _shift, NULL, IIO_VOLTAGE)
> +
> +#define AD_SD_TEMP_CHANNEL(_si, _address, _bits, _storagebits, _shift) \
> + __AD_SD_CHANNEL(_si, 0, -1, _address, _bits, \
> + _storagebits, _shift, NULL, IIO_TEMP)
> +
> +#define AD_SD_SUPPLY_CHANNEL(_si, _channel, _address, _bits, _storagebits, \
> + _shift) \
> + __AD_SD_CHANNEL(_si, _channel, -1, _address, _bits, \
> + _storagebits, _shift, "supply", IIO_VOLTAGE)
> +
> +#endif
>
next prev parent reply other threads:[~2012-08-14 20:19 UTC|newest]
Thread overview: 37+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-08-10 16:36 [PATCH 01/22] staging:iio:ad7793: Add missing break in switch statement Lars-Peter Clausen
2012-08-10 16:36 ` [PATCH 02/22] staging:iio:ad7793: Mark channels as unsigned Lars-Peter Clausen
2012-08-10 16:36 ` [PATCH 03/22] staging:iio:ad7793: Report channel offset Lars-Peter Clausen
2012-08-10 16:36 ` [PATCH 04/22] staging:iio:ad7793: Fix temperature scale and offset Lars-Peter Clausen
2012-08-10 16:36 ` [PATCH 05/22] staging:iio:ad7793: Follow new IIO naming spec Lars-Peter Clausen
2012-08-10 16:36 ` [PATCH 06/22] staging:iio:ad7793: Fix internal reference value Lars-Peter Clausen
2012-08-10 16:36 ` [PATCH 07/22] staging:iio:ad7793: Remove unused platform_data from device state struct Lars-Peter Clausen
2012-08-14 19:39 ` Jonathan Cameron
2012-08-14 20:19 ` Jonathan Cameron
2012-08-15 9:03 ` Lars-Peter Clausen
2012-08-15 9:28 ` Jonathan Cameron
[not found] ` <502B6688.6000904@metafoo.de>
2012-09-03 16:39 ` Lars-Peter Clausen
2012-09-03 20:09 ` Jonathan Cameron
2012-08-10 16:36 ` [PATCH 08/22] staging:iio:ad7192: Add missing break in switch statement Lars-Peter Clausen
2012-08-10 16:36 ` [PATCH 09/22] staging:iio:ad7192: Fix setting ACX Lars-Peter Clausen
2012-08-10 16:36 ` [PATCH 10/22] staging:iio:ad7192: Mark channels as unsigned Lars-Peter Clausen
2012-08-10 16:36 ` [PATCH 11/22] staging:iio:ad7192: Report channel offset Lars-Peter Clausen
2012-08-10 16:36 ` [PATCH 12/22] staging:iio:ad7192: Report offset and scale for temperature channel Lars-Peter Clausen
2012-08-10 16:36 ` [PATCH 13/22] staging:iio:ad7192: Remove unused platform_data from device state struct Lars-Peter Clausen
2012-08-10 16:36 ` [PATCH 14/22] staging:iio:ad7780: Mark channels as unsigned Lars-Peter Clausen
2012-08-10 16:36 ` [PATCH 15/22] iio: Introduce iio_device_{set,get}_drvdata() Lars-Peter Clausen
2012-08-10 16:36 ` [PATCH 16/22] iio:adc: Add common code for ADI Sigma Delta devices Lars-Peter Clausen
2012-08-14 12:03 ` Jonathan Cameron
2012-08-14 20:19 ` Jonathan Cameron [this message]
2012-08-10 16:36 ` [PATCH 17/22] staging:iio:ad7780: Use common Sigma Delta library Lars-Peter Clausen
2012-08-14 12:05 ` Jonathan Cameron
2012-08-10 16:36 ` [PATCH 18/22] staging:iio:ad7793: " Lars-Peter Clausen
2012-08-10 16:36 ` [PATCH 19/22] staging:iio:ad7192: " Lars-Peter Clausen
2012-08-27 17:07 ` Jonathan Cameron
2012-09-03 8:13 ` Lars-Peter Clausen
2012-08-10 16:36 ` [PATCH 20/22] staging:iio:ad7793: Add support for ad7794/ad7795 Lars-Peter Clausen
2012-08-10 16:36 ` [PATCH 21/22] staging:iio:ad7793: Add ad7785 support Lars-Peter Clausen
2012-08-10 16:36 ` [PATCH 22/22] staging:iio:adc: Add AD7791 driver Lars-Peter Clausen
2012-08-11 8:41 ` Peter Meerwald
2012-08-11 17:37 ` Lars-Peter Clausen
2012-08-13 13:12 ` Lars-Peter Clausen
2012-08-14 20:18 ` Jonathan Cameron
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=502AB2D1.3060000@kernel.org \
--to=jic23@kernel.org \
--cc=drivers@analog.com \
--cc=jic23@cam.ac.uk \
--cc=lars@metafoo.de \
--cc=linux-iio@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).