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@xxxxxxxxxx> > --- > 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@xxxxxxxxxx> > + * > + * 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@xxxxxxxxxx>"); > +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@xxxxxxxxxx> > + * > + * 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 > -- To unsubscribe from this list: send the line "unsubscribe linux-iio" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html