> -----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. > + > + 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. > + 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