* [RFC] staging: iio: adc: Enable driver support for ad799x AD converters
@ 2010-10-01 9:41 Michael Hennerich
2010-10-01 9:41 ` [PATCH] " Michael Hennerich
0 siblings, 1 reply; 10+ messages in thread
From: Michael Hennerich @ 2010-10-01 9:41 UTC (permalink / raw)
To: linux-iio; +Cc: drivers
Driver for ad7991, ad7995, ad7999, ad7992, ad7993, ad7994, ad7997 and
ad7998 multichannel ADC.
This patch has been send for review before. However we failed to send it
to Greg. Recent IIO API changes required a few updates.
Greetings,
Michael
Analog Devices GmbH Wilhelm-Wagenfeld-Str. 6 80807 Muenchen
Sitz der Gesellschaft Muenchen, Registergericht Muenchen HRB 4036
Geschaeftsfuehrer Thomas Wessel, William A. Martin, Margaret Seif
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH] staging: iio: adc: Enable driver support for ad799x AD converters
2010-10-01 9:41 [RFC] staging: iio: adc: Enable driver support for ad799x AD converters Michael Hennerich
@ 2010-10-01 9:41 ` Michael Hennerich
2010-10-01 12:09 ` Jonathan Cameron
0 siblings, 1 reply; 10+ messages in thread
From: Michael Hennerich @ 2010-10-01 9:41 UTC (permalink / raw)
To: linux-iio; +Cc: drivers
Driver for ad7991, ad7995, ad7999, ad7992, ad7993, ad7994, ad7997 and
ad7998 multichannel ADC.
Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
---
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;
+
+ 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)
+ 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@blackfin.uclinux.org>");
+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
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH] staging: iio: adc: Enable driver support for ad799x AD converters
2010-10-01 9:41 ` [PATCH] " Michael Hennerich
@ 2010-10-01 12:09 ` Jonathan Cameron
2010-10-01 15:07 ` Hennerich, Michael
0 siblings, 1 reply; 10+ messages in thread
From: Jonathan Cameron @ 2010-10-01 12:09 UTC (permalink / raw)
To: Michael Hennerich; +Cc: linux-iio, drivers
Hi Michael,
I was pretty much happy with this last time round. Couple of comments
inline. The new line missing in the Makefile is probably the only one
that I'd advocate doing pre merge.
The precision attrs have gone away to be replaced by the more informative
type attributes in the scan_elements directory. This can trivially be
done as an additional patch post merge.
There are some subtle changes to the event naming (post discussion on lkml)
but I'll just do this driver alongside the others in the patch set implementing
those changes. This is the first driver providing hyst so that attribute
will also need documenting. Again that should happen post merge.
I think we can also take advantage of some of the helper functions that are
now in place for buffer registration (came out of Barry's work), but that
can definitely happen at a later date.
So in summary I'm happy to see this merge right now. The sooner the better as
far as I'm concerned because I would like it to go in before the event clean up
series currently sat in my tree. That way I can update this one at the same time.
Acked-by: Jonathan Cameron <jic23@cam.ac.uk>
Please send on to Greg KH <greg@kroah.com> for him to merge.
Thanks,
Jonathan
> Driver for ad7991, ad7995, ad7999, ad7992, ad7993, ad7994, ad7997 and
> ad7998 multichannel ADC.
>
> Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
> ---
> 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"
I'll express my usual anti comment on driver names with wild cards,
but as there are hardly any numbers left in the range it is probably fine
here.
> + 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
Please add a new line after this.
> \ 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
Typo in comment.
> + */
> +
> +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;
> +
> + 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,
The precision attribute has been replaced by the _type
attributes in the scan_elements directory as they give
all the information in one consice form. Lets do that
change as an additional patch post merge though.
> + &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 */
We also need to add userspace attributes to cover filtering for these
devices. However, that is definitely a discussion for another day!
> +
> + 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)
> + 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@blackfin.uclinux.org>");
> +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);
> +}
^ permalink raw reply [flat|nested] 10+ messages in thread
* RE: [PATCH] staging: iio: adc: Enable driver support for ad799x AD converters
2010-10-01 12:09 ` Jonathan Cameron
@ 2010-10-01 15:07 ` Hennerich, Michael
2010-10-01 15:50 ` Jonathan Cameron
0 siblings, 1 reply; 10+ messages in thread
From: Hennerich, Michael @ 2010-10-01 15:07 UTC (permalink / raw)
To: Jonathan Cameron; +Cc: linux-iio@vger.kernel.org, Drivers
Jonathan Cameron wrote on 2010-10-01:
> Hi Michael,
>
> I was pretty much happy with this last time round. Couple of comments
> inline. The new line missing in the Makefile is probably the only one
> that I'd advocate doing pre merge.
>
> The precision attrs have gone away to be replaced by the more
> informative type attributes in the scan_elements directory. This can
> trivially be done as an additional patch post merge.
>
> There are some subtle changes to the event naming (post discussion on
> lkml) but I'll just do this driver alongside the others in the patch
> set implementing those changes. This is the first driver providing
> hyst so that attribute will also need documenting. Again that should
> happen post merge.
>
> I think we can also take advantage of some of the helper functions
> that are now in place for buffer registration (came out of Barry's
> work), but that can definitely happen at a later date.
>
> So in summary I'm happy to see this merge right now. The sooner the
> better as far as I'm concerned
Hi Jonathan,
We have a few more iio drivers in our repository. Over the next couple
of weeks I'm trying to get them out.
> because I would like it to go in before
> the event clean up series currently sat in my tree. That way I can
> update this one at the same time.
Oops - this patch was already against your tree:
http://git.kernel.org/?p=3Dlinux/kernel/git/jic23/iio_temp.git
Need to check if it works on Greg's staging.
...It's time to get out of staging
> Acked-by: Jonathan Cameron <jic23@cam.ac.uk>
>
> Please send on to Greg KH <greg@kroah.com> for him to merge.
>
> Thanks,
>
> Jonathan
>
>> Driver for ad7991, ad7995, ad7999, ad7992, ad7993, ad7994, ad7997
>> and
>> ad7998 multichannel ADC.
>>
>> Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
>> ---
>> 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"
> I'll express my usual anti comment on driver names with wild cards,
> but as there are hardly any numbers left in the range it is probably
> fine here.
>> + 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 :=3D max1363_core.o max1363-y +=3D
>> max1363_ring.o
>>
>> obj-$(CONFIG_MAX1363) +=3D max1363.o
>> + +ad799x-y :=3D ad799x_core.o +ad799x-$(CONFIG_AD799X_RING_BUFFER) +=3D
>> ad799x_ring.o +obj-$(CONFIG_AD799X) +=3D ad799x.o Please add a new line
>> after this. \ 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_DELA=
Y 0x02 +#define
>> AD7991_SAMPLE_DELAY 0x01 + +/* + * AD7992, AD7993, AD79=
94, AD7997 and
>> AD7998 defines */ + +#define AD7998_FLTR 0x0=
8 +#define
>> AD7998_ALERT_EN 0x04 +#define AD7998_BUSY_A=
LERT 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_DATAHIG=
H_CH1_REG 0x5
>> +#define AD7998_HYST_CH1_REG 0x6 +#define
>> AD7998_DATALOW_CH2_REG 0x7 +#define AD7998_DATAHIG=
H_CH2_REG 0x8
>> +#define AD7998_HYST_CH2_REG 0x9 +#define
>> AD7998_DATALOW_CH3_REG 0xA +#define AD7998_DATAHIG=
H_CH3_REG 0xB
>> +#define AD7998_HYST_CH3_REG 0xC +#define
>> AD7998_DATALOW_CH4_REG 0xD +#define AD7998_DATAHIG=
H_CH4_REG 0xE
>> +#define AD7998_HYST_CH4_REG 0xF + +#define AD7998_CYC_M=
ASK 0x7
>> +#define AD7998_CYC_DIS 0x0 +#define AD7998=
_CYC_TCONF_32 0x1
>> +#define AD7998_CYC_TCONF_64 0x2 +#define AD7998_CYC_TCO=
NF_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_SEQUENC=
E 0x70 +
>> +enum { + ad7991, + ad7995, + ad7999, + ad7992, + =
ad7993, + ad7994,
>> + ad7997, + ad7998 +}; + +struct ad799x_state; + +/** + * struc=
t
>> ad799x_chip_info - chip specifc information + * @num_inputs: num=
ber 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 devi=
ce attribute
>> group + * @scan_attrs: pointer to the scan element attribu=
te 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 attr=
ibute_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 pol=
l_work; + struct
>> work_struct work_thresh; + atomic_t pro=
tect_ring; + struct
>> iio_trigger *trig; + struct regulator *re=
g; + 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 Typo in comment. + */ + +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_d=
ev
>> *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 =
=3D
>> st->client; + int ret =3D 0; + + ret =3D i2c_smbus_read_wo=
rd_data(client,
>> reg); + if (ret < 0) { + dev_err(&client->dev, "I2C =
read error\n");
>> + return ret; + } + + *data =3D swab16((u16)ret); + + r=
eturn 0; +} +
>> +static int ad799x_i2c_read8(struct ad799x_state *st, u8 reg, u8
>> +*data) { + struct i2c_client *client =3D st->client; + int ret =
=3D 0; +
>> + ret =3D i2c_smbus_read_word_data(client, reg); + if (ret < 0) {
>> + dev_err(&client->dev, "I2C read error\n"); + ret=
urn ret; + } +
>> + *data =3D ret; + + return 0; +} + +static int ad799x_i2c_wri=
te16(struct
>> ad799x_state *st, u8 reg, u16 +data) { + struct i2c_client *client =
=3D
>> st->client; + int ret =3D 0; + + ret =3D i2c_smbus_write_w=
ord_data(client,
>> reg, swab16(data)); + if (ret < 0) + dev_err(&client->de=
v, "I2C write
>> error\n"); + + return ret; +} + +static int ad799x_i2c_write8(stru=
ct
>> ad799x_state *st, u8 reg, u8 +data) { + struct i2c_client *client =
=3D
>> st->client; + int ret =3D 0; + + ret =3D i2c_smbus_write_b=
yte_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 =3D 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 *at=
tr, + char *buf) +{
>> + struct iio_dev *dev_info =3D dev_get_drvdata(dev); + struct
>> ad799x_state *st =3D iio_dev_get_devdata(dev_info); + return sprintf(bu=
f,
>> "%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 !=3D NULL) { + ret =3D
>> 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 =3D dev_get_drvdata(dev); + struct ad799x_state *st =3D
>> iio_dev_get_devdata(dev_info); + struct iio_dev_attr *this_attr =3D
>> to_iio_dev_attr(attr); + int ret =3D 0, len =3D 0; + u32 data ; + =
u16
>> rxbuf[1]; + u8 cmd; + long mask; + + mutex_lock(&dev_info->mlock=
);
>> + mask =3D 1 << this_attr->address; + /* If ring buffer capture=
is
>> occuring, query the buffer */ + if (iio_ring_enabled(dev_info)) {
>> + data =3D ad799x_single_channel_from_ring(st, mask); + =
if (data < 0) {
>> + ret =3D data; + goto error_ret; +=
} + } else { + switch (st->id)
>> { + case ad7991: + case ad7995: + case ad7999=
: + cmd =3D st->config
>> | (mask << AD799X_CHANNEL_SHIFT); + break; + =
case ad7992: + case
>> ad7993: + case ad7994: + cmd =3D mask << AD7=
99X_CHANNEL_SHIFT;
>> + break; + case ad7997: + cas=
e ad7998: + cmd =3D
>> (this_attr->address << + AD799X_CHANNEL_SHIF=
T) |
>> AD7997_8_READ_SINGLE; + break; + def=
ault: + cmd =3D 0; + + } + ret
>> =3D ad799x_i2c_read16(st, cmd, rxbuf); + if (ret < 0) + =
goto
>> error_ret; + + data =3D rxbuf[0] & 0xFFF; + } + + /=
* Pretty print the
>> result */ + len =3D 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
>> =3D dev_get_drvdata(dev); + struct ad799x_state *st =3D
>> iio_dev_get_devdata(dev_info); + + int ret, len =3D 0; + u8 val; +=
ret =3D
>> ad799x_i2c_read8(st, AD7998_CYCLE_TMR_REG, &val); + if (ret) + =
return
>> ret; + + val &=3D AD7998_CYC_MASK; + + switch (val) { + c=
ase
>> AD7998_CYC_DIS: + len =3D sprintf(buf, "0\n"); + b=
reak; + case
>> AD7998_CYC_TCONF_32: + len =3D sprintf(buf, "15625\n"); + =
break; + case
>> AD7998_CYC_TCONF_64: + len =3D sprintf(buf, "7812\n"); + =
break; + case
>> AD7998_CYC_TCONF_128: + len =3D sprintf(buf, "3906\n"); + =
break; + case
>> AD7998_CYC_TCONF_256: + len =3D sprintf(buf, "1953\n"); + =
break; + case
>> AD7998_CYC_TCONF_512: + len =3D sprintf(buf, "976\n"); + =
break; + case
>> AD7998_CYC_TCONF_1024: + len =3D sprintf(buf, "488\n"); + =
break; + case
>> AD7998_CYC_TCONF_2048: + len =3D sprintf(buf, "244\n"); + =
break; + }
>> + return len; +} + +static ssize_t ad799x_write_frequency(struct devi=
ce
>> *dev, + struct device_attribute *a=
ttr, + const char *buf,
>> + size_t len) +{ + struct iio_=
dev *dev_info =3D
>> dev_get_drvdata(dev); + struct ad799x_state *st =3D
>> iio_dev_get_devdata(dev_info); + + long val; + int ret; + u8 =
t; + + ret
>> =3D strict_strtol(buf, 10, &val); + if (ret) + return re=
t; +
>> + mutex_lock(&dev_info->mlock); + ret =3D ad799x_i2c_read8(st,
>> AD7998_CYCLE_TMR_REG, &t); + if (ret) + goto error_ret_mute=
x; + /*
>> Wipe the bits clean */ + t &=3D ~AD7998_CYC_MASK; + + switch (v=
al) {
>> + case 15625: + t |=3D AD7998_CYC_TCONF_32; + b=
reak; + case 7812: + t
>> |=3D AD7998_CYC_TCONF_64; + break; + case 3906: + =
t |=3D
>> AD7998_CYC_TCONF_128; + break; + case 1953: + =
t |=3D
>> AD7998_CYC_TCONF_256; + break; + case 976: + =
t |=3D
>> AD7998_CYC_TCONF_512; + break; + case 488: + =
t |=3D
>> AD7998_CYC_TCONF_1024; + break; + case 244: + =
t |=3D
>> AD7998_CYC_TCONF_2048; + break; + case 0: + =
t |=3D AD7998_CYC_DIS;
>> + break; + default: + ret =3D -EINVAL; + =
goto error_ret_mutex; + } +
>> + ret =3D 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_attri=
bute *attr, + char *buf) +{
>> + struct iio_dev *dev_info =3D dev_get_drvdata(dev); + struct
>> ad799x_state *st =3D iio_dev_get_devdata(dev_info); + struct
>> iio_event_attr *this_attr =3D to_iio_event_attr(attr); + + int ret; =
+ u16
>> val; + ret =3D ad799x_i2c_read16(st, this_attr->mask, &val); + i=
f (ret)
>> + return ret; + + return sprintf(buf, "%d\n", val); +} + +sta=
tic
>> ssize_t ad799x_write_channel_config(struct device *dev, + =
struct
>> device_attribute *attr, + const char=
*buf, + size_t len) +{
>> + struct iio_dev *dev_info =3D dev_get_drvdata(dev); + struct
>> ad799x_state *st =3D iio_dev_get_devdata(dev_info); + struct
>> iio_event_attr *this_attr =3D to_iio_event_attr(attr); + + long val;
>> + int ret; + + ret =3D strict_strtol(buf, 10, &val); + if (ret) =
+ return
>> ret; + + mutex_lock(&dev_info->mlock); + ret =3D ad799x_i2c_write16(=
st,
>> this_attr->mask, val); + mutex_unlock(&dev_info->mlock); + + ret=
urn ret
>> ? ret : len; +} + +static void ad799x_interrupt_bh(struct work_struct
>> *work_s) { + struct ad799x_state *st =3D container_of(work_s, + =
struct
>> ad799x_state, work_thresh); + u8 status; + int i; + + if
>> (ad799x_i2c_read8(st, AD7998_ALERT_STAT_REG, &status)) + got=
o err_out;
>> + + if (!status) + goto err_out; + + ad799x_i2c_write8(s=
t,
>> AD7998_ALERT_STAT_REG, +AD7998_ALERT_STAT_CLEAR); + + for (i =3D =
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 =3D
>> dev_info->dev_data; + + st->last_timestamp =3D 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 =3D
>> dev_get_drvdata(dev); + struct ad799x_state *st =3D
>> 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 spri=
ntf(buf, "%d\n",
>> + st->int_vref_mv >> st->chip_info->bits); } + +stati=
c
>> 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
>> =3D dev_get_drvdata(dev); + struct ad799x_state *st =3D
>> 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[] =3D {
>> + &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 =3D { + .attrs =3D
>> ad7991_5_9_3_4_device_attrs, }; + +static struct attribute
>> *ad7991_5_9_3_4_scan_el_attrs[] =3D { + &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,
> The precision attribute has been replaced by the _type attributes in the
> scan_elements directory as they give all the information in one consice
> form. Lets do that change as an additional patch post merge though.
>
>> + &iio_dev_attr_in_precision.dev_attr.attr,
>> + NULL,
>> +};
>> +
>> +static struct attribute_group ad7991_5_9_3_4_scan_el_group =3D {
>> + .name =3D "scan_elements",
>> + .attrs =3D ad7991_5_9_3_4_scan_el_attrs, };
>> +
>> +static struct attribute *ad7992_device_attrs[] =3D {
>> + &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 =3D {
>> + .attrs =3D ad7992_device_attrs,
>> +};
>> +
>> +static struct attribute *ad7992_scan_el_attrs[] =3D {
>> + &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 =3D {
>> + .name =3D "scan_elements",
>> + .attrs =3D ad7992_scan_el_attrs,
>> +};
>> +
>> +static struct attribute *ad7997_8_device_attrs[] =3D {
>> + &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 =3D {
>> + .attrs =3D ad7997_8_device_attrs,
>> +};
>> +
>> +static struct attribute *ad7997_8_scan_el_attrs[] =3D {
>> + &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 =3D {
>> + .name =3D "scan_elements",
>> + .attrs =3D 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[] =3D {
>> + &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 =3D {
>> + .attrs =3D ad7993_4_7_8_event_attributes, };
>> +
>> +static struct attribute *ad7992_event_attributes[] =3D {
>> + &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 =3D {
>> + .attrs =3D ad7992_event_attributes,
>> +};
>> +
>> +static const struct ad799x_chip_info ad799x_chip_info_tbl[] =3D {
>> + [ad7991] =3D {
>> + .num_inputs =3D 4,
>> + .bits =3D 12,
>> + .int_vref_mv =3D 4096,
>> + .dev_attrs =3D &ad7991_5_9_3_4_dev_attr_group,
>> + .scan_attrs =3D &ad7991_5_9_3_4_scan_el_group,
>> + .ad799x_set_scan_mode =3D ad7991_5_9_set_scan_mode,
>> + },
>> + [ad7995] =3D {
>> + .num_inputs =3D 4,
>> + .bits =3D 10,
>> + .int_vref_mv =3D 1024,
>> + .dev_attrs =3D &ad7991_5_9_3_4_dev_attr_group,
>> + .scan_attrs =3D &ad7991_5_9_3_4_scan_el_group,
>> + .ad799x_set_scan_mode =3D ad7991_5_9_set_scan_mode,
>> + },
>> + [ad7999] =3D {
>> + .num_inputs =3D 4,
>> + .bits =3D 10,
>> + .int_vref_mv =3D 1024,
>> + .dev_attrs =3D &ad7991_5_9_3_4_dev_attr_group,
>> + .scan_attrs =3D &ad7991_5_9_3_4_scan_el_group,
>> + .ad799x_set_scan_mode =3D ad7991_5_9_set_scan_mode,
>> + },
>> + [ad7992] =3D {
>> + .num_inputs =3D 2,
>> + .bits =3D 12,
>> + .int_vref_mv =3D 4096,
>> + .monitor_mode =3D true,
>> + .default_config =3D AD7998_ALERT_EN,
>> + .dev_attrs =3D &ad7992_dev_attr_group,
>> + .scan_attrs =3D &ad7992_scan_el_group,
>> + .event_attrs =3D &ad7992_event_attrs_group,
>> + .ad799x_set_scan_mode =3D ad7992_3_4_set_scan_mode,
>> + },
>> + [ad7993] =3D {
>> + .num_inputs =3D 4,
>> + .bits =3D 10,
>> + .int_vref_mv =3D 1024,
>> + .monitor_mode =3D true,
>> + .default_config =3D AD7998_ALERT_EN,
>> + .dev_attrs =3D &ad7991_5_9_3_4_dev_attr_group,
>> + .scan_attrs =3D &ad7991_5_9_3_4_scan_el_group,
>> + .event_attrs =3D &ad7993_4_7_8_event_attrs_group,
>> + .ad799x_set_scan_mode =3D ad7992_3_4_set_scan_mode,
>> + },
>> + [ad7994] =3D {
>> + .num_inputs =3D 4,
>> + .bits =3D 12,
>> + .int_vref_mv =3D 4096,
>> + .monitor_mode =3D true,
>> + .default_config =3D AD7998_ALERT_EN,
>> + .dev_attrs =3D &ad7991_5_9_3_4_dev_attr_group,
>> + .scan_attrs =3D &ad7991_5_9_3_4_scan_el_group,
>> + .event_attrs =3D &ad7993_4_7_8_event_attrs_group,
>> + .ad799x_set_scan_mode =3D ad7992_3_4_set_scan_mode,
>> + },
>> + [ad7997] =3D {
>> + .num_inputs =3D 8,
>> + .bits =3D 10,
>> + .int_vref_mv =3D 1024,
>> + .monitor_mode =3D true,
>> + .default_config =3D AD7998_ALERT_EN,
>> + .dev_attrs =3D &ad7997_8_dev_attr_group,
>> + .scan_attrs =3D &ad7997_8_scan_el_group,
>> + .event_attrs =3D &ad7993_4_7_8_event_attrs_group,
>> + .ad799x_set_scan_mode =3D ad7997_8_set_scan_mode,
>> + },
>> + [ad7998] =3D {
>> + .num_inputs =3D 8,
>> + .bits =3D 12,
>> + .int_vref_mv =3D 4096,
>> + .monitor_mode =3D true,
>> + .default_config =3D AD7998_ALERT_EN,
>> + .dev_attrs =3D &ad7997_8_dev_attr_group,
>> + .scan_attrs =3D &ad7997_8_scan_el_group,
>> + .event_attrs =3D &ad7993_4_7_8_event_attrs_group,
>> + .ad799x_set_scan_mode =3D ad7997_8_set_scan_mode,
>> + },
>> +};
>> +
>> +static int __devinit ad799x_probe(struct i2c_client *client,
>> + const struct i2c_device_id *id) {
>> + int ret, regdone =3D 0;
>> + struct ad799x_platform_data *pdata =3D client->dev.platform_data;
>> + struct ad799x_state *st =3D kzalloc(sizeof(*st), GFP_KERNEL);
>> + if (st =3D=3D NULL) {
>> + ret =3D -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 =3D id->driver_data;
>> + st->chip_info =3D &ad799x_chip_info_tbl[st->id];
>> + st->config =3D st->chip_info->default_config;
>> +
>> + /* TODO: Add pdata options for filtering and bit delay */
> We also need to add userspace attributes to cover filtering for these
> devices. However, that is definitely a discussion for another day!
>> + + if (pdata) + st->int_vref_mv =3D pdata->vref_mv; + e=
lse
>> + st->int_vref_mv =3D st->chip_info->int_vref_mv; + + s=
t->reg =3D
>> regulator_get(&client->dev, "vcc"); + if (!IS_ERR(st->reg)) { + =
ret =3D
>> regulator_enable(st->reg); + if (ret) + got=
o error_put_reg; + }
>> + st->client =3D client; + + st->indio_dev =3D iio_allocate_de=
vice(); + if
>> (st->indio_dev =3D=3D NULL) { + ret =3D -ENOMEM; + =
goto error_disable_reg;
>> + } + + /* Estabilish that the iio_dev is a child of the i2c device=
*/
>> + st->indio_dev->dev.parent =3D &client->dev; + st->indio_dev->at=
trs =3D
>> st->chip_info->dev_attrs; + st->indio_dev->event_attrs =3D
>> st->chip_info->event_attrs; + + st->indio_dev->dev_data =3D (void *=
)(st);
>> + st->indio_dev->driver_module =3D THIS_MODULE; + st->indio_dev->mo=
des =3D
>> INDIO_DIRECT_MODE; + st->indio_dev->num_interrupt_lines =3D 1; + + r=
et =3D
>> ad799x_set_scan_mode(st, 0); + if (ret) + goto error_=
free_device; +
>> + ret =3D ad799x_register_ring_funcs_and_init(st->indio_dev); + i=
f (ret)
>> + goto error_free_device; + + ret =3D
>> iio_device_register(st->indio_dev); + if (ret) + got=
o
>> error_cleanup_ring; + regdone =3D 1; + + ret =3D
>> 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 =3D
>> iio_register_interrupt_line(client->irq, + st-=
>indio_dev, + 0,
>> + IRQF_TRIGGER_FALLING, + =
client->name); + if (ret) + goto
>> error_cleanup_ring; + + /* + * The event handle=
r 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) + iio_free_device(st-=
>indio_dev);
>> + else + iio_device_unregister(st->indio_dev); +error_disabl=
e_reg:
>> + if (!IS_ERR(st->reg)) + regulator_disable(st->reg); +error_=
put_reg:
>> + if (!IS_ERR(st->reg)) + regulator_put(st->reg); + kfr=
ee(st);
>> +error_ret: + return ret; +} + +static __devexit int
>> ad799x_remove(struct i2c_client *client) { + struct ad799x_state *st =3D
>> i2c_get_clientdata(client); + struct iio_dev *indio_dev =3D
>> 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); + + ret=
urn 0; +} + +static
>> const struct i2c_device_id ad799x_id[] =3D { + { "ad7991", ad7991 }, + {
>> "ad7995", ad7995 }, + { "ad7999", ad7999 }, + { "ad7992", ad7992 =
}, + {
>> "ad7993", ad7993 }, + { "ad7994", ad7994 }, + { "ad7997", ad7997 =
}, + {
>> "ad7998", ad7998 }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, ad799x_i=
d); +
>> +static struct i2c_driver ad799x_driver =3D { + .driver =3D { + =
.name =3D
>> "ad799x", + }, + .probe =3D ad799x_probe, + .remove =3D
>> __devexit_p(ad799x_remove), + .id_table =3D ad799x_id, +}; + +sta=
tic
>> __init int ad799x_init(void) { + return i2c_add_driver(&ad799x_drive=
r);
>> } + +static __exit void ad799x_exit(void) {
>> + i2c_del_driver(&ad799x_driver); +} + +MODULE_AUTHOR("Michael
>> Hennerich +<hennerich@blackfin.uclinux.org>");
>> +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 =3D 0, ret; + u16 *ring=
_data; + if
>> (!(st->indio_dev->ring->scan_mask & mask)) { + ret =3D -EB=
USY; + goto
>> error_ret; + } + numvals =3D st->indio_dev->ring->scan_count; +
>> + ring_data =3D kmalloc(numvals*2, GFP_KERNEL); + if (ring_data =3D=
=3D NULL)
>> { + ret =3D -ENOMEM; + goto error_ret; + }=
+ ret =3D
>> 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 >>=3D 1; + while (ma=
sk) {
>> + if (mask & st->indio_dev->ring->scan_mask) + =
count++; + mask >>=3D
>> 1; + } + + ret =3D 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 =3D indio_dev->dev_data; + size_t d_size; + u=
nsigned
>> long numvals; + + /* + * Need to figure out the current mode base=
d
>> upon the requested + * scan mask in iio_dev + */ + + if (st->id =
=3D=3D
>> ad7997 || st->id =3D=3D ad7998) + ad799x_set_scan_mode(st=
,
>> st->indio_dev->ring->scan_mask); + + numvals =3D
>> st->indio_dev->ring->scan_count; + + if
>> (indio_dev->ring->access.set_bytes_per_datum) { + d_size =3D =
numvals*2 +
>> sizeof(s64); + if (d_size % 8) + d_s=
ize +=3D 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 =3D
>> indio_dev->dev_data; + + schedule_work(&st->poll_work); + + ret=
urn; +}
>> +/** + * 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 =3D container_of(work_s, struct ad799x_stat=
e,
>> + poll_work); + struct iio_=
dev *indio_dev =3D st->indio_dev;
>> + struct iio_sw_ring_buffer *ring =3D iio_to_sw_ring(indio_dev- ring)=
;
>> + s64 time_ns; + __u8 *rxbuf; + int b_sent; + size_t d_size; + =
u8 cmd;
>> + + unsigned long numvals =3D st->indio_dev->ring->scan_count; + + /=
*
>> Ensure the timestamp is 8 byte aligned */ + d_size =3D numvals*2 +
>> sizeof(s64); + + if (d_size % sizeof(s64)) + d_size +=3D=
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 no=
t currently
>> implemented + * might as well have this test in here in the mean=
time
>> as it does + * no harm. + */ + if (numvals =3D=3D 0) + =
return; + + rxbuf
>> =3D kmalloc(d_size, GFP_KERNEL); + if (rxbuf =3D=3D NULL) + =
return; +
>> + switch (st->id) { + case ad7991: + case ad7995: + case ad7999=
: + cmd
>> =3D st->config | (st->indio_dev->ring->scan_mask <<
>> + AD799X_CHANNEL_SHIFT); + break; + =
case ad7992: + case ad7993:
>> + case ad7994: + cmd =3D (st->indio_dev->ring->scan_mask <<
>> + AD799X_CHANNEL_SHIFT) | AD7998_CONV_RES_REG; + =
break; + case
>> ad7997: + case ad7998: + cmd =3D AD7997_8_READ_SEQUENCE |
>> AD7998_CONV_RES_REG; + break; + default: + =
cmd =3D 0; + } + + b_sent =3D
>> i2c_smbus_read_i2c_block_data(st->client, + cmd, numval=
s*2, rxbuf);
>> + if (b_sent < 0) + goto done; + + time_ns =3D 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 =3D indio_dev->dev_data; + int ret =
=3D 0; +
>> + indio_dev->ring =3D iio_sw_rb_allocate(indio_dev); + if
>> (!indio_dev->ring) { + ret =3D -ENOMEM; + g=
oto error_ret; + } + /*
>> Effectively select the ring buffer implementation */
>> + iio_ring_sw_register_funcs(&st->indio_dev->ring->access);
>> + indio_dev->pollfunc =3D kzalloc(sizeof(*indio_dev->pollfunc),
>> GFP_KERNEL); + if (indio_dev->pollfunc =3D=3D NULL) { + =
ret =3D -ENOMEM;
>> + goto error_deallocate_sw_rb; + } + /* Configure the po=
lling function
>> called on trigger interrupts */ + indio_dev->pollfunc->poll_func_main=
=3D
>> &ad799x_poll_func_th; + indio_dev->pollfunc->private_data =3D indio=
_dev;
>> + + /* Ring buffer functions - here trigger setup related */ +
>> + indio_dev->ring->preenable =3D &ad799x_ring_preenable;
>> + indio_dev->ring->postenable =3D &iio_triggered_ring_postenable;
>> + indio_dev->ring->predisable =3D &iio_triggered_ring_predisable; +
>> + INIT_WORK(&st->poll_work, &ad799x_poll_bh_to_ring); +
>> + indio_dev->ring->scan_el_attrs =3D st->chip_info->scan_attrs; + + /=
*
>> Flag that polled ring buffering is possible */ + indio_dev->modes |=
=3D
>> INDIO_RING_TRIGGERED; + return 0; +error_deallocate_sw_rb:
>> + iio_sw_rb_free(indio_dev->ring); +error_ret: + return ret; +} + +v=
oid
>> 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); +}
Greetings,
Michael
Analog Devices GmbH Wilhelm-Wagenfeld-Str. 6 80807 Muenchen
Sitz der Gesellschaft Muenchen, Registergericht Muenchen HRB 4036 Geschaeft=
sfuehrer Thomas Wessel, William A. Martin, Margaret Seif
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] staging: iio: adc: Enable driver support for ad799x AD converters
2010-10-01 15:07 ` Hennerich, Michael
@ 2010-10-01 15:50 ` Jonathan Cameron
2010-10-04 8:26 ` Hennerich, Michael
0 siblings, 1 reply; 10+ messages in thread
From: Jonathan Cameron @ 2010-10-01 15:50 UTC (permalink / raw)
To: Hennerich, Michael; +Cc: linux-iio@vger.kernel.org, Drivers
On 10/01/10 16:07, Hennerich, Michael wrote:
> Jonathan Cameron wrote on 2010-10-01:
>> Hi Michael,
>>
>> I was pretty much happy with this last time round. Couple of comments
>> inline. The new line missing in the Makefile is probably the only one
>> that I'd advocate doing pre merge.
>>
>> The precision attrs have gone away to be replaced by the more
>> informative type attributes in the scan_elements directory. This can
>> trivially be done as an additional patch post merge.
>>
>> There are some subtle changes to the event naming (post discussion on
>> lkml) but I'll just do this driver alongside the others in the patch
>> set implementing those changes. This is the first driver providing
>> hyst so that attribute will also need documenting. Again that should
>> happen post merge.
>>
>> I think we can also take advantage of some of the helper functions
>> that are now in place for buffer registration (came out of Barry's
>> work), but that can definitely happen at a later date.
>>
>> So in summary I'm happy to see this merge right now. The sooner the
>> better as far as I'm concerned
>
> Hi Jonathan,
>
> We have a few more iio drivers in our repository. Over the next couple
> of weeks I'm trying to get them out.
Excellent.
>
>> because I would like it to go in before
>> the event clean up series currently sat in my tree. That way I can
>> update this one at the same time.
>
> Oops - this patch was already against your tree:
> http://git.kernel.org/?p=linux/kernel/git/jic23/iio_temp.git
> Need to check if it works on Greg's staging.
Ah. Shouldn't be too bad. That's what I get for putting temporary trees
up - that one only exists for testing the adis16260 and adis16350 driver
changes.
> ...It's time to get out of staging
Couple of big bits that I think will need doing before we are ready
to run that gauntlet. Now its mainly stuff around the buffer code.
>
>> Acked-by: Jonathan Cameron <jic23@cam.ac.uk>
>>
>> Please send on to Greg KH <greg@kroah.com> for him to merge.
>>
>> Thanks,
>>
>> Jonathan
>>
>>> Driver for ad7991, ad7995, ad7999, ad7992, ad7993, ad7994, ad7997
>>> and
>>> ad7998 multichannel ADC.
>>>
>>> Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
>>> ---
>>> 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"
>> I'll express my usual anti comment on driver names with wild cards,
>> but as there are hardly any numbers left in the range it is probably
>> fine here.
>>> + 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 Please add a new line
>>> after this. \ 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 Typo in comment. + */ + +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; + + 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,
>> The precision attribute has been replaced by the _type attributes in the
>> scan_elements directory as they give all the information in one consice
>> form. Lets do that change as an additional patch post merge though.
>>
>>> + &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 */
>> We also need to add userspace attributes to cover filtering for these
>> devices. However, that is definitely a discussion for another day!
>>> + + 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) + 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@blackfin.uclinux.org>");
>>> +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); +}
>
> Greetings,
> Michael
>
> Analog Devices GmbH Wilhelm-Wagenfeld-Str. 6 80807 Muenchen
> Sitz der Gesellschaft Muenchen, Registergericht Muenchen HRB 4036 Geschaeftsfuehrer Thomas Wessel, William A. Martin, Margaret Seif
>
>
^ permalink raw reply [flat|nested] 10+ messages in thread
* RE: [PATCH] staging: iio: adc: Enable driver support for ad799x AD converters
2010-10-01 15:50 ` Jonathan Cameron
@ 2010-10-04 8:26 ` Hennerich, Michael
2010-10-04 9:56 ` Jonathan Cameron
0 siblings, 1 reply; 10+ messages in thread
From: Hennerich, Michael @ 2010-10-04 8:26 UTC (permalink / raw)
To: Jonathan Cameron; +Cc: linux-iio@vger.kernel.org, Drivers
Jonathan Cameron wrote on 2010-10-01:
> On 10/01/10 16:07, Hennerich, Michael wrote:
>> Jonathan Cameron wrote on 2010-10-01:
>>> Hi Michael,
>>>
>>> I was pretty much happy with this last time round. Couple of comments
>>> inline. The new line missing in the Makefile is probably the only one
>>> that I'd advocate doing pre merge.
>>>
>>> The precision attrs have gone away to be replaced by the more
>>> informative type attributes in the scan_elements directory. This can
>>> trivially be done as an additional patch post merge.
>>>
>>> There are some subtle changes to the event naming (post discussion on
>>> lkml) but I'll just do this driver alongside the others in the patch
>>> set implementing those changes. This is the first driver providing
>>> hyst so that attribute will also need documenting. Again that should
>>> happen post merge.
>>>
>>> I think we can also take advantage of some of the helper functions
>>> that are now in place for buffer registration (came out of Barry's
>>> work), but that can definitely happen at a later date.
>>>
>>> So in summary I'm happy to see this merge right now. The sooner the
>>> better as far as I'm concerned
>>
>> Hi Jonathan,
>>
>> We have a few more iio drivers in our repository. Over the next couple
>> of weeks I'm trying to get them out. Excellent.
>>
>>> because I would like it to go in before
>>> the event clean up series currently sat in my tree. That way I can
>>> update this one at the same time.
>>
>> Oops - this patch was already against your tree:
>> http://git.kernel.org/?p=3Dlinux/kernel/git/jic23/iio_temp.git
>>
>> Need to check if it works on Greg's staging.
> Ah. Shouldn't be too bad. That's what I get for putting temporary trees
> up - that one only exists for testing the adis16260 and adis16350 driver
> changes.
Well - it looks bad.
It basically errors on everything I changed in order to make it work on you=
r temp tree.
I'll send Greg my original version...
drivers/staging/iio/adc/ad799x_ring.c: In function 'ad799x_single_channel_f=
rom_ring':
drivers/staging/iio/adc/ad799x_ring.c:35: error: 'struct iio_ring_buffer' h=
as no member named 'scan_mask'
drivers/staging/iio/adc/ad799x_ring.c:39: error: 'struct iio_ring_buffer' h=
as no member named 'scan_count'
drivers/staging/iio/adc/ad799x_ring.c:53: error: 'struct iio_ring_buffer' h=
as no member named 'scan_mask'
drivers/staging/iio/adc/ad799x_ring.c: In function 'ad799x_ring_preenable':
drivers/staging/iio/adc/ad799x_ring.c:85: error: 'struct iio_ring_buffer' h=
as no member named 'scan_mask'
drivers/staging/iio/adc/ad799x_ring.c:87: error: 'struct iio_ring_buffer' h=
as no member named 'scan_count'
drivers/staging/iio/adc/ad799x_ring.c:89: error: 'struct iio_ring_access_fu=
ncs' has no member named 'set_bytes_per_datum'
drivers/staging/iio/adc/ad799x_ring.c:93: error: 'struct iio_ring_access_fu=
ncs' has no member named 'set_bytes_per_datum'
drivers/staging/iio/adc/ad799x_ring.c: In function 'ad799x_poll_bh_to_ring'=
:
drivers/staging/iio/adc/ad799x_ring.c:136: error: 'struct iio_ring_buffer' =
has no member named 'scan_count'
drivers/staging/iio/adc/ad799x_ring.c:163: error: 'struct iio_ring_buffer' =
has no member named 'scan_mask'
drivers/staging/iio/adc/ad799x_ring.c:169: error: 'struct iio_ring_buffer' =
has no member named 'scan_mask'
drivers/staging/iio/adc/ad799x_ring.c: In function 'ad799x_register_ring_fu=
ncs_and_init':
drivers/staging/iio/adc/ad799x_ring.c:225: error: 'struct iio_ring_buffer' =
has no member named 'scan_el_attrs'
LD drivers/staging/iio/light/built-in.o
drivers/staging/iio/adc/ad799x_core.c: In function 'ad799x_scan_el_set_stat=
e':
drivers/staging/iio/adc/ad799x_core.c:108: error: 'struct iio_ring_buffer' =
has no member named 'scan_mask'
drivers/staging/iio/adc/ad799x_core.c:117:1: error: macro "IIO_SCAN_EL_C" r=
equires 5 arguments, but only 4 given
drivers/staging/iio/adc/ad799x_core.c: At top level:
drivers/staging/iio/adc/ad799x_core.c:117: warning: type defaults to 'int' =
in declaration of 'IIO_SCAN_EL_C'
drivers/staging/iio/adc/ad799x_core.c:118:1: error: macro "IIO_SCAN_EL_C" r=
equires 5 arguments, but only 4 given
drivers/staging/iio/adc/ad799x_core.c:118: warning: type defaults to 'int' =
in declaration of 'IIO_SCAN_EL_C'
drivers/staging/iio/adc/ad799x_core.c:119:1: error: macro "IIO_SCAN_EL_C" r=
equires 5 arguments, but only 4 given
drivers/staging/iio/adc/ad799x_core.c:119: warning: type defaults to 'int' =
in declaration of 'IIO_SCAN_EL_C'
drivers/staging/iio/adc/ad799x_core.c:120:1: error: macro "IIO_SCAN_EL_C" r=
equires 5 arguments, but only 4 given
drivers/staging/iio/adc/ad799x_core.c:120: warning: type defaults to 'int' =
in declaration of 'IIO_SCAN_EL_C'
drivers/staging/iio/adc/ad799x_core.c:121:1: error: macro "IIO_SCAN_EL_C" r=
equires 5 arguments, but only 4 given
drivers/staging/iio/adc/ad799x_core.c:121: warning: type defaults to 'int' =
in declaration of 'IIO_SCAN_EL_C'
drivers/staging/iio/adc/ad799x_core.c:122:1: error: macro "IIO_SCAN_EL_C" r=
equires 5 arguments, but only 4 given
drivers/staging/iio/adc/ad799x_core.c:122: warning: type defaults to 'int' =
in declaration of 'IIO_SCAN_EL_C'
drivers/staging/iio/adc/ad799x_core.c:123:1: error: macro "IIO_SCAN_EL_C" r=
equires 5 arguments, but only 4 given
drivers/staging/iio/adc/ad799x_core.c:123: warning: type defaults to 'int' =
in declaration of 'IIO_SCAN_EL_C'
drivers/staging/iio/adc/ad799x_core.c:124:1: error: macro "IIO_SCAN_EL_C" r=
equires 5 arguments, but only 4 given
drivers/staging/iio/adc/ad799x_core.c:124: warning: type defaults to 'int' =
in declaration of 'IIO_SCAN_EL_C'
drivers/staging/iio/adc/ad799x_core.c: In function 'ad799x_interrupt_bh':
drivers/staging/iio/adc/ad799x_core.c:391: warning: suggest parentheses aro=
und + or - inside shift
drivers/staging/iio/adc/ad799x_core.c:392: warning: right shift count >=3D =
width of type
drivers/staging/iio/adc/ad799x_core.c:392: warning: suggest parentheses aro=
und + or - inside shift
drivers/staging/iio/adc/ad799x_core.c: At top level:
drivers/staging/iio/adc/ad799x_core.c:469: error: 'iio_scan_el_in0' undecla=
red here (not in a function)
drivers/staging/iio/adc/ad799x_core.c:470: error: 'iio_const_attr_in0_index=
' undeclared here (not in a function)
drivers/staging/iio/adc/ad799x_core.c:471: error: 'iio_scan_el_in1' undecla=
red here (not in a function)
drivers/staging/iio/adc/ad799x_core.c:472: error: 'iio_const_attr_in1_index=
' undeclared here (not in a function)
drivers/staging/iio/adc/ad799x_core.c:473: error: 'iio_scan_el_in2' undecla=
red here (not in a function)
drivers/staging/iio/adc/ad799x_core.c:474: error: 'iio_const_attr_in2_index=
' undeclared here (not in a function)
drivers/staging/iio/adc/ad799x_core.c:475: error: 'iio_scan_el_in3' undecla=
red here (not in a function)
drivers/staging/iio/adc/ad799x_core.c:476: error: 'iio_const_attr_in3_index=
' undeclared here (not in a function)
drivers/staging/iio/adc/ad799x_core.c:499: error: request for member 'dev_a=
ttr' in something not a structure or union
drivers/staging/iio/adc/ad799x_core.c:499: error: request for member 'attr'=
in something not a structure or union
drivers/staging/iio/adc/ad799x_core.c:499: error: initializer element is no=
t constant
drivers/staging/iio/adc/ad799x_core.c:499: error: (near initialization for =
'ad7992_scan_el_attrs[0]')
drivers/staging/iio/adc/ad799x_core.c:500: error: request for member 'dev_a=
ttr' in something not a structure or union
drivers/staging/iio/adc/ad799x_core.c:500: error: request for member 'attr'=
in something not a structure or union
drivers/staging/iio/adc/ad799x_core.c:500: error: initializer element is no=
t constant
drivers/staging/iio/adc/ad799x_core.c:500: error: (near initialization for =
'ad7992_scan_el_attrs[1]')
drivers/staging/iio/adc/ad799x_core.c:501: error: request for member 'dev_a=
ttr' in something not a structure or union
drivers/staging/iio/adc/ad799x_core.c:501: error: request for member 'attr'=
in something not a structure or union
drivers/staging/iio/adc/ad799x_core.c:501: error: initializer element is no=
t constant
drivers/staging/iio/adc/ad799x_core.c:501: error: (near initialization for =
'ad7992_scan_el_attrs[2]')
drivers/staging/iio/adc/ad799x_core.c:502: error: request for member 'dev_a=
ttr' in something not a structure or union
drivers/staging/iio/adc/ad799x_core.c:502: error: request for member 'attr'=
in something not a structure or union
drivers/staging/iio/adc/ad799x_core.c:502: error: initializer element is no=
t constant
drivers/staging/iio/adc/ad799x_core.c:502: error: (near initialization for =
'ad7992_scan_el_attrs[3]')
drivers/staging/iio/adc/ad799x_core.c:531: error: request for member 'dev_a=
ttr' in something not a structure or union
drivers/staging/iio/adc/ad799x_core.c:531: error: request for member 'attr'=
in something not a structure or union
drivers/staging/iio/adc/ad799x_core.c:531: error: initializer element is no=
t constant
drivers/staging/iio/adc/ad799x_core.c:531: error: (near initialization for =
'ad7997_8_scan_el_attrs[0]')
drivers/staging/iio/adc/ad799x_core.c:532: error: request for member 'dev_a=
ttr' in something not a structure or union
drivers/staging/iio/adc/ad799x_core.c:532: error: request for member 'attr'=
in something not a structure or union
drivers/staging/iio/adc/ad799x_core.c:532: error: initializer element is no=
t constant
drivers/staging/iio/adc/ad799x_core.c:532: error: (near initialization for =
'ad7997_8_scan_el_attrs[1]')
drivers/staging/iio/adc/ad799x_core.c:533: error: request for member 'dev_a=
ttr' in something not a structure or union
drivers/staging/iio/adc/ad799x_core.c:533: error: request for member 'attr'=
in something not a structure or union
drivers/staging/iio/adc/ad799x_core.c:533: error: initializer element is no=
t constant
drivers/staging/iio/adc/ad799x_core.c:533: error: (near initialization for =
'ad7997_8_scan_el_attrs[2]')
drivers/staging/iio/adc/ad799x_core.c:534: error: request for member 'dev_a=
ttr' in something not a structure or union
drivers/staging/iio/adc/ad799x_core.c:534: error: request for member 'attr'=
in something not a structure or union
drivers/staging/iio/adc/ad799x_core.c:534: error: initializer element is no=
t constant
drivers/staging/iio/adc/ad799x_core.c:534: error: (near initialization for =
'ad7997_8_scan_el_attrs[3]')
drivers/staging/iio/adc/ad799x_core.c:535: error: request for member 'dev_a=
ttr' in something not a structure or union
drivers/staging/iio/adc/ad799x_core.c:535: error: request for member 'attr'=
in something not a structure or union
drivers/staging/iio/adc/ad799x_core.c:535: error: initializer element is no=
t constant
drivers/staging/iio/adc/ad799x_core.c:535: error: (near initialization for =
'ad7997_8_scan_el_attrs[4]')
drivers/staging/iio/adc/ad799x_core.c:536: error: request for member 'dev_a=
ttr' in something not a structure or union
drivers/staging/iio/adc/ad799x_core.c:536: error: request for member 'attr'=
in something not a structure or union
drivers/staging/iio/adc/ad799x_core.c:536: error: initializer element is no=
t constant
drivers/staging/iio/adc/ad799x_core.c:536: error: (near initialization for =
'ad7997_8_scan_el_attrs[5]')
drivers/staging/iio/adc/ad799x_core.c:537: error: request for member 'dev_a=
ttr' in something not a structure or union
drivers/staging/iio/adc/ad799x_core.c:537: error: request for member 'attr'=
in something not a structure or union
drivers/staging/iio/adc/ad799x_core.c:537: error: initializer element is no=
t constant
drivers/staging/iio/adc/ad799x_core.c:537: error: (near initialization for =
'ad7997_8_scan_el_attrs[6]')
drivers/staging/iio/adc/ad799x_core.c:538: error: request for member 'dev_a=
ttr' in something not a structure or union
drivers/staging/iio/adc/ad799x_core.c:538: error: request for member 'attr'=
in something not a structure or union
drivers/staging/iio/adc/ad799x_core.c:538: error: initializer element is no=
t constant
drivers/staging/iio/adc/ad799x_core.c:538: error: (near initialization for =
'ad7997_8_scan_el_attrs[7]')
drivers/staging/iio/adc/ad799x_core.c:539: error: 'iio_scan_el_in4' undecla=
red here (not in a function)
drivers/staging/iio/adc/ad799x_core.c:539: error: request for member 'dev_a=
ttr' in something not a structure or union
drivers/staging/iio/adc/ad799x_core.c:539: error: request for member 'attr'=
in something not a structure or union
drivers/staging/iio/adc/ad799x_core.c:539: error: initializer element is no=
t constant
drivers/staging/iio/adc/ad799x_core.c:539: error: (near initialization for =
'ad7997_8_scan_el_attrs[8]')
drivers/staging/iio/adc/ad799x_core.c:540: error: 'iio_const_attr_in4_index=
' undeclared here (not in a function)
drivers/staging/iio/adc/ad799x_core.c:540: error: request for member 'dev_a=
ttr' in something not a structure or union
drivers/staging/iio/adc/ad799x_core.c:540: error: request for member 'attr'=
in something not a structure or union
drivers/staging/iio/adc/ad799x_core.c:540: error: initializer element is no=
t constant
drivers/staging/iio/adc/ad799x_core.c:540: error: (near initialization for =
'ad7997_8_scan_el_attrs[9]')
drivers/staging/iio/adc/ad799x_core.c:541: error: 'iio_scan_el_in5' undecla=
red here (not in a function)
drivers/staging/iio/adc/ad799x_core.c:541: error: request for member 'dev_a=
ttr' in something not a structure or union
drivers/staging/iio/adc/ad799x_core.c:541: error: request for member 'attr'=
in something not a structure or union
drivers/staging/iio/adc/ad799x_core.c:541: error: initializer element is no=
t constant
drivers/staging/iio/adc/ad799x_core.c:541: error: (near initialization for =
'ad7997_8_scan_el_attrs[10]')
drivers/staging/iio/adc/ad799x_core.c:542: error: 'iio_const_attr_in5_index=
' undeclared here (not in a function)
drivers/staging/iio/adc/ad799x_core.c:542: error: request for member 'dev_a=
ttr' in something not a structure or union
drivers/staging/iio/adc/ad799x_core.c:542: error: request for member 'attr'=
in something not a structure or union
drivers/staging/iio/adc/ad799x_core.c:542: error: initializer element is no=
t constant
drivers/staging/iio/adc/ad799x_core.c:542: error: (near initialization for =
'ad7997_8_scan_el_attrs[11]')
drivers/staging/iio/adc/ad799x_core.c:543: error: 'iio_scan_el_in6' undecla=
red here (not in a function)
drivers/staging/iio/adc/ad799x_core.c:543: error: request for member 'dev_a=
ttr' in something not a structure or union
drivers/staging/iio/adc/ad799x_core.c:543: error: request for member 'attr'=
in something not a structure or union
drivers/staging/iio/adc/ad799x_core.c:543: error: initializer element is no=
t constant
drivers/staging/iio/adc/ad799x_core.c:543: error: (near initialization for =
'ad7997_8_scan_el_attrs[12]')
drivers/staging/iio/adc/ad799x_core.c:544: error: 'iio_const_attr_in6_index=
' undeclared here (not in a function)
drivers/staging/iio/adc/ad799x_core.c:544: error: request for member 'dev_a=
ttr' in something not a structure or union
drivers/staging/iio/adc/ad799x_core.c:544: error: request for member 'attr'=
in something not a structure or union
drivers/staging/iio/adc/ad799x_core.c:544: error: initializer element is no=
t constant
drivers/staging/iio/adc/ad799x_core.c:544: error: (near initialization for =
'ad7997_8_scan_el_attrs[13]')
drivers/staging/iio/adc/ad799x_core.c:545: error: 'iio_scan_el_in7' undecla=
red here (not in a function)
drivers/staging/iio/adc/ad799x_core.c:545: error: request for member 'dev_a=
ttr' in something not a structure or union
drivers/staging/iio/adc/ad799x_core.c:545: error: request for member 'attr'=
in something not a structure or union
drivers/staging/iio/adc/ad799x_core.c:545: error: initializer element is no=
t constant
drivers/staging/iio/adc/ad799x_core.c:545: error: (near initialization for =
'ad7997_8_scan_el_attrs[14]')
drivers/staging/iio/adc/ad799x_core.c:546: error: 'iio_const_attr_in7_index=
' undeclared here (not in a function)
drivers/staging/iio/adc/ad799x_core.c:546: error: request for member 'dev_a=
ttr' in something not a structure or union
drivers/staging/iio/adc/ad799x_core.c:546: error: request for member 'attr'=
in something not a structure or union
drivers/staging/iio/adc/ad799x_core.c:546: error: initializer element is no=
t constant
drivers/staging/iio/adc/ad799x_core.c:546: error: (near initialization for =
'ad7997_8_scan_el_attrs[15]')
>
>> ...It's time to get out of staging
> Couple of big bits that I think will need doing before we are ready
> to run that gauntlet. Now its mainly stuff around the buffer code.
>
>>
>>> Acked-by: Jonathan Cameron <jic23@cam.ac.uk>
>>>
>>> Please send on to Greg KH <greg@kroah.com> for him to merge.
>>>
>>> Thanks,
>>>
>>> Jonathan
>>>
>>>> Driver for ad7991, ad7995, ad7999, ad7992, ad7993, ad7994, ad7997
>>>> and
>>>> ad7998 multichannel ADC.
>>>>
>>>> Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
>>>> ---
>>>> 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"
>>> I'll express my usual anti comment on driver names with wild cards,
>>> but as there are hardly any numbers left in the range it is probably
>>> fine here.
>>>> + 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 :=3D
>>>> max1363_core.o max1363-y +=3D max1363_ring.o
>>>>
>>>> obj-$(CONFIG_MAX1363) +=3D max1363.o
>>>> + +ad799x-y :=3D ad799x_core.o +ad799x-$(CONFIG_AD799X_RING_BUFFER) +=
=3D
>>>> ad799x_ring.o +obj-$(CONFIG_AD799X) +=3D ad799x.o Please add a new lin=
e
>>>> after this. \ 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 Typo in
>>>> comment. + */ + +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 =3D st->client; + int ret =3D 0; + +
>>>> ret =3D i2c_smbus_read_word_data(client, reg); + if (ret < 0) =
{
>>>> + dev_err(&client->dev, "I2C read error\n"); +
>>>> return ret; + } + + *data =3D swab16((u16)ret); + + return 0; +=
}
>>>> + +static int ad799x_i2c_read8(struct ad799x_state *st, u8 reg, u8
>>>> +*data) { + struct i2c_client *client =3D st->client; + int ret
>>>> =3D 0; + + ret =3D i2c_smbus_read_word_data(client, reg); + if (re=
t <
>>>> 0) { + dev_err(&client->dev, "I2C read error\n"); + return
>>>> ret; + } + + *data =3D ret; + + return 0; +} + +static int
>>>> ad799x_i2c_write16(struct ad799x_state *st, u8 reg, u16 +data) { +
>>>> struct i2c_client *client =3D st->client; + int ret =3D 0; + +
>>>> ret =3D 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 =3D
>>>> st->client; + int ret =3D 0; + + ret =3D
>>>> 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 =3D 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 =3D dev_get_drvdata(dev); + struct ad799x_state
>>>> *st =3D 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 !=3D NULL) { + ret =3D
>>>> 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 =3D dev_get_drvdata(dev); + struct
>>>> ad799x_state *st =3D iio_dev_get_devdata(dev_info); + struct
>>>> iio_dev_attr *this_attr =3D to_iio_dev_attr(attr); + int ret =3D 0=
,
>>>> len =3D 0; + u32 data ; + u16 rxbuf[1]; + u8 cmd; + long mask; =
+
>>>> + mutex_lock(&dev_info- mlock); + mask =3D 1 << this_attr->address=
;
>>>> + /* If ring buffer capture is occuring, query the buffer */ +
>>>> if (iio_ring_enabled(dev_info)) { + data =3D
>>>> ad799x_single_channel_from_ring(st, mask); + if (data < 0) { +
>>>> ret =3D data; + goto
> error_ret; + } + } else { + switch (st-
>> id)
>>>> { + case ad7991: + case ad7995: + case
>>>> ad7999: + cmd =3D st->config | (mask <<
>>>> AD799X_CHANNEL_SHIFT); + break; + case ad7992: +
>>>> case ad7993: + case ad7994: + cmd =3D
>>>> mask << AD799X_CHANNEL_SHIFT; + break; +
>>>> case ad7997: + case ad7998: + cmd =3D
>>>> (this_attr->address << + AD799X_CHANNEL_SHIFT) |
>>>> AD7997_8_READ_SINGLE; + break; +
> default: + cmd =3D 0; + + } +
> ret
>>>> =3D ad799x_i2c_read16(st, cmd, rxbuf); + if (ret < 0) +
>>>> goto error_ret; + + data =3D rxbuf[0] & 0xFFF; + } =
+
>>>> + /* Pretty print the result */ + len =3D 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 =3D
>>>> dev_get_drvdata(dev); + struct ad799x_state *st =3D
>>>> iio_dev_get_devdata(dev_info); + + int ret, len =3D 0; + u8 val;
>>>> + ret =3D ad799x_i2c_read8(st, AD7998_CYCLE_TMR_REG, &val); + i=
f
>>>> (ret) + return ret; + + val &=3D AD7998_CYC_MASK; + + switch
>>>> (val) { + case AD7998_CYC_DIS: + len =3D sprintf(buf,
>>>> "0\n"); + break; + case AD7998_CYC_TCONF_32: +
>>>> len =3D sprintf(buf, "15625\n"); + break; + case
>>>> AD7998_CYC_TCONF_64: + len =3D sprintf(buf, "7812\n"); +
>>>> break; + case AD7998_CYC_TCONF_128: + len
>>>> =3D sprintf(buf, "3906\n"); + break; + case
>>>> AD7998_CYC_TCONF_256: + len =3D sprintf(buf, "1953\n"); +
>>>> break; + case AD7998_CYC_TCONF_512: + len
>>>> =3D sprintf(buf, "976\n"); + break; + case
>>>> AD7998_CYC_TCONF_1024: + len =3D sprintf(buf, "488\n"); +
>>>> break; + case AD7998_CYC_TCONF_2048: + len =3D
>>>> 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 =3D dev_get_drvdata(dev); + struct ad799x_state
>>>> *st =3D iio_dev_get_devdata(dev_info); + + long val; + int ret; =
+
>>>> u8 t; + + ret =3D strict_strtol(buf, 10, &val); + if (ret) +
>>>> return ret; + + mutex_lock(&dev_info->mlock); + ret =3D
>>>> ad799x_i2c_read8(st, AD7998_CYCLE_TMR_REG, &t); + if (ret) +
>>>> goto error_ret_mutex; + /* Wipe the bits clean */ + t &=3D
>>>> ~AD7998_CYC_MASK; + + switch (val) { + case 15625: +
>>>> t |=3D AD7998_CYC_TCONF_32; + break; + case 7812: +
>>>> t |=3D AD7998_CYC_TCONF_64; + break; + case 3906: + =
t
>>>> |=3D AD7998_CYC_TCONF_128; + break; + case 1953: +
>>>> t |=3D AD7998_CYC_TCONF_256; + break; + case 976: =
+
>>>> t |=3D AD7998_CYC_TCONF_512; + break; + case 488: =
+
>>>> t |=3D AD7998_CYC_TCONF_1024; + break; + case 244: =
+
>>>> t |=3D AD7998_CYC_TCONF_2048; + break; + case 0: +
>>>> t |=3D AD7998_CYC_DIS; + break; + default: +
>>>> ret =3D -EINVAL; + goto error_ret_mutex; + } + +
>>>> ret =3D 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 =3D dev_get_drvdata(dev); + struct
>>>> ad799x_state *st =3D iio_dev_get_devdata(dev_info); + struct
>>>> iio_event_attr *this_attr =3D to_iio_event_attr(attr); + + int ret=
;
>>>> + u16 val; + ret =3D 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 =3D dev_get_drvdata(dev);
>>>> + struct ad799x_state *st =3D iio_dev_get_devdata(dev_info); +
>>>> struct iio_event_attr *this_attr =3D to_iio_event_attr(attr); + +
>>>> long val; + int ret; + + ret =3D strict_strtol(buf, 10, &val); +
>>>> if (ret) + return ret; + +
>>>> mutex_lock(&dev_info->mlock); + ret =3D 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 =3D
>>>> 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 =
=3D
>>>> 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 =3D dev_info->dev_data=
;
>>>> + + st->last_timestamp =3D 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
>>>> =3D dev_get_drvdata(dev); + struct ad799x_state *st =3D
>>>> 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 =3D dev_get_drvdata(dev); + struct
>>>> ad799x_state *st =3D 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[] =3D { +
>>>> &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 =3D { + .attrs =3D
>>>> ad7991_5_9_3_4_device_attrs, }; + +static struct attribute
>>>> *ad7991_5_9_3_4_scan_el_attrs[] =3D { + &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,
>>> The precision attribute has been replaced by the _type attributes in
>>> the scan_elements directory as they give all the information in one
>>> consice form. Lets do that change as an additional patch post merge
>>> though.
>>>
>>>> + &iio_dev_attr_in_precision.dev_attr.attr, + NULL, +}; +
>>>> +static struct attribute_group ad7991_5_9_3_4_scan_el_group =3D { +
>>>> .name =3D "scan_elements", + .attrs =3D ad7991_5_9_3_4_scan_el_attr=
s,
>>>> }; + +static struct attribute *ad7992_device_attrs[] =3D { +
>>>> &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 =3D { + .attrs =3D
>>>> ad7992_device_attrs, +}; + +static struct attribute
>>>> *ad7992_scan_el_attrs[] =3D { + &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 =3D { + .name =3D
>>>> "scan_elements", + .attrs =3D ad7992_scan_el_attrs, +}; + +static
>>>> struct attribute *ad7997_8_device_attrs[] =3D { +
>>>> &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 =3D { + .attrs =3D
>>>> ad7997_8_device_attrs, +}; + +static struct attribute
>>>> *ad7997_8_scan_el_attrs[] =3D { + &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 =3D { + .name =3D
>>>> "scan_elements", + .attrs =3D 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[] =3D {
>>>> + &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 =3D { + .attrs =3D
>>>> ad7993_4_7_8_event_attributes, }; + +static struct attribute
>>>> *ad7992_event_attributes[] =3D { +
>>>> &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 =
=3D
>>>> { + .attrs =3D ad7992_event_attributes, +}; + +static const struct
>>>> ad799x_chip_info ad799x_chip_info_tbl[] =3D { + [ad7991] =3D { +
>>>> .num_inputs =3D 4, + .bits =3D 12, +
>>>> .int_vref_mv =3D 4096, + .dev_attrs =3D
>>>> &ad7991_5_9_3_4_dev_attr_group, + .scan_attrs =3D
>>>> &ad7991_5_9_3_4_scan_el_group, + .ad799x_set_scan_mode =3D
>>>> ad7991_5_9_set_scan_mode, + }, + [ad7995] =3D { +
>>>> .num_inputs =3D 4, + .bits =3D 10, + .int_vref_m=
v =3D
>>>> 1024, + .dev_attrs =3D &ad7991_5_9_3_4_dev_attr_group, +
>>>> .scan_attrs =3D &ad7991_5_9_3_4_scan_el_group, +
>>>> .ad799x_set_scan_mode =3D ad7991_5_9_set_scan_mode, + }, +
>>>> [ad7999] =3D { + .num_inputs =3D 4, + .bits =3D =
10, +
>>>> .int_vref_mv =3D 1024, + .dev_attrs =3D
>>>> &ad7991_5_9_3_4_dev_attr_group, + .scan_attrs =3D
>>>> &ad7991_5_9_3_4_scan_el_group, + .ad799x_set_scan_mode =3D
>>>> ad7991_5_9_set_scan_mode, + }, + [ad7992] =3D { +
>>>> .num_inputs =3D 2, + .bits =3D 12, + .int_vref_m=
v =3D
>>>> 4096, + .monitor_mode =3D true, + .default_confi=
g
>>>> =3D AD7998_ALERT_EN, + .dev_attrs =3D &ad7992_dev_attr_grou=
p,
>>>> + .scan_attrs =3D &ad7992_scan_el_group, +
>>>> .event_attrs =3D &ad7992_event_attrs_group, +
>>>> .ad799x_set_scan_mode =3D ad7992_3_4_set_scan_mode, + }, +
>>>> [ad7993] =3D { + .num_inputs =3D 4, + .bits =3D =
10, +
>>>> .int_vref_mv =3D 1024, + .monitor_mode =3D true,=
+
>>>> .default_config =3D AD7998_ALERT_EN, + .dev_attrs
>>>> =3D &ad7991_5_9_3_4_dev_attr_group, + .scan_attrs =3D
>>>> &ad7991_5_9_3_4_scan_el_group, + .event_attrs =3D
>>>> &ad7993_4_7_8_event_attrs_group, + .ad799x_set_scan_mode =
=3D
>>>> ad7992_3_4_set_scan_mode, + }, + [ad7994] =3D { +
>>>> .num_inputs =3D 4, + .bits =3D 12, + .int_vref_m=
v =3D
>>>> 4096, + .monitor_mode =3D true, + .default_confi=
g
>>>> =3D AD7998_ALERT_EN, + .dev_attrs =3D
>>>> &ad7991_5_9_3_4_dev_attr_group, + .scan_attrs =3D
>>>> &ad7991_5_9_3_4_scan_el_group, + .event_attrs =3D
>>>> &ad7993_4_7_8_event_attrs_group, + .ad799x_set_scan_mode =
=3D
>>>> ad7992_3_4_set_scan_mode, + }, + [ad7997] =3D { +
>>>> .num_inputs =3D 8, + .bits =3D 10, + .int_vref_m=
v =3D
>>>> 1024, + .monitor_mode =3D true, + .default_confi=
g
>>>> =3D AD7998_ALERT_EN, + .dev_attrs =3D
>>>> &ad7997_8_dev_attr_group, + .scan_attrs =3D
>>>> &ad7997_8_scan_el_group, + .event_attrs =3D
>>>> &ad7993_4_7_8_event_attrs_group, + .ad799x_set_scan_mode =
=3D
>>>> ad7997_8_set_scan_mode, + }, + [ad7998] =3D { +
>>>> .num_inputs =3D 8, + .bits =3D 12, + .int_vref_m=
v =3D
>>>> 4096, + .monitor_mode =3D true, + .default_confi=
g
>>>> =3D AD7998_ALERT_EN, + .dev_attrs =3D
>>>> &ad7997_8_dev_attr_group, + .scan_attrs =3D
>>>> &ad7997_8_scan_el_group, + .event_attrs =3D
>>>> &ad7993_4_7_8_event_attrs_group, + .ad799x_set_scan_mode =
=3D
>>>> ad7997_8_set_scan_mode, + }, +}; + +static int __devinit
>>>> ad799x_probe(struct i2c_client *client, +
>>>> const struct i2c_device_id *id) { + int ret, regdone =3D 0; +
>>>> struct ad799x_platform_data *pdata =3D client- dev.platform_data; +
>>>> struct ad799x_state *st =3D kzalloc(sizeof(*st), GFP_KERNEL); + if
>>>> (st =3D=3D NULL) { + ret =3D -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 =3D id->driver_data; +
>>>> st->chip_info =3D &ad799x_chip_info_tbl[st->id]; + st->config =3D
>>>> st->chip_info->default_config; + + /* TODO: Add pdata options for
>>>> filtering and bit delay */
>>> We also need to add userspace attributes to cover filtering for these
>>> devices. However, that is definitely a discussion for another day!
>>>> + + if (pdata) + st->int_vref_mv =3D pdata->vref_mv; + els=
e
>>>> + st->int_vref_mv =3D st->chip_info->int_vref_mv; + +
>>>> st->reg =3D regulator_get(&client->dev, "vcc"); + if
>>>> (!IS_ERR(st->reg)) { + ret =3D regulator_enable(st->reg)=
;
>>>> + if (ret) + goto error_put_reg; + } + st->client =3D
>>>> client; + + st->indio_dev =3D iio_allocate_device(); + i=
f
>>>> (st->indio_dev =3D=3D NULL) { + ret =3D -ENOMEM; + goto
>>>> error_disable_reg; + } + + /* Estabilish that the iio_dev is a
>>>> child of the i2c device */ + st->indio_dev->dev.parent =3D
>>>> &client->dev; + st->indio_dev- attrs =3D st->chip_info->dev_attrs;
>>>> + st->indio_dev->event_attrs =3D st->chip_info->event_attrs; + +
>>>> st->indio_dev->dev_data =3D (void *)(st); +
>>>> st->indio_dev->driver_module =3D THIS_MODULE; + st->indio_dev- modes
>>>> =3D INDIO_DIRECT_MODE; + st->indio_dev->num_interrupt_lines =3D 1; + +
>>>> ret =3D ad799x_set_scan_mode(st, 0); + if (ret) +
>>>> goto error_free_device; + + ret =3D
>>>> ad799x_register_ring_funcs_and_init(st->indio_dev); + if (ret) +
>>>> goto error_free_device; + + ret =3D
>>>> iio_device_register(st->indio_dev); + if (ret) + goto
>>>> error_cleanup_ring; + regdone =3D 1; + + ret =3D
>>>> 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 =3D
>>>> 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) +
>>>> 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 =3D i2c_get_clientdata(client); +
>>>> struct iio_dev *indio_dev =3D 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[] =3D =
{
>>>> + { "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 =3D { + .driver =3D { + .name =
=3D
>>>> "ad799x", + }, + .probe =3D ad799x_probe, + .remove =3D
>>>> __devexit_p(ad799x_remove), + .id_table =3D 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@blackfin.uclinux.org>"); +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 =3D 0, ret; + u16
>>>> *ring_data; + if (!(st->indio_dev->ring->scan_mask & mask)) { +
>>>> ret =3D -EBUSY; + goto error_ret; + } +
>>>> numvals =3D st->indio_dev->ring->scan_count; + + ring_data =3D
>>>> kmalloc(numvals*2, GFP_KERNEL); + if (ring_data =3D=3D NULL) { +
>>>> ret =3D -ENOMEM; + goto error_ret; + } + ret =3D
>>>> 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 >>=3D
>>>> 1; + while (mask) { + if (mask &
>>>> st->indio_dev->ring->scan_mask) + count++; + mask >>=3D 1=
;
>>>> + } + + ret =3D 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 =3D 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 =3D=3D ad7997 || st->id =3D=3D ad7998) +
>>>> ad799x_set_scan_mode(st, st->indio_dev->ring->scan_mask); + + numvals
>>>> =3D st->indio_dev->ring->scan_count; + + if
>>>> (indio_dev->ring->access.set_bytes_per_datum) { + d_size =
=3D
>>>> numvals*2 + sizeof(s64); + if (d_size % 8) + d_size +=3D
>>>> 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 =3D 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 =3D
>>>> container_of(work_s, struct ad799x_state, +
>>>> poll_work); + struct iio_dev *indio_dev =3D
>>>> st->indio_dev; + struct iio_sw_ring_buffer *ring =3D
>>>> iio_to_sw_ring(indio_dev- ring); + s64 time_ns; + __u8 *rxbuf; +
>>>> int b_sent; + size_t d_size; + u8 cmd; + + unsigned long
>>>> numvals =3D st->indio_dev->ring->scan_count; + + /* Ensure the
>>>> timestamp is 8 byte aligned */ + d_size =3D numvals*2 + sizeof(s64); =
+
>>>> + if (d_size % sizeof(s64)) + d_size +=3D 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 =3D=3D 0) + return; + + rxbuf =3D kmalloc(d_size,
>>>> GFP_KERNEL); + if (rxbuf =3D=3D NULL) + return; + + switch (st->id=
) {
>>>> + case ad7991: + case ad7995: + case ad7999: + cmd =3D
>>>> st->config | (st->indio_dev->ring->scan_mask << +
>>>> AD799X_CHANNEL_SHIFT); + break; + case ad7992:
>>>> + case ad7993: + case ad7994: + cmd =3D
>>>> (st->indio_dev->ring->scan_mask << +
>>>> AD799X_CHANNEL_SHIFT) | AD7998_CONV_RES_REG; + break; + case
>>>> ad7997: + case ad7998: + cmd =3D AD7997_8_READ_SEQUENCE |
>>>> AD7998_CONV_RES_REG; + break; + default: + cmd =
=3D
>>>> 0; + } + + b_sent =3D i2c_smbus_read_i2c_block_data(st->client,
>>>> + cmd, numvals*2, rxbuf); + if (b_sent < 0) +
>>>> goto done; + + time_ns =3D 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 =3D indio_dev->dev_data; + int ret
>>>> =3D 0; + + indio_dev->ring =3D iio_sw_rb_allocate(indio_dev); +
>>>> if (!indio_dev->ring) { + ret =3D -ENOMEM; + goto
>>>> error_ret; + } + /* Effectively select the ring buffer
>>>> implementation */ +
>>>> iio_ring_sw_register_funcs(&st->indio_dev->ring->access); +
>>>> indio_dev->pollfunc =3D kzalloc(sizeof(*indio_dev->pollfunc),
>>>> GFP_KERNEL); + if (indio_dev->pollfunc =3D=3D NULL) { + ret =3D
>>>> -ENOMEM; + goto error_deallocate_sw_rb; + } + /*
>>>> Configure the polling function called on trigger interrupts */ +
>>>> indio_dev->pollfunc- poll_func_main =3D &ad799x_poll_func_th; +
>>>> indio_dev->pollfunc->private_data =3D indio_dev; + + /* Ring buffer
>>>> functions - here trigger setup related */ + +
>>>> indio_dev->ring->preenable =3D &ad799x_ring_preenable; +
>>>> indio_dev->ring->postenable =3D &iio_triggered_ring_postenable; +
>>>> indio_dev->ring->predisable =3D &iio_triggered_ring_predisable; + +
>>>> INIT_WORK(&st->poll_work, &ad799x_poll_bh_to_ring); + +
>>>> indio_dev->ring->scan_el_attrs =3D st->chip_info->scan_attrs; + + /*
>>>> Flag that polled ring buffering is possible */ + indio_dev- modes
>>>> |=3D 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); +}
>>
>> Greetings,
>> Michael
>>
>> Analog Devices GmbH Wilhelm-Wagenfeld-Str. 6 80807 Muenchen
>> Sitz der Gesellschaft Muenchen, Registergericht Muenchen HRB 4036
>> Geschaeftsfuehrer Thomas Wessel, William A. Martin, Margaret Seif
>>
>>
Greetings,
Michael
Analog Devices GmbH Wilhelm-Wagenfeld-Str. 6 80807 Muenchen
Sitz der Gesellschaft Muenchen, Registergericht Muenchen HRB 4036
Geschaeftsfuehrer Thomas Wessel, William A. Martin, Margaret Seif
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] staging: iio: adc: Enable driver support for ad799x AD converters
2010-10-04 8:26 ` Hennerich, Michael
@ 2010-10-04 9:56 ` Jonathan Cameron
2010-10-04 12:13 ` Hennerich, Michael
2010-10-05 8:32 ` Hennerich, Michael
0 siblings, 2 replies; 10+ messages in thread
From: Jonathan Cameron @ 2010-10-04 9:56 UTC (permalink / raw)
To: Hennerich, Michael; +Cc: linux-iio@vger.kernel.org, Drivers
...
>>> Hi Jonathan,
>>>
>>> We have a few more iio drivers in our repository. Over the next couple
>>> of weeks I'm trying to get them out. Excellent.
>>>
>>>> because I would like it to go in before
>>>> the event clean up series currently sat in my tree. That way I can
>>>> update this one at the same time.
>>>
>>> Oops - this patch was already against your tree:
>>> http://git.kernel.org/?p=linux/kernel/git/jic23/iio_temp.git
>>>
>>> Need to check if it works on Greg's staging.
>> Ah. Shouldn't be too bad. That's what I get for putting temporary trees
>> up - that one only exists for testing the adis16260 and adis16350 driver
>> changes.
>
> Well - it looks bad.
> It basically errors on everything I changed in order to make it work on your temp tree.
> I'll send Greg my original version...
Are you sure this was against staging-next branch of the staging-next tree? (which is where
Greg will merge this) Far as I can see all the changes since that in my temp tree are to do
with the event code cleanups and I don't think that would generate most of these. The index an
type changes + the rearrangement of the buffer code has been merged for a while.
It applies and builds as is. git's am checking throws up
/home/jic23/src/kernel/staging-next-2.6/.git/rebase-apply/patch:610: trailing whitespace.
i & 0x1 ?
and sparse gives
drivers/staging/iio/adc/ad799x_core.c: In function 'ad799x_interrupt_bh':
drivers/staging/iio/adc/ad799x_core.c:391: warning: suggest parentheses around + or - inside shift
drivers/staging/iio/adc/ad799x_core.c:392: warning: right shift count >= width of type
drivers/staging/iio/adc/ad799x_core.c:392: warning: suggest parentheses around + or - inside shift
both of which are probably worth fixing.
>
> drivers/staging/iio/adc/ad799x_ring.c: In function 'ad799x_single_channel_from_ring':
> drivers/staging/iio/adc/ad799x_ring.c:35: error: 'struct iio_ring_buffer' has no member named 'scan_mask'
> drivers/staging/iio/adc/ad799x_ring.c:39: error: 'struct iio_ring_buffer' has no member named 'scan_count'
> drivers/staging/iio/adc/ad799x_ring.c:53: error: 'struct iio_ring_buffer' has no member named 'scan_mask'
> drivers/staging/iio/adc/ad799x_ring.c: In function 'ad799x_ring_preenable':
> drivers/staging/iio/adc/ad799x_ring.c:85: error: 'struct iio_ring_buffer' has no member named 'scan_mask'
> drivers/staging/iio/adc/ad799x_ring.c:87: error: 'struct iio_ring_buffer' has no member named 'scan_count'
> drivers/staging/iio/adc/ad799x_ring.c:89: error: 'struct iio_ring_access_funcs' has no member named 'set_bytes_per_datum'
> drivers/staging/iio/adc/ad799x_ring.c:93: error: 'struct iio_ring_access_funcs' has no member named 'set_bytes_per_datum'
> drivers/staging/iio/adc/ad799x_ring.c: In function 'ad799x_poll_bh_to_ring':
> drivers/staging/iio/adc/ad799x_ring.c:136: error: 'struct iio_ring_buffer' has no member named 'scan_count'
> drivers/staging/iio/adc/ad799x_ring.c:163: error: 'struct iio_ring_buffer' has no member named 'scan_mask'
> drivers/staging/iio/adc/ad799x_ring.c:169: error: 'struct iio_ring_buffer' has no member named 'scan_mask'
> drivers/staging/iio/adc/ad799x_ring.c: In function 'ad799x_register_ring_funcs_and_init':
> drivers/staging/iio/adc/ad799x_ring.c:225: error: 'struct iio_ring_buffer' has no member named 'scan_el_attrs'
> LD drivers/staging/iio/light/built-in.o
> drivers/staging/iio/adc/ad799x_core.c: In function 'ad799x_scan_el_set_state':
> drivers/staging/iio/adc/ad799x_core.c:108: error: 'struct iio_ring_buffer' has no member named 'scan_mask'
> drivers/staging/iio/adc/ad799x_core.c:117:1: error: macro "IIO_SCAN_EL_C" requires 5 arguments, but only 4 given
> drivers/staging/iio/adc/ad799x_core.c: At top level:
> drivers/staging/iio/adc/ad799x_core.c:117: warning: type defaults to 'int' in declaration of 'IIO_SCAN_EL_C'
> drivers/staging/iio/adc/ad799x_core.c:118:1: error: macro "IIO_SCAN_EL_C" requires 5 arguments, but only 4 given
> drivers/staging/iio/adc/ad799x_core.c:118: warning: type defaults to 'int' in declaration of 'IIO_SCAN_EL_C'
> drivers/staging/iio/adc/ad799x_core.c:119:1: error: macro "IIO_SCAN_EL_C" requires 5 arguments, but only 4 given
> drivers/staging/iio/adc/ad799x_core.c:119: warning: type defaults to 'int' in declaration of 'IIO_SCAN_EL_C'
> drivers/staging/iio/adc/ad799x_core.c:120:1: error: macro "IIO_SCAN_EL_C" requires 5 arguments, but only 4 given
> drivers/staging/iio/adc/ad799x_core.c:120: warning: type defaults to 'int' in declaration of 'IIO_SCAN_EL_C'
> drivers/staging/iio/adc/ad799x_core.c:121:1: error: macro "IIO_SCAN_EL_C" requires 5 arguments, but only 4 given
> drivers/staging/iio/adc/ad799x_core.c:121: warning: type defaults to 'int' in declaration of 'IIO_SCAN_EL_C'
> drivers/staging/iio/adc/ad799x_core.c:122:1: error: macro "IIO_SCAN_EL_C" requires 5 arguments, but only 4 given
> drivers/staging/iio/adc/ad799x_core.c:122: warning: type defaults to 'int' in declaration of 'IIO_SCAN_EL_C'
> drivers/staging/iio/adc/ad799x_core.c:123:1: error: macro "IIO_SCAN_EL_C" requires 5 arguments, but only 4 given
> drivers/staging/iio/adc/ad799x_core.c:123: warning: type defaults to 'int' in declaration of 'IIO_SCAN_EL_C'
> drivers/staging/iio/adc/ad799x_core.c:124:1: error: macro "IIO_SCAN_EL_C" requires 5 arguments, but only 4 given
> drivers/staging/iio/adc/ad799x_core.c:124: warning: type defaults to 'int' in declaration of 'IIO_SCAN_EL_C'
> drivers/staging/iio/adc/ad799x_core.c: In function 'ad799x_interrupt_bh':
> drivers/staging/iio/adc/ad799x_core.c:391: warning: suggest parentheses around + or - inside shift
> drivers/staging/iio/adc/ad799x_core.c:392: warning: right shift count >= width of type
> drivers/staging/iio/adc/ad799x_core.c:392: warning: suggest parentheses around + or - inside shift
> drivers/staging/iio/adc/ad799x_core.c: At top level:
> drivers/staging/iio/adc/ad799x_core.c:469: error: 'iio_scan_el_in0' undeclared here (not in a function)
> drivers/staging/iio/adc/ad799x_core.c:470: error: 'iio_const_attr_in0_index' undeclared here (not in a function)
> drivers/staging/iio/adc/ad799x_core.c:471: error: 'iio_scan_el_in1' undeclared here (not in a function)
> drivers/staging/iio/adc/ad799x_core.c:472: error: 'iio_const_attr_in1_index' undeclared here (not in a function)
> drivers/staging/iio/adc/ad799x_core.c:473: error: 'iio_scan_el_in2' undeclared here (not in a function)
> drivers/staging/iio/adc/ad799x_core.c:474: error: 'iio_const_attr_in2_index' undeclared here (not in a function)
> drivers/staging/iio/adc/ad799x_core.c:475: error: 'iio_scan_el_in3' undeclared here (not in a function)
> drivers/staging/iio/adc/ad799x_core.c:476: error: 'iio_const_attr_in3_index' undeclared here (not in a function)
> drivers/staging/iio/adc/ad799x_core.c:499: error: request for member 'dev_attr' in something not a structure or union
> drivers/staging/iio/adc/ad799x_core.c:499: error: request for member 'attr' in something not a structure or union
> drivers/staging/iio/adc/ad799x_core.c:499: error: initializer element is not constant
> drivers/staging/iio/adc/ad799x_core.c:499: error: (near initialization for 'ad7992_scan_el_attrs[0]')
> drivers/staging/iio/adc/ad799x_core.c:500: error: request for member 'dev_attr' in something not a structure or union
> drivers/staging/iio/adc/ad799x_core.c:500: error: request for member 'attr' in something not a structure or union
> drivers/staging/iio/adc/ad799x_core.c:500: error: initializer element is not constant
> drivers/staging/iio/adc/ad799x_core.c:500: error: (near initialization for 'ad7992_scan_el_attrs[1]')
> drivers/staging/iio/adc/ad799x_core.c:501: error: request for member 'dev_attr' in something not a structure or union
> drivers/staging/iio/adc/ad799x_core.c:501: error: request for member 'attr' in something not a structure or union
> drivers/staging/iio/adc/ad799x_core.c:501: error: initializer element is not constant
> drivers/staging/iio/adc/ad799x_core.c:501: error: (near initialization for 'ad7992_scan_el_attrs[2]')
> drivers/staging/iio/adc/ad799x_core.c:502: error: request for member 'dev_attr' in something not a structure or union
> drivers/staging/iio/adc/ad799x_core.c:502: error: request for member 'attr' in something not a structure or union
> drivers/staging/iio/adc/ad799x_core.c:502: error: initializer element is not constant
> drivers/staging/iio/adc/ad799x_core.c:502: error: (near initialization for 'ad7992_scan_el_attrs[3]')
> drivers/staging/iio/adc/ad799x_core.c:531: error: request for member 'dev_attr' in something not a structure or union
> drivers/staging/iio/adc/ad799x_core.c:531: error: request for member 'attr' in something not a structure or union
> drivers/staging/iio/adc/ad799x_core.c:531: error: initializer element is not constant
> drivers/staging/iio/adc/ad799x_core.c:531: error: (near initialization for 'ad7997_8_scan_el_attrs[0]')
> drivers/staging/iio/adc/ad799x_core.c:532: error: request for member 'dev_attr' in something not a structure or union
> drivers/staging/iio/adc/ad799x_core.c:532: error: request for member 'attr' in something not a structure or union
> drivers/staging/iio/adc/ad799x_core.c:532: error: initializer element is not constant
> drivers/staging/iio/adc/ad799x_core.c:532: error: (near initialization for 'ad7997_8_scan_el_attrs[1]')
> drivers/staging/iio/adc/ad799x_core.c:533: error: request for member 'dev_attr' in something not a structure or union
> drivers/staging/iio/adc/ad799x_core.c:533: error: request for member 'attr' in something not a structure or union
> drivers/staging/iio/adc/ad799x_core.c:533: error: initializer element is not constant
> drivers/staging/iio/adc/ad799x_core.c:533: error: (near initialization for 'ad7997_8_scan_el_attrs[2]')
> drivers/staging/iio/adc/ad799x_core.c:534: error: request for member 'dev_attr' in something not a structure or union
> drivers/staging/iio/adc/ad799x_core.c:534: error: request for member 'attr' in something not a structure or union
> drivers/staging/iio/adc/ad799x_core.c:534: error: initializer element is not constant
> drivers/staging/iio/adc/ad799x_core.c:534: error: (near initialization for 'ad7997_8_scan_el_attrs[3]')
> drivers/staging/iio/adc/ad799x_core.c:535: error: request for member 'dev_attr' in something not a structure or union
> drivers/staging/iio/adc/ad799x_core.c:535: error: request for member 'attr' in something not a structure or union
> drivers/staging/iio/adc/ad799x_core.c:535: error: initializer element is not constant
> drivers/staging/iio/adc/ad799x_core.c:535: error: (near initialization for 'ad7997_8_scan_el_attrs[4]')
> drivers/staging/iio/adc/ad799x_core.c:536: error: request for member 'dev_attr' in something not a structure or union
> drivers/staging/iio/adc/ad799x_core.c:536: error: request for member 'attr' in something not a structure or union
> drivers/staging/iio/adc/ad799x_core.c:536: error: initializer element is not constant
> drivers/staging/iio/adc/ad799x_core.c:536: error: (near initialization for 'ad7997_8_scan_el_attrs[5]')
> drivers/staging/iio/adc/ad799x_core.c:537: error: request for member 'dev_attr' in something not a structure or union
> drivers/staging/iio/adc/ad799x_core.c:537: error: request for member 'attr' in something not a structure or union
> drivers/staging/iio/adc/ad799x_core.c:537: error: initializer element is not constant
> drivers/staging/iio/adc/ad799x_core.c:537: error: (near initialization for 'ad7997_8_scan_el_attrs[6]')
> drivers/staging/iio/adc/ad799x_core.c:538: error: request for member 'dev_attr' in something not a structure or union
> drivers/staging/iio/adc/ad799x_core.c:538: error: request for member 'attr' in something not a structure or union
> drivers/staging/iio/adc/ad799x_core.c:538: error: initializer element is not constant
> drivers/staging/iio/adc/ad799x_core.c:538: error: (near initialization for 'ad7997_8_scan_el_attrs[7]')
> drivers/staging/iio/adc/ad799x_core.c:539: error: 'iio_scan_el_in4' undeclared here (not in a function)
> drivers/staging/iio/adc/ad799x_core.c:539: error: request for member 'dev_attr' in something not a structure or union
> drivers/staging/iio/adc/ad799x_core.c:539: error: request for member 'attr' in something not a structure or union
> drivers/staging/iio/adc/ad799x_core.c:539: error: initializer element is not constant
> drivers/staging/iio/adc/ad799x_core.c:539: error: (near initialization for 'ad7997_8_scan_el_attrs[8]')
> drivers/staging/iio/adc/ad799x_core.c:540: error: 'iio_const_attr_in4_index' undeclared here (not in a function)
> drivers/staging/iio/adc/ad799x_core.c:540: error: request for member 'dev_attr' in something not a structure or union
> drivers/staging/iio/adc/ad799x_core.c:540: error: request for member 'attr' in something not a structure or union
> drivers/staging/iio/adc/ad799x_core.c:540: error: initializer element is not constant
> drivers/staging/iio/adc/ad799x_core.c:540: error: (near initialization for 'ad7997_8_scan_el_attrs[9]')
> drivers/staging/iio/adc/ad799x_core.c:541: error: 'iio_scan_el_in5' undeclared here (not in a function)
> drivers/staging/iio/adc/ad799x_core.c:541: error: request for member 'dev_attr' in something not a structure or union
> drivers/staging/iio/adc/ad799x_core.c:541: error: request for member 'attr' in something not a structure or union
> drivers/staging/iio/adc/ad799x_core.c:541: error: initializer element is not constant
> drivers/staging/iio/adc/ad799x_core.c:541: error: (near initialization for 'ad7997_8_scan_el_attrs[10]')
> drivers/staging/iio/adc/ad799x_core.c:542: error: 'iio_const_attr_in5_index' undeclared here (not in a function)
> drivers/staging/iio/adc/ad799x_core.c:542: error: request for member 'dev_attr' in something not a structure or union
> drivers/staging/iio/adc/ad799x_core.c:542: error: request for member 'attr' in something not a structure or union
> drivers/staging/iio/adc/ad799x_core.c:542: error: initializer element is not constant
> drivers/staging/iio/adc/ad799x_core.c:542: error: (near initialization for 'ad7997_8_scan_el_attrs[11]')
> drivers/staging/iio/adc/ad799x_core.c:543: error: 'iio_scan_el_in6' undeclared here (not in a function)
> drivers/staging/iio/adc/ad799x_core.c:543: error: request for member 'dev_attr' in something not a structure or union
> drivers/staging/iio/adc/ad799x_core.c:543: error: request for member 'attr' in something not a structure or union
> drivers/staging/iio/adc/ad799x_core.c:543: error: initializer element is not constant
> drivers/staging/iio/adc/ad799x_core.c:543: error: (near initialization for 'ad7997_8_scan_el_attrs[12]')
> drivers/staging/iio/adc/ad799x_core.c:544: error: 'iio_const_attr_in6_index' undeclared here (not in a function)
> drivers/staging/iio/adc/ad799x_core.c:544: error: request for member 'dev_attr' in something not a structure or union
> drivers/staging/iio/adc/ad799x_core.c:544: error: request for member 'attr' in something not a structure or union
> drivers/staging/iio/adc/ad799x_core.c:544: error: initializer element is not constant
> drivers/staging/iio/adc/ad799x_core.c:544: error: (near initialization for 'ad7997_8_scan_el_attrs[13]')
> drivers/staging/iio/adc/ad799x_core.c:545: error: 'iio_scan_el_in7' undeclared here (not in a function)
> drivers/staging/iio/adc/ad799x_core.c:545: error: request for member 'dev_attr' in something not a structure or union
> drivers/staging/iio/adc/ad799x_core.c:545: error: request for member 'attr' in something not a structure or union
> drivers/staging/iio/adc/ad799x_core.c:545: error: initializer element is not constant
> drivers/staging/iio/adc/ad799x_core.c:545: error: (near initialization for 'ad7997_8_scan_el_attrs[14]')
> drivers/staging/iio/adc/ad799x_core.c:546: error: 'iio_const_attr_in7_index' undeclared here (not in a function)
> drivers/staging/iio/adc/ad799x_core.c:546: error: request for member 'dev_attr' in something not a structure or union
> drivers/staging/iio/adc/ad799x_core.c:546: error: request for member 'attr' in something not a structure or union
> drivers/staging/iio/adc/ad799x_core.c:546: error: initializer element is not constant
> drivers/staging/iio/adc/ad799x_core.c:546: error: (near initialization for 'ad7997_8_scan_el_attrs[15]')
>
>
^ permalink raw reply [flat|nested] 10+ messages in thread
* RE: [PATCH] staging: iio: adc: Enable driver support for ad799x AD converters
2010-10-04 9:56 ` Jonathan Cameron
@ 2010-10-04 12:13 ` Hennerich, Michael
2010-10-05 8:32 ` Hennerich, Michael
1 sibling, 0 replies; 10+ messages in thread
From: Hennerich, Michael @ 2010-10-04 12:13 UTC (permalink / raw)
To: Jonathan Cameron; +Cc: linux-iio@vger.kernel.org, Drivers
Jonathan Cameron wrote on 2010-10-04:
> ...
>>>> Hi Jonathan,
>>>>
>>>> We have a few more iio drivers in our repository. Over the next
>>>> couple of weeks I'm trying to get them out. Excellent.
>>>>
>>>>> because I would like it to go in before the event clean up series
>>>>> currently sat in my tree. That way I can update this one at the
>>>>> same time.
>>>>
>>>> Oops - this patch was already against your tree:
>>>> http://git.kernel.org/?p=3Dlinux/kernel/git/jic23/iio_temp.git
>>>>
>>>> Need to check if it works on Greg's staging.
>>> Ah. Shouldn't be too bad. That's what I get for putting temporary
>>> trees up - that one only exists for testing the adis16260 and
>>> adis16350 driver changes.
>>
>> Well - it looks bad. It basically errors on everything I changed in
>> order to make it work on your temp tree. I'll send Greg my original
>> version...
> Are you sure this was against staging-next branch of the staging-next
> tree? (which is where Greg will merge this) Far as I can see all the
> changes since that in my temp tree are to do with the event code
> cleanups and I don't think that would generate most of these. The
> index an type changes + the rearrangement of the buffer code has been
> merged for a while.
>
>
> It applies and builds as is. git's am checking throws up
> /home/jic23/src/kernel/staging-next-2.6/.git/rebase-apply/patch:610:
> trailing whitespace.
> i & 0x1 ?
> and sparse gives drivers/staging/iio/adc/ad799x_core.c: In function
> 'ad799x_interrupt_bh': drivers/staging/iio/adc/ad799x_core.c:391:
> warning: suggest parentheses around + or - inside shift
> drivers/staging/iio/adc/ad799x_core.c:392: warning: right shift count
>> =3D width of type
> drivers/staging/iio/adc/ad799x_core.c:392: warning: suggest
> parentheses around + or - inside shift
>
> both of which are probably worth fixing.
Do you think adding parentheses around (i) is going to fix the issue?
Or does the MACRO needs some fixing?
- i & 0x1 ?
- IIO_EVENT_CODE_IN_HIGH_THRESH(i >> 1) :
- IIO_EVENT_CODE_IN_LOW_THRESH(i >> 1),
+ i & 0x1 ?
+ IIO_EVENT_CODE_IN_HIGH_THRESH((i) >> 1) :
+ IIO_EVENT_CODE_IN_LOW_THRESH((i) >> 1),
I tried using sparse - however in my environment it doesn't pick up proper =
kernel includes.
Do you know how to use sparse with cross compile? Or do you use the include=
s installed on your host?
Greetings,
Michael
Analog Devices GmbH Wilhelm-Wagenfeld-Str. 6 80807 Muenchen
Sitz der Gesellschaft Muenchen, Registergericht Muenchen HRB 4036 Geschaeft=
sfuehrer Thomas Wessel, William A. Martin, Margaret Seif
^ permalink raw reply [flat|nested] 10+ messages in thread
* RE: [PATCH] staging: iio: adc: Enable driver support for ad799x AD converters
2010-10-04 9:56 ` Jonathan Cameron
2010-10-04 12:13 ` Hennerich, Michael
@ 2010-10-05 8:32 ` Hennerich, Michael
2010-10-08 8:57 ` Jonathan Cameron
1 sibling, 1 reply; 10+ messages in thread
From: Hennerich, Michael @ 2010-10-05 8:32 UTC (permalink / raw)
To: Jonathan Cameron; +Cc: linux-iio@vger.kernel.org, Drivers
Jonathan Cameron wrote on 2010-10-04:
> ...
>>>> Hi Jonathan,
>>>>
>>>> We have a few more iio drivers in our repository. Over the next
>>>> couple of weeks I'm trying to get them out. Excellent.
>>>>
>>>>> because I would like it to go in before the event clean up series
>>>>> currently sat in my tree. That way I can update this one at the
>>>>> same time.
>>>>
>>>> Oops - this patch was already against your tree:
>>>> http://git.kernel.org/?p=3Dlinux/kernel/git/jic23/iio_temp.git
>>>>
>>>> Need to check if it works on Greg's staging.
>>> Ah. Shouldn't be too bad. That's what I get for putting temporary
>>> trees up - that one only exists for testing the adis16260 and
>>> adis16350 driver changes.
>>
>> Well - it looks bad. It basically errors on everything I changed in
>> order to make it work on your temp tree. I'll send Greg my original
>> version...
> Are you sure this was against staging-next branch of the staging-next
> tree? (which is where Greg will merge this) Far as I can see all the
> changes since that in my temp tree are to do with the event code
> cleanups and I don't think that would generate most of these. The
> index an type changes + the rearrangement of the buffer code has been
> merged for a while.
>
>
> It applies and builds as is. git's am checking throws up
> /home/jic23/src/kernel/staging-next-2.6/.git/rebase-apply/patch:610:
> trailing whitespace.
> i & 0x1 ?
> and sparse gives drivers/staging/iio/adc/ad799x_core.c: In function
> 'ad799x_interrupt_bh': drivers/staging/iio/adc/ad799x_core.c:391:
> warning: suggest parentheses around + or - inside shift
> drivers/staging/iio/adc/ad799x_core.c:392: warning: right shift count
>> =3D width of type
> drivers/staging/iio/adc/ad799x_core.c:392: warning: suggest
> parentheses around + or - inside shift
>
> both of which are probably worth fixing.
Hmm - I don't see this warning.
What version of sparse are you using - and do you pass any extra arguments =
to sparse?
CHECK drivers/staging/iio/adc/ad799x_core.c
CC drivers/staging/iio/adc/ad799x_core.o
LD drivers/staging/iio/adc/ad799x.o
Greetings,
Michael
Analog Devices GmbH Wilhelm-Wagenfeld-Str. 6 80807 Muenchen
Sitz der Gesellschaft Muenchen, Registergericht Muenchen HRB 4036 Geschaeft=
sfuehrer Thomas Wessel, William A. Martin, Margaret Seif
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] staging: iio: adc: Enable driver support for ad799x AD converters
2010-10-05 8:32 ` Hennerich, Michael
@ 2010-10-08 8:57 ` Jonathan Cameron
0 siblings, 0 replies; 10+ messages in thread
From: Jonathan Cameron @ 2010-10-08 8:57 UTC (permalink / raw)
To: Hennerich, Michael; +Cc: linux-iio@vger.kernel.org, Drivers
On 10/05/10 09:32, Hennerich, Michael wrote:
> Jonathan Cameron wrote on 2010-10-04:
>> ...
>>>>> Hi Jonathan,
>>>>>
>>>>> We have a few more iio drivers in our repository. Over the next
>>>>> couple of weeks I'm trying to get them out. Excellent.
>>>>>
>>>>>> because I would like it to go in before the event clean up series
>>>>>> currently sat in my tree. That way I can update this one at the
>>>>>> same time.
>>>>>
>>>>> Oops - this patch was already against your tree:
>>>>> http://git.kernel.org/?p=linux/kernel/git/jic23/iio_temp.git
>>>>>
>>>>> Need to check if it works on Greg's staging.
>>>> Ah. Shouldn't be too bad. That's what I get for putting temporary
>>>> trees up - that one only exists for testing the adis16260 and
>>>> adis16350 driver changes.
>>>
>>> Well - it looks bad. It basically errors on everything I changed in
>>> order to make it work on your temp tree. I'll send Greg my original
>>> version...
>> Are you sure this was against staging-next branch of the staging-next
>> tree? (which is where Greg will merge this) Far as I can see all the
>> changes since that in my temp tree are to do with the event code
>> cleanups and I don't think that would generate most of these. The
>> index an type changes + the rearrangement of the buffer code has been
>> merged for a while.
>>
>>
>> It applies and builds as is. git's am checking throws up
>> /home/jic23/src/kernel/staging-next-2.6/.git/rebase-apply/patch:610:
>> trailing whitespace.
>> i & 0x1 ?
>> and sparse gives drivers/staging/iio/adc/ad799x_core.c: In function
>> 'ad799x_interrupt_bh': drivers/staging/iio/adc/ad799x_core.c:391:
>> warning: suggest parentheses around + or - inside shift
>> drivers/staging/iio/adc/ad799x_core.c:392: warning: right shift count
>>> = width of type
>> drivers/staging/iio/adc/ad799x_core.c:392: warning: suggest
>> parentheses around + or - inside shift
>>
>> both of which are probably worth fixing.
>
> Hmm - I don't see this warning.
> What version of sparse are you using - and do you pass any extra arguments to sparse?
>
> CHECK drivers/staging/iio/adc/ad799x_core.c
> CC drivers/staging/iio/adc/ad799x_core.o
> LD drivers/staging/iio/adc/ad799x.o
Hi Michael,
Whilst testing the light sensor I discovered that this warning isn't form sparse, its
from gcc itself. Sorry for the false info. I'm using a 4.3.3 arm cross compiler.
Jonathan
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2010-10-08 8:51 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-10-01 9:41 [RFC] staging: iio: adc: Enable driver support for ad799x AD converters Michael Hennerich
2010-10-01 9:41 ` [PATCH] " Michael Hennerich
2010-10-01 12:09 ` Jonathan Cameron
2010-10-01 15:07 ` Hennerich, Michael
2010-10-01 15:50 ` Jonathan Cameron
2010-10-04 8:26 ` Hennerich, Michael
2010-10-04 9:56 ` Jonathan Cameron
2010-10-04 12:13 ` Hennerich, Michael
2010-10-05 8:32 ` Hennerich, Michael
2010-10-08 8:57 ` Jonathan Cameron
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.