> From: Datta, Shubhrajyoti [mailto:shubhrajyoti@xxxxxx] > > -----Original Message----- > > From: linux-iio-owner@xxxxxxxxxxxxxxx [mailto:linux-iio- > > owner@xxxxxxxxxxxxxxx] On Behalf Of michael.hennerich@xxxxxxxxxx > > Sent: Friday, October 01, 2010 8:12 PM > > To: greg@xxxxxxxxx > > Cc: linux-iio@xxxxxxxxxxxxxxx; drivers@xxxxxxxxxx; jic23@xxxxxxxxx; > > Michael Hennerich > > Subject: [PATCH 1/2] staging: iio: adc: Enable driver support for > ad799x > > AD converters > > > > From: Michael Hennerich <michael.hennerich@xxxxxxxxxx> > > > > Driver for ad7991, ad7995, ad7999, ad7992, ad7993, ad7994, ad7997 and > > ad7998 multichannel ADC. > > > > Signed-off-by: Michael Hennerich <michael.hennerich@xxxxxxxxxx> > > Acked-by: Jonathan Cameron <jic23@xxxxxxxxx> > > --- > > drivers/staging/iio/adc/Kconfig | 20 + > > drivers/staging/iio/adc/Makefile | 4 + > > drivers/staging/iio/adc/ad799x.h | 157 ++++++ > > drivers/staging/iio/adc/ad799x_core.c | 918 > > +++++++++++++++++++++++++++++++++ > > drivers/staging/iio/adc/ad799x_ring.c | 246 +++++++++ > > 5 files changed, 1345 insertions(+), 0 deletions(-) > > create mode 100644 drivers/staging/iio/adc/ad799x.h > > create mode 100644 drivers/staging/iio/adc/ad799x_core.c > > create mode 100644 drivers/staging/iio/adc/ad799x_ring.c > > > > diff --git a/drivers/staging/iio/adc/Kconfig > > b/drivers/staging/iio/adc/Kconfig > > index 0835fbc..3ea4da8 100644 > > --- a/drivers/staging/iio/adc/Kconfig > > +++ b/drivers/staging/iio/adc/Kconfig > > @@ -26,3 +26,23 @@ config MAX1363_RING_BUFFER > > help > > Say yes here to include ring buffer support in the MAX1363 > > ADC driver. > > + > > +config AD799X > > + tristate "Analog Devices AD799x ADC driver" > > + depends on I2C > > + select IIO_TRIGGER if IIO_RING_BUFFER > > + select AD799X_RING_BUFFER > > + help > > + Say yes here to build support for Analog Devices: > > + ad7991, ad7995, ad7999, ad7992, ad7993, ad7994, ad7997, > ad7998 > > + i2c analog to digital convertors (ADC). Provides direct > access > > + via sysfs. > > + > > +config AD799X_RING_BUFFER > > + bool "Analog Devices AD799x: use ring buffer" > > + depends on AD799X > > + select IIO_RING_BUFFER > > + select IIO_SW_RING > > + help > > + Say yes here to include ring buffer support in the AD799X > > + ADC driver. > > diff --git a/drivers/staging/iio/adc/Makefile > > b/drivers/staging/iio/adc/Makefile > > index 688510f..f4aa63a 100644 > > --- a/drivers/staging/iio/adc/Makefile > > +++ b/drivers/staging/iio/adc/Makefile > > @@ -6,3 +6,7 @@ max1363-y := max1363_core.o > > max1363-y += max1363_ring.o > > > > obj-$(CONFIG_MAX1363) += max1363.o > > + > > +ad799x-y := ad799x_core.o > > +ad799x-$(CONFIG_AD799X_RING_BUFFER) += ad799x_ring.o > > +obj-$(CONFIG_AD799X) += ad799x.o > > \ No newline at end of file > > diff --git a/drivers/staging/iio/adc/ad799x.h > > b/drivers/staging/iio/adc/ad799x.h > > new file mode 100644 > > index 0000000..73f3ec5 > > --- /dev/null > > +++ b/drivers/staging/iio/adc/ad799x.h > > @@ -0,0 +1,157 @@ > > +/* > > + * Copyright (C) 2010 Michael Hennerich, Analog Devices Inc. > > + * Copyright (C) 2008-2010 Jonathan Cameron > > + * > > + * This program is free software; you can redistribute it and/or > modify > > + * it under the terms of the GNU General Public License version 2 as > > + * published by the Free Software Foundation. > > + * > > + * ad799x.h > > + */ > > + > > +#ifndef _AD799X_H_ > > +#define _AD799X_H_ > > + > > +#define AD799X_CHANNEL_SHIFT 4 > > + > > +/* > > + * AD7991, AD7995 and AD7999 defines > > + */ > > + > > +#define AD7991_REF_SEL 0x08 > > +#define AD7991_FLTR 0x04 > > +#define AD7991_BIT_TRIAL_DELAY 0x02 > > +#define AD7991_SAMPLE_DELAY 0x01 > > + > > +/* > > + * AD7992, AD7993, AD7994, AD7997 and AD7998 defines > > + */ > > + > > +#define AD7998_FLTR 0x08 > > +#define AD7998_ALERT_EN 0x04 > > +#define AD7998_BUSY_ALERT 0x02 > > +#define AD7998_BUSY_ALERT_POL 0x01 > > + > > +#define AD7998_CONV_RES_REG 0x0 > > +#define AD7998_ALERT_STAT_REG 0x1 > > +#define AD7998_CONF_REG 0x2 > > +#define AD7998_CYCLE_TMR_REG 0x3 > > +#define AD7998_DATALOW_CH1_REG 0x4 > > +#define AD7998_DATAHIGH_CH1_REG 0x5 > > +#define AD7998_HYST_CH1_REG 0x6 > > +#define AD7998_DATALOW_CH2_REG 0x7 > > +#define AD7998_DATAHIGH_CH2_REG 0x8 > > +#define AD7998_HYST_CH2_REG 0x9 > > +#define AD7998_DATALOW_CH3_REG 0xA > > +#define AD7998_DATAHIGH_CH3_REG 0xB > > +#define AD7998_HYST_CH3_REG 0xC > > +#define AD7998_DATALOW_CH4_REG 0xD > > +#define AD7998_DATAHIGH_CH4_REG 0xE > > +#define AD7998_HYST_CH4_REG 0xF > > + > > +#define AD7998_CYC_MASK 0x7 > > +#define AD7998_CYC_DIS 0x0 > > +#define AD7998_CYC_TCONF_32 0x1 > > +#define AD7998_CYC_TCONF_64 0x2 > > +#define AD7998_CYC_TCONF_128 0x3 > > +#define AD7998_CYC_TCONF_256 0x4 > > +#define AD7998_CYC_TCONF_512 0x5 > > +#define AD7998_CYC_TCONF_1024 0x6 > > +#define AD7998_CYC_TCONF_2048 0x7 > > + > > +#define AD7998_ALERT_STAT_CLEAR 0xFF > > + > > +/* > > + * AD7997 and AD7997 defines > > + */ > > + > > +#define AD7997_8_READ_SINGLE 0x80 > > +#define AD7997_8_READ_SEQUENCE 0x70 > > + > > +enum { > > + ad7991, > > + ad7995, > > + ad7999, > > + ad7992, > > + ad7993, > > + ad7994, > > + ad7997, > > + ad7998 > > +}; > > + > > +struct ad799x_state; > > + > > +/** > > + * struct ad799x_chip_info - chip specifc information > > + * @num_inputs: number of physical inputs on chip > > + * @bits: accuracy of the adc in bits > > + * @int_vref_mv: the internal reference voltage > > + * @monitor_mode: whether the chip supports monitor interrupts > > + * @default_config: device default configuration > > + * @dev_attrs: pointer to the device attribute group > > + * @scan_attrs: pointer to the scan element attribute > group > > + * @event_attrs: pointer to the monitor event attribute group > > + * @ad799x_set_scan_mode: function pointer to the device specific > mode > > function > > + > > + */ > > +struct ad799x_chip_info { > > + u8 num_inputs; > > + u8 bits; > > + u16 int_vref_mv; > > + bool monitor_mode; > > + u16 default_config; > > + struct attribute_group *dev_attrs; > > + struct attribute_group *scan_attrs; > > + struct attribute_group *event_attrs; > > + int (*ad799x_set_scan_mode) (struct ad799x_state *st, > > + unsigned mask); > > +}; > > + > > +struct ad799x_state { > > + struct iio_dev *indio_dev; > > + struct i2c_client *client; > > + const struct ad799x_chip_info *chip_info; > > + struct work_struct poll_work; > > + struct work_struct work_thresh; > > + atomic_t protect_ring; > > + struct iio_trigger *trig; > > + struct regulator *reg; > > + s64 last_timestamp; > > + u16 int_vref_mv; > > + unsigned id; > > + char *name; > > + u16 config; > > +}; > > + > > +/* > > + * TODO: struct ad799x_platform_data needs to go into > inlude/linux/iio > > + */ > > + > > +struct ad799x_platform_data { > > + u16 vref_mv; > > +}; > > + > > +int ad799x_set_scan_mode(struct ad799x_state *st, unsigned mask); > > + > > +#ifdef CONFIG_AD799X_RING_BUFFER > > +int ad799x_single_channel_from_ring(struct ad799x_state *st, long > mask); > > +int ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev); > > +void ad799x_ring_cleanup(struct iio_dev *indio_dev); > > +#else /* CONFIG_AD799X_RING_BUFFER */ > > +int ad799x_single_channel_from_ring(struct ad799x_state *st, long > mask) > > +{ > > + return -EINVAL; > > +} > > + > > + > > +static inline int > > +ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev) > > +{ > > + return 0; > > +} > > + > > +static inline void ad799x_ring_cleanup(struct iio_dev *indio_dev) > > +{ > > +} > > +#endif /* CONFIG_AD799X_RING_BUFFER */ > > +#endif /* _AD799X_H_ */ > > diff --git a/drivers/staging/iio/adc/ad799x_core.c > > b/drivers/staging/iio/adc/ad799x_core.c > > new file mode 100644 > > index 0000000..772c664 > > --- /dev/null > > +++ b/drivers/staging/iio/adc/ad799x_core.c > > @@ -0,0 +1,918 @@ > > +/* > > + * iio/adc/ad799x.c > > + * Copyright (C) 2010 Michael Hennerich, Analog Devices Inc. > > + * > > + * based on iio/adc/max1363 > > + * Copyright (C) 2008-2010 Jonathan Cameron > > + * > > + * based on linux/drivers/i2c/chips/max123x > > + * Copyright (C) 2002-2004 Stefan Eletzhofer > > + * > > + * based on linux/drivers/acron/char/pcf8583.c > > + * Copyright (C) 2000 Russell King > > + * > > + * This program is free software; you can redistribute it and/or > modify > > + * it under the terms of the GNU General Public License version 2 as > > + * published by the Free Software Foundation. > > + * > > + * ad799x.c > > + * > > + * Support for ad7991, ad7995, ad7999, ad7992, ad7993, ad7994, > ad7997, > > + * ad7998 and similar chips. > > + * > > + */ > > + > > +#include <linux/interrupt.h> > > +#include <linux/workqueue.h> > > +#include <linux/device.h> > > +#include <linux/kernel.h> > > +#include <linux/sysfs.h> > > +#include <linux/list.h> > > +#include <linux/i2c.h> > > +#include <linux/regulator/consumer.h> > > +#include <linux/slab.h> > > +#include <linux/types.h> > > +#include <linux/err.h> > > + > > +#include "../iio.h" > > +#include "../sysfs.h" > > + > > +#include "../ring_generic.h" > > +#include "adc.h" > > +#include "ad799x.h" > > + > > +/* > > + * ad799x register access by I2C > > + */ > > +static int ad799x_i2c_read16(struct ad799x_state *st, u8 reg, u16 > *data) > > +{ > > + struct i2c_client *client = st->client; > > + int ret = 0; > > + > > + ret = i2c_smbus_read_word_data(client, reg); > > + if (ret < 0) { > > + dev_err(&client->dev, "I2C read error\n"); > > + return ret; > > + } > > + > > + *data = swab16((u16)ret); > > + > > + return 0; > > +} > > + > > +static int ad799x_i2c_read8(struct ad799x_state *st, u8 reg, u8 > *data) > > +{ > > + struct i2c_client *client = st->client; > > + int ret = 0; > > + > > + ret = i2c_smbus_read_word_data(client, reg); > > + if (ret < 0) { > > + dev_err(&client->dev, "I2C read error\n"); > > + return ret; > > + } > > + > > + *data = ret; > Ret is int and data is a char * . Do you think a type cast would be > better. Well - the case where ret may become negative is handled before. However I should use i2c_smbus_read_byte_data here. This code works just the same, since the AD799x repeats the last date. Thanks for pointing out that section. I'll add the cast. > > + > > + return 0; > > +} > > + > > +static int ad799x_i2c_write16(struct ad799x_state *st, u8 reg, u16 > data) > > +{ > > + struct i2c_client *client = st->client; > > + int ret = 0; > > + > > + ret = i2c_smbus_write_word_data(client, reg, swab16(data)); > > + if (ret < 0) > > + dev_err(&client->dev, "I2C write error\n"); > > + > > + return ret; > > +} > > + > > +static int ad799x_i2c_write8(struct ad799x_state *st, u8 reg, u8 > data) > > +{ > > + struct i2c_client *client = st->client; > > + int ret = 0; > > + > > + ret = i2c_smbus_write_byte_data(client, reg, data); > > + if (ret < 0) > > + dev_err(&client->dev, "I2C write error\n"); > > + > > + return ret; > > +} > > + > > +static int ad799x_scan_el_set_state(struct iio_scan_el *scan_el, > > + struct iio_dev *indio_dev, > > + bool state) > > +{ > > + struct ad799x_state *st = indio_dev->dev_data; > > + return ad799x_set_scan_mode(st, st->indio_dev->ring- > >scan_mask); > > +} > > + > > +/* Here we claim all are 16 bits. This currently does no harm and > saves > > + * us a lot of scan element listings */ > > + > > +#define AD799X_SCAN_EL(number) > \ > > + IIO_SCAN_EL_C(in##number, number, 0, ad799x_scan_el_set_state); > > + > > +static AD799X_SCAN_EL(0); > > +static AD799X_SCAN_EL(1); > > +static AD799X_SCAN_EL(2); > > +static AD799X_SCAN_EL(3); > > +static AD799X_SCAN_EL(4); > > +static AD799X_SCAN_EL(5); > > +static AD799X_SCAN_EL(6); > > +static AD799X_SCAN_EL(7); > > + > > +static ssize_t ad799x_show_precision(struct device *dev, > > + struct device_attribute *attr, > > + char *buf) > > +{ > > + struct iio_dev *dev_info = dev_get_drvdata(dev); > > + struct ad799x_state *st = iio_dev_get_devdata(dev_info); > > + return sprintf(buf, "%d\n", st->chip_info->bits); > > +} > > + > > +static IIO_DEVICE_ATTR(in_precision, S_IRUGO, ad799x_show_precision, > > + NULL, 0); > > + > > +static int ad7991_5_9_set_scan_mode(struct ad799x_state *st, > unsigned > > mask) > > +{ > > + return i2c_smbus_write_byte(st->client, > > + st->config | (mask << AD799X_CHANNEL_SHIFT)); > > +} > > + > > +static int ad7992_3_4_set_scan_mode(struct ad799x_state *st, > unsigned > > mask) > > +{ > > + return ad799x_i2c_write8(st, AD7998_CONF_REG, > > + st->config | (mask << AD799X_CHANNEL_SHIFT)); > > +} > > + > > +static int ad7997_8_set_scan_mode(struct ad799x_state *st, unsigned > mask) > > +{ > > + return ad799x_i2c_write16(st, AD7998_CONF_REG, > > + st->config | (mask << AD799X_CHANNEL_SHIFT)); > > +} > > + > > +int ad799x_set_scan_mode(struct ad799x_state *st, unsigned mask) > > +{ > > + int ret; > > + > > + if (st->chip_info->ad799x_set_scan_mode != NULL) { > > + ret = st->chip_info->ad799x_set_scan_mode(st, mask); > > + return (ret > 0) ? 0 : ret; > > + } > > + > > + return 0; > > +} > > + > > +static ssize_t ad799x_read_single_channel(struct device *dev, > > + struct device_attribute *attr, > > + char *buf) > > +{ > > + struct iio_dev *dev_info = dev_get_drvdata(dev); > > + struct ad799x_state *st = iio_dev_get_devdata(dev_info); > > + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); > > + int ret = 0, len = 0; > > + u32 data ; > > + u16 rxbuf[1]; > > + u8 cmd; > > + long mask; > > + > > + mutex_lock(&dev_info->mlock); > > + mask = 1 << this_attr->address; > > + /* If ring buffer capture is occuring, query the buffer */ > > + if (iio_ring_enabled(dev_info)) { > > + data = ad799x_single_channel_from_ring(st, mask); > > + if (data < 0) { > > + ret = data; > > + goto error_ret; > > + } > > + } else { > > + switch (st->id) { > > + case ad7991: > > + case ad7995: > > + case ad7999: > > + cmd = st->config | (mask << > AD799X_CHANNEL_SHIFT); > > + break; > > + case ad7992: > > + case ad7993: > > + case ad7994: > > + cmd = mask << AD799X_CHANNEL_SHIFT; > > + break; > > + case ad7997: > > + case ad7998: > > + cmd = (this_attr->address << > > + AD799X_CHANNEL_SHIFT) | > AD7997_8_READ_SINGLE; > > + break; > > + default: > > + cmd = 0; > > + > > + } > > + ret = ad799x_i2c_read16(st, cmd, rxbuf); > > + if (ret < 0) > > + goto error_ret; > > + > > + data = rxbuf[0] & 0xFFF; > > + } > > + > > + /* Pretty print the result */ > > + len = sprintf(buf, "%u\n", data); > > + > > +error_ret: > > + mutex_unlock(&dev_info->mlock); > > + return ret ? ret : len; > > +} > > + > > +static ssize_t ad799x_read_frequency(struct device *dev, > > + struct device_attribute *attr, > > + char *buf) > > +{ > > + struct iio_dev *dev_info = dev_get_drvdata(dev); > > + struct ad799x_state *st = iio_dev_get_devdata(dev_info); > > + > > + int ret, len = 0; > > + u8 val; > > + ret = ad799x_i2c_read8(st, AD7998_CYCLE_TMR_REG, &val); > > + if (ret) > > + return ret; > > + > > + val &= AD7998_CYC_MASK; > > + > > + switch (val) { > > + case AD7998_CYC_DIS: > > + len = sprintf(buf, "0\n"); > > + break; > > + case AD7998_CYC_TCONF_32: > > + len = sprintf(buf, "15625\n"); > > + break; > > + case AD7998_CYC_TCONF_64: > > + len = sprintf(buf, "7812\n"); > > + break; > > + case AD7998_CYC_TCONF_128: > > + len = sprintf(buf, "3906\n"); > > + break; > > + case AD7998_CYC_TCONF_256: > > + len = sprintf(buf, "1953\n"); > > + break; > > + case AD7998_CYC_TCONF_512: > > + len = sprintf(buf, "976\n"); > > + break; > > + case AD7998_CYC_TCONF_1024: > > + len = sprintf(buf, "488\n"); > > + break; > > + case AD7998_CYC_TCONF_2048: > > + len = sprintf(buf, "244\n"); > > + break; > > + } > > + return len; > > +} > > + > > +static ssize_t ad799x_write_frequency(struct device *dev, > > + struct device_attribute *attr, > > + const char *buf, > > + size_t len) > > +{ > > + struct iio_dev *dev_info = dev_get_drvdata(dev); > > + struct ad799x_state *st = iio_dev_get_devdata(dev_info); > > + > > + long val; > > + int ret; > > + u8 t; > > + > > + ret = strict_strtol(buf, 10, &val); > > + if (ret) > > + return ret; > > + > > + mutex_lock(&dev_info->mlock); > > + ret = ad799x_i2c_read8(st, AD7998_CYCLE_TMR_REG, &t); > > + if (ret) > > + goto error_ret_mutex; > > + /* Wipe the bits clean */ > > + t &= ~AD7998_CYC_MASK; > > + > > + switch (val) { > > + case 15625: > > + t |= AD7998_CYC_TCONF_32; > > + break; > > + case 7812: > > + t |= AD7998_CYC_TCONF_64; > > + break; > > + case 3906: > > + t |= AD7998_CYC_TCONF_128; > > + break; > > + case 1953: > > + t |= AD7998_CYC_TCONF_256; > > + break; > > + case 976: > > + t |= AD7998_CYC_TCONF_512; > > + break; > > + case 488: > > + t |= AD7998_CYC_TCONF_1024; > > + break; > > + case 244: > > + t |= AD7998_CYC_TCONF_2048; > > + break; > > + case 0: > > + t |= AD7998_CYC_DIS; > > + break; > > + default: > > + ret = -EINVAL; > > + goto error_ret_mutex; > > + } > > + > > + ret = ad799x_i2c_write8(st, AD7998_CYCLE_TMR_REG, t); > > + > > +error_ret_mutex: > > + mutex_unlock(&dev_info->mlock); > > + > > + return ret ? ret : len; > > +} > > + > > + > > +static ssize_t ad799x_read_channel_config(struct device *dev, > > + struct device_attribute *attr, > > + char *buf) > > +{ > > + struct iio_dev *dev_info = dev_get_drvdata(dev); > > + struct ad799x_state *st = iio_dev_get_devdata(dev_info); > > + struct iio_event_attr *this_attr = to_iio_event_attr(attr); > > + > > + int ret; > > + u16 val; > > + ret = ad799x_i2c_read16(st, this_attr->mask, &val); > > + if (ret) > > + return ret; > > + > > + return sprintf(buf, "%d\n", val); > > +} > > + > > +static ssize_t ad799x_write_channel_config(struct device *dev, > > + struct device_attribute *attr, > > + const char *buf, > > + size_t len) > > +{ > > + struct iio_dev *dev_info = dev_get_drvdata(dev); > > + struct ad799x_state *st = iio_dev_get_devdata(dev_info); > > + struct iio_event_attr *this_attr = to_iio_event_attr(attr); > > + > > + long val; > > + int ret; > > + > > + ret = strict_strtol(buf, 10, &val); > > + if (ret) > > + return ret; > > + > > + mutex_lock(&dev_info->mlock); > > + ret = ad799x_i2c_write16(st, this_attr->mask, val); > > + mutex_unlock(&dev_info->mlock); > > + > > + return ret ? ret : len; > > +} > > + > > +static void ad799x_interrupt_bh(struct work_struct *work_s) > > +{ > > + struct ad799x_state *st = container_of(work_s, > > + struct ad799x_state, work_thresh); > > + u8 status; > > + int i; > > + > > + if (ad799x_i2c_read8(st, AD7998_ALERT_STAT_REG, &status)) > > + goto err_out; > > + > > + if (!status) > > + goto err_out; > > + > > + ad799x_i2c_write8(st, AD7998_ALERT_STAT_REG, > > AD7998_ALERT_STAT_CLEAR); > > + > > + for (i = 0; i < 8; i++) { > > + if (status & (1 << i)) > > + iio_push_event(st->indio_dev, 0, > > + i & 0x1 ? > > + IIO_EVENT_CODE_IN_HIGH_THRESH(i >> 1) : > > + IIO_EVENT_CODE_IN_LOW_THRESH(i >> 1), > > + st->last_timestamp); > > + } > > + > > +err_out: > > + enable_irq(st->client->irq); > > +} > > + > > +static int ad799x_interrupt(struct iio_dev *dev_info, > > + int index, > > + s64 timestamp, > > + int no_test) > > +{ > > + struct ad799x_state *st = dev_info->dev_data; > > + > > + st->last_timestamp = timestamp; > > + schedule_work(&st->work_thresh); > > + return 0; > > +} > > + > > +IIO_EVENT_SH(ad799x, &ad799x_interrupt); > > + > > +/* Direct read attribtues */ > > +static IIO_DEV_ATTR_IN_RAW(0, ad799x_read_single_channel, 0); > > +static IIO_DEV_ATTR_IN_RAW(1, ad799x_read_single_channel, 1); > > +static IIO_DEV_ATTR_IN_RAW(2, ad799x_read_single_channel, 2); > > +static IIO_DEV_ATTR_IN_RAW(3, ad799x_read_single_channel, 3); > > +static IIO_DEV_ATTR_IN_RAW(4, ad799x_read_single_channel, 4); > > +static IIO_DEV_ATTR_IN_RAW(5, ad799x_read_single_channel, 5); > > +static IIO_DEV_ATTR_IN_RAW(6, ad799x_read_single_channel, 6); > > +static IIO_DEV_ATTR_IN_RAW(7, ad799x_read_single_channel, 7); > > + > > +static ssize_t ad799x_show_scale(struct device *dev, > > + struct device_attribute *attr, > > + char *buf) > > +{ > > + /* Driver currently only support internal vref */ > > + struct iio_dev *dev_info = dev_get_drvdata(dev); > > + struct ad799x_state *st = iio_dev_get_devdata(dev_info); > > + /* Corresponds to Vref / 2^(bits) */ > > + > > + if ((1 << (st->chip_info->bits + 1)) > > + > st->int_vref_mv) > > + return sprintf(buf, "0.5\n"); > > + else > > + return sprintf(buf, "%d\n", > > + st->int_vref_mv >> st->chip_info->bits); > > +} > > + > > +static IIO_DEVICE_ATTR(in_scale, S_IRUGO, ad799x_show_scale, NULL, > 0); > > + > > +static ssize_t ad799x_show_name(struct device *dev, > > + struct device_attribute *attr, > > + char *buf) > > +{ > > + struct iio_dev *dev_info = dev_get_drvdata(dev); > > + struct ad799x_state *st = iio_dev_get_devdata(dev_info); > > + return sprintf(buf, "%s\n", st->client->name); > > +} > > + > > +static IIO_DEVICE_ATTR(name, S_IRUGO, ad799x_show_name, NULL, 0); > > + > > +static struct attribute *ad7991_5_9_3_4_device_attrs[] = { > > + &iio_dev_attr_in0_raw.dev_attr.attr, > > + &iio_dev_attr_in1_raw.dev_attr.attr, > > + &iio_dev_attr_in2_raw.dev_attr.attr, > > + &iio_dev_attr_in3_raw.dev_attr.attr, > > + &iio_dev_attr_name.dev_attr.attr, > > + &iio_dev_attr_in_scale.dev_attr.attr, > > + NULL > > +}; > > + > > +static struct attribute_group ad7991_5_9_3_4_dev_attr_group = { > > + .attrs = ad7991_5_9_3_4_device_attrs, > > +}; > > + > > +static struct attribute *ad7991_5_9_3_4_scan_el_attrs[] = { > > + &iio_scan_el_in0.dev_attr.attr, > > + &iio_const_attr_in0_index.dev_attr.attr, > > + &iio_scan_el_in1.dev_attr.attr, > > + &iio_const_attr_in1_index.dev_attr.attr, > > + &iio_scan_el_in2.dev_attr.attr, > > + &iio_const_attr_in2_index.dev_attr.attr, > > + &iio_scan_el_in3.dev_attr.attr, > > + &iio_const_attr_in3_index.dev_attr.attr, > > + &iio_dev_attr_in_precision.dev_attr.attr, > > + NULL, > > +}; > > + > > +static struct attribute_group ad7991_5_9_3_4_scan_el_group = { > > + .name = "scan_elements", > > + .attrs = ad7991_5_9_3_4_scan_el_attrs, > > +}; > > + > > +static struct attribute *ad7992_device_attrs[] = { > > + &iio_dev_attr_in0_raw.dev_attr.attr, > > + &iio_dev_attr_in1_raw.dev_attr.attr, > > + &iio_dev_attr_name.dev_attr.attr, > > + &iio_dev_attr_in_scale.dev_attr.attr, > > + NULL > > +}; > > + > > +static struct attribute_group ad7992_dev_attr_group = { > > + .attrs = ad7992_device_attrs, > > +}; > > + > > +static struct attribute *ad7992_scan_el_attrs[] = { > > + &iio_scan_el_in0.dev_attr.attr, > > + &iio_const_attr_in0_index.dev_attr.attr, > > + &iio_scan_el_in1.dev_attr.attr, > > + &iio_const_attr_in1_index.dev_attr.attr, > > + &iio_dev_attr_in_precision.dev_attr.attr, > > + NULL, > > +}; > > + > > +static struct attribute_group ad7992_scan_el_group = { > > + .name = "scan_elements", > > + .attrs = ad7992_scan_el_attrs, > > +}; > > + > > +static struct attribute *ad7997_8_device_attrs[] = { > > + &iio_dev_attr_in0_raw.dev_attr.attr, > > + &iio_dev_attr_in1_raw.dev_attr.attr, > > + &iio_dev_attr_in2_raw.dev_attr.attr, > > + &iio_dev_attr_in3_raw.dev_attr.attr, > > + &iio_dev_attr_in4_raw.dev_attr.attr, > > + &iio_dev_attr_in5_raw.dev_attr.attr, > > + &iio_dev_attr_in6_raw.dev_attr.attr, > > + &iio_dev_attr_in7_raw.dev_attr.attr, > > + &iio_dev_attr_name.dev_attr.attr, > > + &iio_dev_attr_in_scale.dev_attr.attr, > > + NULL > > +}; > > + > > +static struct attribute_group ad7997_8_dev_attr_group = { > > + .attrs = ad7997_8_device_attrs, > > +}; > > + > > +static struct attribute *ad7997_8_scan_el_attrs[] = { > > + &iio_scan_el_in0.dev_attr.attr, > > + &iio_const_attr_in0_index.dev_attr.attr, > > + &iio_scan_el_in1.dev_attr.attr, > > + &iio_const_attr_in1_index.dev_attr.attr, > > + &iio_scan_el_in2.dev_attr.attr, > > + &iio_const_attr_in2_index.dev_attr.attr, > > + &iio_scan_el_in3.dev_attr.attr, > > + &iio_const_attr_in3_index.dev_attr.attr, > > + &iio_scan_el_in4.dev_attr.attr, > > + &iio_const_attr_in4_index.dev_attr.attr, > > + &iio_scan_el_in5.dev_attr.attr, > > + &iio_const_attr_in5_index.dev_attr.attr, > > + &iio_scan_el_in6.dev_attr.attr, > > + &iio_const_attr_in6_index.dev_attr.attr, > > + &iio_scan_el_in7.dev_attr.attr, > > + &iio_const_attr_in7_index.dev_attr.attr, > > + &iio_dev_attr_in_precision.dev_attr.attr, > > + NULL, > > +}; > > + > > +static struct attribute_group ad7997_8_scan_el_group = { > > + .name = "scan_elements", > > + .attrs = ad7997_8_scan_el_attrs, > > +}; > > + > > +IIO_EVENT_ATTR_SH(in0_thresh_low_value, > > + iio_event_ad799x, > > + ad799x_read_channel_config, > > + ad799x_write_channel_config, > > + AD7998_DATALOW_CH1_REG); > > + > > +IIO_EVENT_ATTR_SH(in0_thresh_high_value, > > + iio_event_ad799x, > > + ad799x_read_channel_config, > > + ad799x_write_channel_config, > > + AD7998_DATAHIGH_CH1_REG); > > + > > +IIO_EVENT_ATTR_SH(in0_thresh_both_hyst_raw, > > + iio_event_ad799x, > > + ad799x_read_channel_config, > > + ad799x_write_channel_config, > > + AD7998_HYST_CH1_REG); > > + > > +IIO_EVENT_ATTR_SH(in1_thresh_low_value, > > + iio_event_ad799x, > > + ad799x_read_channel_config, > > + ad799x_write_channel_config, > > + AD7998_DATALOW_CH2_REG); > > + > > +IIO_EVENT_ATTR_SH(in1_thresh_high_value, > > + iio_event_ad799x, > > + ad799x_read_channel_config, > > + ad799x_write_channel_config, > > + AD7998_DATAHIGH_CH2_REG); > > + > > +IIO_EVENT_ATTR_SH(in1_thresh_both_hyst_raw, > > + iio_event_ad799x, > > + ad799x_read_channel_config, > > + ad799x_write_channel_config, > > + AD7998_HYST_CH2_REG); > > + > > +IIO_EVENT_ATTR_SH(in2_thresh_low_value, > > + iio_event_ad799x, > > + ad799x_read_channel_config, > > + ad799x_write_channel_config, > > + AD7998_DATALOW_CH3_REG); > > + > > +IIO_EVENT_ATTR_SH(in2_thresh_high_value, > > + iio_event_ad799x, > > + ad799x_read_channel_config, > > + ad799x_write_channel_config, > > + AD7998_DATAHIGH_CH3_REG); > > + > > +IIO_EVENT_ATTR_SH(in2_thresh_both_hyst_raw, > > + iio_event_ad799x, > > + ad799x_read_channel_config, > > + ad799x_write_channel_config, > > + AD7998_HYST_CH3_REG); > > + > > +IIO_EVENT_ATTR_SH(in3_thresh_low_value, > > + iio_event_ad799x, > > + ad799x_read_channel_config, > > + ad799x_write_channel_config, > > + AD7998_DATALOW_CH4_REG); > > + > > +IIO_EVENT_ATTR_SH(in3_thresh_high_value, > > + iio_event_ad799x, > > + ad799x_read_channel_config, > > + ad799x_write_channel_config, > > + AD7998_DATAHIGH_CH4_REG); > > + > > +IIO_EVENT_ATTR_SH(in3_thresh_both_hyst_raw, > > + iio_event_ad799x, > > + ad799x_read_channel_config, > > + ad799x_write_channel_config, > > + AD7998_HYST_CH4_REG); > > + > > +static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, > > + ad799x_read_frequency, > > + ad799x_write_frequency); > > +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("15625 7812 3906 1953 976 488 > 244 > > 0"); > > + > > +static struct attribute *ad7993_4_7_8_event_attributes[] = { > > + &iio_event_attr_in0_thresh_low_value.dev_attr.attr, > > + &iio_event_attr_in0_thresh_high_value.dev_attr.attr, > > + &iio_event_attr_in0_thresh_both_hyst_raw.dev_attr.attr, > > + &iio_event_attr_in1_thresh_low_value.dev_attr.attr, > > + &iio_event_attr_in1_thresh_high_value.dev_attr.attr, > > + &iio_event_attr_in1_thresh_both_hyst_raw.dev_attr.attr, > > + &iio_event_attr_in2_thresh_low_value.dev_attr.attr, > > + &iio_event_attr_in2_thresh_high_value.dev_attr.attr, > > + &iio_event_attr_in2_thresh_both_hyst_raw.dev_attr.attr, > > + &iio_event_attr_in3_thresh_low_value.dev_attr.attr, > > + &iio_event_attr_in3_thresh_high_value.dev_attr.attr, > > + &iio_event_attr_in3_thresh_both_hyst_raw.dev_attr.attr, > > + &iio_dev_attr_sampling_frequency.dev_attr.attr, > > + &iio_const_attr_sampling_frequency_available.dev_attr.attr, > > + NULL, > > +}; > > + > > +static struct attribute_group ad7993_4_7_8_event_attrs_group = { > > + .attrs = ad7993_4_7_8_event_attributes, > > +}; > > + > > +static struct attribute *ad7992_event_attributes[] = { > > + &iio_event_attr_in0_thresh_low_value.dev_attr.attr, > > + &iio_event_attr_in0_thresh_high_value.dev_attr.attr, > > + &iio_event_attr_in0_thresh_both_hyst_raw.dev_attr.attr, > > + &iio_event_attr_in1_thresh_low_value.dev_attr.attr, > > + &iio_event_attr_in1_thresh_high_value.dev_attr.attr, > > + &iio_event_attr_in1_thresh_both_hyst_raw.dev_attr.attr, > > + &iio_dev_attr_sampling_frequency.dev_attr.attr, > > + &iio_const_attr_sampling_frequency_available.dev_attr.attr, > > + NULL, > > +}; > > + > > +static struct attribute_group ad7992_event_attrs_group = { > > + .attrs = ad7992_event_attributes, > > +}; > > + > > +static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { > > + [ad7991] = { > > + .num_inputs = 4, > > + .bits = 12, > > + .int_vref_mv = 4096, > > + .dev_attrs = &ad7991_5_9_3_4_dev_attr_group, > > + .scan_attrs = &ad7991_5_9_3_4_scan_el_group, > > + .ad799x_set_scan_mode = ad7991_5_9_set_scan_mode, > > + }, > > + [ad7995] = { > > + .num_inputs = 4, > > + .bits = 10, > > + .int_vref_mv = 1024, > > + .dev_attrs = &ad7991_5_9_3_4_dev_attr_group, > > + .scan_attrs = &ad7991_5_9_3_4_scan_el_group, > > + .ad799x_set_scan_mode = ad7991_5_9_set_scan_mode, > > + }, > > + [ad7999] = { > > + .num_inputs = 4, > > + .bits = 10, > > + .int_vref_mv = 1024, > > + .dev_attrs = &ad7991_5_9_3_4_dev_attr_group, > > + .scan_attrs = &ad7991_5_9_3_4_scan_el_group, > > + .ad799x_set_scan_mode = ad7991_5_9_set_scan_mode, > > + }, > > + [ad7992] = { > > + .num_inputs = 2, > > + .bits = 12, > > + .int_vref_mv = 4096, > > + .monitor_mode = true, > > + .default_config = AD7998_ALERT_EN, > > + .dev_attrs = &ad7992_dev_attr_group, > > + .scan_attrs = &ad7992_scan_el_group, > > + .event_attrs = &ad7992_event_attrs_group, > > + .ad799x_set_scan_mode = ad7992_3_4_set_scan_mode, > > + }, > > + [ad7993] = { > > + .num_inputs = 4, > > + .bits = 10, > > + .int_vref_mv = 1024, > > + .monitor_mode = true, > > + .default_config = AD7998_ALERT_EN, > > + .dev_attrs = &ad7991_5_9_3_4_dev_attr_group, > > + .scan_attrs = &ad7991_5_9_3_4_scan_el_group, > > + .event_attrs = &ad7993_4_7_8_event_attrs_group, > > + .ad799x_set_scan_mode = ad7992_3_4_set_scan_mode, > > + }, > > + [ad7994] = { > > + .num_inputs = 4, > > + .bits = 12, > > + .int_vref_mv = 4096, > > + .monitor_mode = true, > > + .default_config = AD7998_ALERT_EN, > > + .dev_attrs = &ad7991_5_9_3_4_dev_attr_group, > > + .scan_attrs = &ad7991_5_9_3_4_scan_el_group, > > + .event_attrs = &ad7993_4_7_8_event_attrs_group, > > + .ad799x_set_scan_mode = ad7992_3_4_set_scan_mode, > > + }, > > + [ad7997] = { > > + .num_inputs = 8, > > + .bits = 10, > > + .int_vref_mv = 1024, > > + .monitor_mode = true, > > + .default_config = AD7998_ALERT_EN, > > + .dev_attrs = &ad7997_8_dev_attr_group, > > + .scan_attrs = &ad7997_8_scan_el_group, > > + .event_attrs = &ad7993_4_7_8_event_attrs_group, > > + .ad799x_set_scan_mode = ad7997_8_set_scan_mode, > > + }, > > + [ad7998] = { > > + .num_inputs = 8, > > + .bits = 12, > > + .int_vref_mv = 4096, > > + .monitor_mode = true, > > + .default_config = AD7998_ALERT_EN, > > + .dev_attrs = &ad7997_8_dev_attr_group, > > + .scan_attrs = &ad7997_8_scan_el_group, > > + .event_attrs = &ad7993_4_7_8_event_attrs_group, > > + .ad799x_set_scan_mode = ad7997_8_set_scan_mode, > > + }, > > +}; > > + > > +static int __devinit ad799x_probe(struct i2c_client *client, > > + const struct i2c_device_id *id) > > +{ > > + int ret, regdone = 0; > > + struct ad799x_platform_data *pdata = client->dev.platform_data; > > + struct ad799x_state *st = kzalloc(sizeof(*st), GFP_KERNEL); > > + if (st == NULL) { > > + ret = -ENOMEM; > > + goto error_ret; > > + } > > + > > + /* this is only used for device removal purposes */ > > + i2c_set_clientdata(client, st); > > + > > + atomic_set(&st->protect_ring, 0); > > + st->id = id->driver_data; > > + st->chip_info = &ad799x_chip_info_tbl[st->id]; > > + st->config = st->chip_info->default_config; > > + > > + /* TODO: Add pdata options for filtering and bit delay */ > > + > > + if (pdata) > > + st->int_vref_mv = pdata->vref_mv; > > + else > > + st->int_vref_mv = st->chip_info->int_vref_mv; > > + > > + st->reg = regulator_get(&client->dev, "vcc"); > > + if (!IS_ERR(st->reg)) { > > + ret = regulator_enable(st->reg); > > + if (ret) > > + goto error_put_reg; > > + } > > + st->client = client; > > + > > + st->indio_dev = iio_allocate_device(); > > + if (st->indio_dev == NULL) { > > + ret = -ENOMEM; > > + goto error_disable_reg; > > + } > > + > > + /* Estabilish that the iio_dev is a child of the i2c device */ > > + st->indio_dev->dev.parent = &client->dev; > > + st->indio_dev->attrs = st->chip_info->dev_attrs; > > + st->indio_dev->event_attrs = st->chip_info->event_attrs; > > + > > + st->indio_dev->dev_data = (void *)(st); > > + st->indio_dev->driver_module = THIS_MODULE; > > + st->indio_dev->modes = INDIO_DIRECT_MODE; > > + st->indio_dev->num_interrupt_lines = 1; > > + > > + ret = ad799x_set_scan_mode(st, 0); > > + if (ret) > > + goto error_free_device; > > + > > + ret = ad799x_register_ring_funcs_and_init(st->indio_dev); > > + if (ret) > > + goto error_free_device; > > + > > + ret = iio_device_register(st->indio_dev); > > + if (ret) > > + goto error_cleanup_ring; > > + regdone = 1; > > + > > + ret = iio_ring_buffer_register(st->indio_dev->ring, 0); > > + if (ret) > > + goto error_cleanup_ring; > > + > > + if (client->irq > 0 && st->chip_info->monitor_mode) { > > + INIT_WORK(&st->work_thresh, ad799x_interrupt_bh); > > + > > + ret = iio_register_interrupt_line(client->irq, > > + st->indio_dev, > > + 0, > > + IRQF_TRIGGER_FALLING, > > + client->name); > > + if (ret) > > + goto error_cleanup_ring; > > + > > + /* > > + * The event handler list element refer to > iio_event_ad799x. > > + * All event attributes bind to the same event handler. > > + * So, only register event handler once. > > + */ > > + iio_add_event_to_list(&iio_event_ad799x, > > + &st->indio_dev->interrupts[0]- > >ev_list); > > + } > > + > > + return 0; > > +error_cleanup_ring: > > + ad799x_ring_cleanup(st->indio_dev); > > +error_free_device: > > + if (!regdone) > > Where is regdone populated if it is always 1 we may remove the check. Regdone is only set in case iio_device_register() succeeds. > > + iio_free_device(st->indio_dev); > > + else > > + iio_device_unregister(st->indio_dev); > > +error_disable_reg: > > + if (!IS_ERR(st->reg)) > > + regulator_disable(st->reg); > > +error_put_reg: > > + if (!IS_ERR(st->reg)) > > + regulator_put(st->reg); > > + kfree(st); > > +error_ret: > > + return ret; > > +} > > + > > +static __devexit int ad799x_remove(struct i2c_client *client) > > +{ > > + struct ad799x_state *st = i2c_get_clientdata(client); > > + struct iio_dev *indio_dev = st->indio_dev; > > + > > + if (client->irq > 0 && st->chip_info->monitor_mode) > > + iio_unregister_interrupt_line(indio_dev, 0); > > + > > + iio_ring_buffer_unregister(indio_dev->ring); > > + ad799x_ring_cleanup(indio_dev); > > + iio_device_unregister(indio_dev); > > + if (!IS_ERR(st->reg)) { > > + regulator_disable(st->reg); > > + regulator_put(st->reg); > > + } > > + kfree(st); > > + > > + return 0; > > +} > > + > > +static const struct i2c_device_id ad799x_id[] = { > > + { "ad7991", ad7991 }, > > + { "ad7995", ad7995 }, > > + { "ad7999", ad7999 }, > > + { "ad7992", ad7992 }, > > + { "ad7993", ad7993 }, > > + { "ad7994", ad7994 }, > > + { "ad7997", ad7997 }, > > + { "ad7998", ad7998 }, > > + {} > > +}; > > + > > +MODULE_DEVICE_TABLE(i2c, ad799x_id); > > + > > +static struct i2c_driver ad799x_driver = { > > + .driver = { > > + .name = "ad799x", > > + }, > > + .probe = ad799x_probe, > > + .remove = __devexit_p(ad799x_remove), > > + .id_table = ad799x_id, > > +}; > > + > > +static __init int ad799x_init(void) > > +{ > > + return i2c_add_driver(&ad799x_driver); > > +} > > + > > +static __exit void ad799x_exit(void) > > +{ > > + i2c_del_driver(&ad799x_driver); > > +} > > + > > +MODULE_AUTHOR("Michael Hennerich <hennerich@xxxxxxxxxxxxxxxxxxxx>"); > > +MODULE_DESCRIPTION("Analog Devices AD799x ADC"); > > +MODULE_LICENSE("GPL v2"); > > +MODULE_ALIAS("i2c:ad799x"); > > + > > +module_init(ad799x_init); > > +module_exit(ad799x_exit); > > diff --git a/drivers/staging/iio/adc/ad799x_ring.c > > b/drivers/staging/iio/adc/ad799x_ring.c > > new file mode 100644 > > index 0000000..0f2041a > > --- /dev/null > > +++ b/drivers/staging/iio/adc/ad799x_ring.c > > @@ -0,0 +1,246 @@ > > +/* > > + * Copyright (C) 2010 Michael Hennerich, Analog Devices Inc. > > + * Copyright (C) 2008-2010 Jonathan Cameron > > + * > > + * This program is free software; you can redistribute it and/or > modify > > + * it under the terms of the GNU General Public License version 2 as > > + * published by the Free Software Foundation. > > + * > > + * ad799x_ring.c > > + */ > > + > > +#include <linux/interrupt.h> > > +#include <linux/workqueue.h> > > +#include <linux/device.h> > > +#include <linux/slab.h> > > +#include <linux/kernel.h> > > +#include <linux/sysfs.h> > > +#include <linux/list.h> > > +#include <linux/i2c.h> > > +#include <linux/bitops.h> > > + > > +#include "../iio.h" > > +#include "../ring_generic.h" > > +#include "../ring_sw.h" > > +#include "../trigger.h" > > +#include "../sysfs.h" > > + > > +#include "ad799x.h" > > + > > +int ad799x_single_channel_from_ring(struct ad799x_state *st, long > mask) > > +{ > > + unsigned long numvals; > > + int count = 0, ret; > > + u16 *ring_data; > > + if (!(st->indio_dev->ring->scan_mask & mask)) { > > + ret = -EBUSY; > > + goto error_ret; > > + } > > + numvals = st->indio_dev->ring->scan_count; > > + > > + ring_data = kmalloc(numvals*2, GFP_KERNEL); > > + if (ring_data == NULL) { > > + ret = -ENOMEM; > > + goto error_ret; > > + } > > + ret = st->indio_dev->ring->access.read_last(st->indio_dev- > >ring, > > + (u8 *) ring_data); > > + if (ret) > > + goto error_free_ring_data; > > + /* Need a count of channels prior to this one */ > > + mask >>= 1; > > + while (mask) { > > + if (mask & st->indio_dev->ring->scan_mask) > > + count++; > > + mask >>= 1; > > + } > > + > > + ret = be16_to_cpu(ring_data[count]) & 0xFFF; > > + > > +error_free_ring_data: > > + kfree(ring_data); > > +error_ret: > > + return ret; > > +} > > + > > +/** > > + * ad799x_ring_preenable() setup the parameters of the ring before > > enabling > > + * > > + * The complex nature of the setting of the nuber of bytes per datum > is > > due > > + * to this driver currently ensuring that the timestamp is stored at > an 8 > > + * byte boundary. > > + **/ > > +static int ad799x_ring_preenable(struct iio_dev *indio_dev) > > +{ > > + struct ad799x_state *st = indio_dev->dev_data; > > + size_t d_size; > > + unsigned long numvals; > > + > > + /* > > + * Need to figure out the current mode based upon the requested > > + * scan mask in iio_dev > > + */ > > + > > + if (st->id == ad7997 || st->id == ad7998) > > + ad799x_set_scan_mode(st, st->indio_dev->ring- > >scan_mask); > > + > > + numvals = st->indio_dev->ring->scan_count; > > + > > + if (indio_dev->ring->access.set_bytes_per_datum) { > > + d_size = numvals*2 + sizeof(s64); > > + if (d_size % 8) > > + d_size += 8 - (d_size % 8); > > + indio_dev->ring->access.set_bytes_per_datum(indio_dev- > >ring, > > + d_size); > > + } > > + > > + return 0; > > +} > > + > > +/** > > + * ad799x_poll_func_th() th of trigger launched polling to ring > buffer > > + * > > + * As sampling only occurs on i2c comms occuring, leave timestamping > > until > > + * then. Some triggers will generate their own time stamp. > Currently > > + * there is no way of notifying them when no one cares. > > + **/ > > +static void ad799x_poll_func_th(struct iio_dev *indio_dev, s64 time) > > +{ > > + struct ad799x_state *st = indio_dev->dev_data; > > + > > + schedule_work(&st->poll_work); > > + > > + return; > > +} > > +/** > > + * ad799x_poll_bh_to_ring() bh of trigger launched polling to ring > buffer > > + * @work_s: the work struct through which this was scheduled > > + * > > + * Currently there is no option in this driver to disable the saving > of > > + * timestamps within the ring. > > + * I think the one copy of this at a time was to avoid problems if > the > > + * trigger was set far too high and the reads then locked up the > > computer. > > + **/ > > +static void ad799x_poll_bh_to_ring(struct work_struct *work_s) > > +{ > > + struct ad799x_state *st = container_of(work_s, struct > ad799x_state, > > + poll_work); > > + struct iio_dev *indio_dev = st->indio_dev; > > + struct iio_sw_ring_buffer *ring = iio_to_sw_ring(indio_dev- > >ring); > > + s64 time_ns; > > + __u8 *rxbuf; > > + int b_sent; > > + size_t d_size; > > + u8 cmd; > > + > > + unsigned long numvals = st->indio_dev->ring->scan_count; > > + > > + /* Ensure the timestamp is 8 byte aligned */ > > + d_size = numvals*2 + sizeof(s64); > > + > > + if (d_size % sizeof(s64)) > > + d_size += sizeof(s64) - (d_size % sizeof(s64)); > > + > > + /* Ensure only one copy of this function running at a time */ > > + if (atomic_inc_return(&st->protect_ring) > 1) > > + return; > > + > > + /* Monitor mode prevents reading. Whilst not currently > implemented > > + * might as well have this test in here in the meantime as it > does > > + * no harm. > > + */ > > + if (numvals == 0) > > + return; > > + > > + rxbuf = kmalloc(d_size, GFP_KERNEL); > > + if (rxbuf == NULL) > > + return; > > + > > + switch (st->id) { > > + case ad7991: > > + case ad7995: > > + case ad7999: > > + cmd = st->config | (st->indio_dev->ring->scan_mask << > > + AD799X_CHANNEL_SHIFT); > > + break; > > + case ad7992: > > + case ad7993: > > + case ad7994: > > + cmd = (st->indio_dev->ring->scan_mask << > > + AD799X_CHANNEL_SHIFT) | AD7998_CONV_RES_REG; > > + break; > > + case ad7997: > > + case ad7998: > > + cmd = AD7997_8_READ_SEQUENCE | AD7998_CONV_RES_REG; > > + break; > > + default: > > + cmd = 0; > > + } > > + > > + b_sent = i2c_smbus_read_i2c_block_data(st->client, > > + cmd, numvals*2, rxbuf); > > + if (b_sent < 0) > > + goto done; > > + > > + time_ns = iio_get_time_ns(); > > + > > + memcpy(rxbuf + d_size - sizeof(s64), &time_ns, > sizeof(time_ns)); > > + > > + indio_dev->ring->access.store_to(&ring->buf, rxbuf, time_ns); > > +done: > > + kfree(rxbuf); > > + atomic_dec(&st->protect_ring); > > +} > > + > > + > > +int ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev) > > +{ > > + struct ad799x_state *st = indio_dev->dev_data; > > + int ret = 0; > > + > > + indio_dev->ring = iio_sw_rb_allocate(indio_dev); > > + if (!indio_dev->ring) { > > + ret = -ENOMEM; > > + goto error_ret; > > + } > > + /* Effectively select the ring buffer implementation */ > > + iio_ring_sw_register_funcs(&st->indio_dev->ring->access); > > + indio_dev->pollfunc = kzalloc(sizeof(*indio_dev->pollfunc), > > GFP_KERNEL); > > + if (indio_dev->pollfunc == NULL) { > > + ret = -ENOMEM; > > + goto error_deallocate_sw_rb; > > + } > > + /* Configure the polling function called on trigger interrupts > */ > > + indio_dev->pollfunc->poll_func_main = &ad799x_poll_func_th; > > + indio_dev->pollfunc->private_data = indio_dev; > > + > > + /* Ring buffer functions - here trigger setup related */ > > + > > + indio_dev->ring->preenable = &ad799x_ring_preenable; > > + indio_dev->ring->postenable = &iio_triggered_ring_postenable; > > + indio_dev->ring->predisable = &iio_triggered_ring_predisable; > > + > > + INIT_WORK(&st->poll_work, &ad799x_poll_bh_to_ring); > > + > > + indio_dev->ring->scan_el_attrs = st->chip_info->scan_attrs; > > + > > + /* Flag that polled ring buffering is possible */ > > + indio_dev->modes |= INDIO_RING_TRIGGERED; > > + return 0; > > +error_deallocate_sw_rb: > > + iio_sw_rb_free(indio_dev->ring); > > +error_ret: > > + return ret; > > +} > > + > > +void ad799x_ring_cleanup(struct iio_dev *indio_dev) > > +{ > > + /* ensure that the trigger has been detached */ > > + if (indio_dev->trig) { > > + iio_put_trigger(indio_dev->trig); > > + iio_trigger_dettach_poll_func(indio_dev->trig, > > + indio_dev->pollfunc); > > + } > > + kfree(indio_dev->pollfunc); > > + iio_sw_rb_free(indio_dev->ring); > > +} > > -- > > 1.6.0.2 > > > > -- > > 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 -- 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