summaryrefslogtreecommitdiffstats
path: root/drivers/staging/iio/adc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/iio/adc')
-rw-r--r--drivers/staging/iio/adc/Kconfig35
-rw-r--r--drivers/staging/iio/adc/Makefile11
-rw-r--r--drivers/staging/iio/adc/ad7298.c501
-rw-r--r--drivers/staging/iio/adc/ad7298.h80
-rw-r--r--drivers/staging/iio/adc/ad7298_core.c287
-rw-r--r--drivers/staging/iio/adc/ad7298_ring.c258
-rw-r--r--drivers/staging/iio/adc/ad7476.h1
-rw-r--r--drivers/staging/iio/adc/ad7476_core.c2
-rw-r--r--drivers/staging/iio/adc/ad7476_ring.c37
-rw-r--r--drivers/staging/iio/adc/ad7606.h117
-rw-r--r--drivers/staging/iio/adc/ad7606_core.c556
-rw-r--r--drivers/staging/iio/adc/ad7606_par.c188
-rw-r--r--drivers/staging/iio/adc/ad7606_ring.c280
-rw-r--r--drivers/staging/iio/adc/ad7606_spi.c126
-rw-r--r--drivers/staging/iio/adc/ad7887.h1
-rw-r--r--drivers/staging/iio/adc/ad7887_ring.c36
-rw-r--r--drivers/staging/iio/adc/ad799x.h1
-rw-r--r--drivers/staging/iio/adc/ad799x_core.c12
-rw-r--r--drivers/staging/iio/adc/ad799x_ring.c43
19 files changed, 2010 insertions, 562 deletions
diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig
index 86869cd233ae..6692a3d87f23 100644
--- a/drivers/staging/iio/adc/Kconfig
+++ b/drivers/staging/iio/adc/Kconfig
@@ -49,11 +49,14 @@ config AD7291
temperature sensors.
config AD7298
- tristate "Analog Devices AD7298 temperature sensor and ADC driver"
+ tristate "Analog Devices AD7298 ADC driver"
depends on SPI
help
Say yes here to build support for Analog Devices AD7298
- temperature sensors and ADC.
+ 8 Channel ADC with temperature sensor.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ad7298.
config AD7314
tristate "Analog Devices AD7314 temperature sensor driver"
@@ -62,6 +65,34 @@ config AD7314
Say yes here to build support for Analog Devices AD7314
temperature sensors.
+config AD7606
+ tristate "Analog Devices AD7606 ADC driver"
+ depends on GPIOLIB
+ select IIO_RING_BUFFER
+ select IIO_TRIGGER
+ select IIO_SW_RING
+ help
+ Say yes here to build support for Analog Devices:
+ ad7606, ad7606-6, ad7606-4 analog to digital convertors (ADC).
+
+ To compile this driver as a module, choose M here: the
+ module will be called ad7606.
+
+config AD7606_IFACE_PARALLEL
+ tristate "parallel interface support"
+ depends on AD7606
+ help
+ Say yes here to include parallel interface support on the AD7606
+ ADC driver.
+
+config AD7606_IFACE_SPI
+ tristate "spi interface support"
+ depends on AD7606
+ depends on SPI
+ help
+ Say yes here to include parallel interface support on the AD7606
+ ADC driver.
+
config AD799X
tristate "Analog Devices AD799x ADC driver"
depends on I2C
diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile
index 6f231a2cb777..31067defd79b 100644
--- a/drivers/staging/iio/adc/Makefile
+++ b/drivers/staging/iio/adc/Makefile
@@ -7,6 +7,12 @@ max1363-y += max1363_ring.o
obj-$(CONFIG_MAX1363) += max1363.o
+ad7606-y := ad7606_core.o
+ad7606-$(CONFIG_IIO_RING_BUFFER) += ad7606_ring.o
+ad7606-$(CONFIG_AD7606_IFACE_PARALLEL) += ad7606_par.o
+ad7606-$(CONFIG_AD7606_IFACE_SPI) += ad7606_spi.o
+obj-$(CONFIG_AD7606) += ad7606.o
+
ad799x-y := ad799x_core.o
ad799x-$(CONFIG_AD799X_RING_BUFFER) += ad799x_ring.o
obj-$(CONFIG_AD799X) += ad799x.o
@@ -19,10 +25,13 @@ ad7887-y := ad7887_core.o
ad7887-$(CONFIG_IIO_RING_BUFFER) += ad7887_ring.o
obj-$(CONFIG_AD7887) += ad7887.o
+ad7298-y := ad7298_core.o
+ad7298-$(CONFIG_IIO_RING_BUFFER) += ad7298_ring.o
+obj-$(CONFIG_AD7298) += ad7298.o
+
obj-$(CONFIG_AD7150) += ad7150.o
obj-$(CONFIG_AD7152) += ad7152.o
obj-$(CONFIG_AD7291) += ad7291.o
-obj-$(CONFIG_AD7298) += ad7298.o
obj-$(CONFIG_AD7314) += ad7314.o
obj-$(CONFIG_AD7745) += ad7745.o
obj-$(CONFIG_AD7816) += ad7816.o
diff --git a/drivers/staging/iio/adc/ad7298.c b/drivers/staging/iio/adc/ad7298.c
deleted file mode 100644
index 1a080c977637..000000000000
--- a/drivers/staging/iio/adc/ad7298.c
+++ /dev/null
@@ -1,501 +0,0 @@
-/*
- * AD7298 digital temperature sensor driver supporting AD7298
- *
- * Copyright 2010 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
- */
-
-#include <linux/interrupt.h>
-#include <linux/gpio.h>
-#include <linux/workqueue.h>
-#include <linux/device.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/sysfs.h>
-#include <linux/list.h>
-#include <linux/spi/spi.h>
-#include <linux/rtc.h>
-
-#include "../iio.h"
-#include "../sysfs.h"
-
-/*
- * AD7298 command
- */
-#define AD7298_PD 0x1
-#define AD7298_T_AVG_MASK 0x2
-#define AD7298_EXT_REF 0x4
-#define AD7298_T_SENSE_MASK 0x20
-#define AD7298_VOLTAGE_MASK 0x3fc0
-#define AD7298_VOLTAGE_OFFSET 0x6
-#define AD7298_VOLTAGE_LIMIT_COUNT 8
-#define AD7298_REPEAT 0x40
-#define AD7298_WRITE 0x80
-
-/*
- * AD7298 value masks
- */
-#define AD7298_CHANNEL_MASK 0xf000
-#define AD7298_VALUE_MASK 0xfff
-#define AD7298_T_VALUE_SIGN 0x400
-#define AD7298_T_VALUE_FLOAT_OFFSET 2
-#define AD7298_T_VALUE_FLOAT_MASK 0x2
-
-/*
- * struct ad7298_chip_info - chip specifc information
- */
-
-struct ad7298_chip_info {
- const char *name;
- struct spi_device *spi_dev;
- struct iio_dev *indio_dev;
- u16 command;
- u16 busy_pin;
- u8 channels; /* Active voltage channels */
-};
-
-/*
- * ad7298 register access by SPI
- */
-static int ad7298_spi_write(struct ad7298_chip_info *chip, u16 data)
-{
- struct spi_device *spi_dev = chip->spi_dev;
- int ret = 0;
-
- data |= AD7298_WRITE;
- data = cpu_to_be16(data);
- ret = spi_write(spi_dev, (u8 *)&data, sizeof(data));
- if (ret < 0)
- dev_err(&spi_dev->dev, "SPI write error\n");
-
- return ret;
-}
-
-static int ad7298_spi_read(struct ad7298_chip_info *chip, u16 mask, u16 *data)
-{
- struct spi_device *spi_dev = chip->spi_dev;
- int ret = 0;
- u8 count = chip->channels;
- u16 command;
- int i;
-
- if (mask & AD7298_T_SENSE_MASK) {
- command = chip->command & ~(AD7298_T_AVG_MASK | AD7298_VOLTAGE_MASK);
- command |= AD7298_T_SENSE_MASK;
- count = 1;
- } else if (mask & AD7298_T_AVG_MASK) {
- command = chip->command & ~AD7298_VOLTAGE_MASK;
- command |= AD7298_T_SENSE_MASK | AD7298_T_AVG_MASK;
- count = 2;
- } else if (mask & AD7298_VOLTAGE_MASK) {
- command = chip->command & ~(AD7298_T_AVG_MASK | AD7298_T_SENSE_MASK);
- count = chip->channels;
- }
-
- ret = ad7298_spi_write(chip, chip->command);
- if (ret < 0) {
- dev_err(&spi_dev->dev, "SPI write command error\n");
- return ret;
- }
-
- ret = spi_read(spi_dev, (u8 *)&command, sizeof(command));
- if (ret < 0) {
- dev_err(&spi_dev->dev, "SPI read error\n");
- return ret;
- }
-
- i = 10000;
- while (i && gpio_get_value(chip->busy_pin)) {
- cpu_relax();
- i--;
- }
- if (!i) {
- dev_err(&spi_dev->dev, "Always in busy convertion.\n");
- return -EBUSY;
- }
-
- for (i = 0; i < count; i++) {
- ret = spi_read(spi_dev, (u8 *)&data[i], sizeof(data[i]));
- if (ret < 0) {
- dev_err(&spi_dev->dev, "SPI read error\n");
- return ret;
- }
- *data = be16_to_cpu(data[i]);
- }
-
- return 0;
-}
-
-static ssize_t ad7298_show_mode(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
- struct ad7298_chip_info *chip = dev_info->dev_data;
-
- if (chip->command & AD7298_REPEAT)
- return sprintf(buf, "repeat\n");
- else
- return sprintf(buf, "normal\n");
-}
-
-static ssize_t ad7298_store_mode(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
-{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
- struct ad7298_chip_info *chip = dev_info->dev_data;
-
- if (strcmp(buf, "repeat"))
- chip->command |= AD7298_REPEAT;
- else
- chip->command &= (~AD7298_REPEAT);
-
- return 1;
-}
-
-static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
- ad7298_show_mode,
- ad7298_store_mode,
- 0);
-
-static ssize_t ad7298_show_available_modes(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return sprintf(buf, "normal\nrepeat\n");
-}
-
-static IIO_DEVICE_ATTR(available_modes, S_IRUGO, ad7298_show_available_modes, NULL, 0);
-
-static ssize_t ad7298_store_reset(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
-{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
- struct ad7298_chip_info *chip = dev_info->dev_data;
- u16 command;
- int ret;
-
- command = chip->command & ~AD7298_PD;
-
- ret = ad7298_spi_write(chip, command);
- if (ret)
- return -EIO;
-
- command = chip->command | AD7298_PD;
-
- ret = ad7298_spi_write(chip, command);
- if (ret)
- return -EIO;
-
- return len;
-}
-
-static IIO_DEVICE_ATTR(reset, S_IWUSR,
- NULL,
- ad7298_store_reset,
- 0);
-
-static ssize_t ad7298_show_ext_ref(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
- struct ad7298_chip_info *chip = dev_info->dev_data;
-
- return sprintf(buf, "%d\n", !!(chip->command & AD7298_EXT_REF));
-}
-
-static ssize_t ad7298_store_ext_ref(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
-{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
- struct ad7298_chip_info *chip = dev_info->dev_data;
- u16 command;
- int ret;
-
- command = chip->command & (~AD7298_EXT_REF);
- if (strcmp(buf, "1"))
- command |= AD7298_EXT_REF;
-
- ret = ad7298_spi_write(chip, command);
- if (ret)
- return -EIO;
-
- chip->command = command;
-
- return len;
-}
-
-static IIO_DEVICE_ATTR(ext_ref, S_IRUGO | S_IWUSR,
- ad7298_show_ext_ref,
- ad7298_store_ext_ref,
- 0);
-
-static ssize_t ad7298_show_t_sense(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
- struct ad7298_chip_info *chip = dev_info->dev_data;
- u16 data;
- char sign = ' ';
- int ret;
-
- ret = ad7298_spi_read(chip, AD7298_T_SENSE_MASK, &data);
- if (ret)
- return -EIO;
-
- if (data & AD7298_T_VALUE_SIGN) {
- /* convert supplement to positive value */
- data = (AD7298_T_VALUE_SIGN << 1) - data;
- sign = '-';
- }
-
- return sprintf(buf, "%c%d.%.2d\n", sign,
- (data >> AD7298_T_VALUE_FLOAT_OFFSET),
- (data & AD7298_T_VALUE_FLOAT_MASK) * 25);
-}
-
-static IIO_DEVICE_ATTR(t_sense, S_IRUGO, ad7298_show_t_sense, NULL, 0);
-
-static ssize_t ad7298_show_t_average(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
- struct ad7298_chip_info *chip = dev_info->dev_data;
- u16 data[2];
- char sign = ' ';
- int ret;
-
- ret = ad7298_spi_read(chip, AD7298_T_AVG_MASK, data);
- if (ret)
- return -EIO;
-
- if (data[1] & AD7298_T_VALUE_SIGN) {
- /* convert supplement to positive value */
- data[1] = (AD7298_T_VALUE_SIGN << 1) - data[1];
- sign = '-';
- }
-
- return sprintf(buf, "%c%d.%.2d\n", sign,
- (data[1] >> AD7298_T_VALUE_FLOAT_OFFSET),
- (data[1] & AD7298_T_VALUE_FLOAT_MASK) * 25);
-}
-
-static IIO_DEVICE_ATTR(t_average, S_IRUGO, ad7298_show_t_average, NULL, 0);
-
-static ssize_t ad7298_show_voltage(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
- struct ad7298_chip_info *chip = dev_info->dev_data;
- u16 data[AD7298_VOLTAGE_LIMIT_COUNT];
- int i, size, ret;
-
- ret = ad7298_spi_read(chip, AD7298_VOLTAGE_MASK, data);
- if (ret)
- return -EIO;
-
- for (i = 0; i < AD7298_VOLTAGE_LIMIT_COUNT; i++) {
- if (chip->command & (AD7298_T_SENSE_MASK << i)) {
- ret = sprintf(buf, "channel[%d]=%d\n", i,
- data[i] & AD7298_VALUE_MASK);
- if (ret < 0)
- break;
- buf += ret;
- size += ret;
- }
- }
-
- return size;
-}
-
-static IIO_DEVICE_ATTR(voltage, S_IRUGO, ad7298_show_voltage, NULL, 0);
-
-static ssize_t ad7298_show_channel_mask(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
- struct ad7298_chip_info *chip = dev_info->dev_data;
-
- return sprintf(buf, "0x%x\n", (chip->command & AD7298_VOLTAGE_MASK) >>
- AD7298_VOLTAGE_OFFSET);
-}
-
-static ssize_t ad7298_store_channel_mask(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
-{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
- struct ad7298_chip_info *chip = dev_info->dev_data;
- unsigned long data;
- int i, ret;
-
- ret = strict_strtoul(buf, 16, &data);
- if (ret || data > 0xff)
- return -EINVAL;
-
- chip->command &= (~AD7298_VOLTAGE_MASK);
- chip->command |= data << AD7298_VOLTAGE_OFFSET;
-
- for (i = 0, chip->channels = 0; i < AD7298_VOLTAGE_LIMIT_COUNT; i++) {
- if (chip->command & (AD7298_T_SENSE_MASK << i))
- chip->channels++;
- }
-
- return ret;
-}
-
-static IIO_DEVICE_ATTR(channel_mask, S_IRUGO | S_IWUSR,
- ad7298_show_channel_mask,
- ad7298_store_channel_mask,
- 0);
-
-static ssize_t ad7298_show_name(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
- struct ad7298_chip_info *chip = dev_info->dev_data;
- return sprintf(buf, "%s\n", chip->name);
-}
-
-static IIO_DEVICE_ATTR(name, S_IRUGO, ad7298_show_name, NULL, 0);
-
-static struct attribute *ad7298_attributes[] = {
- &iio_dev_attr_available_modes.dev_attr.attr,
- &iio_dev_attr_mode.dev_attr.attr,
- &iio_dev_attr_reset.dev_attr.attr,
- &iio_dev_attr_ext_ref.dev_attr.attr,
- &iio_dev_attr_t_sense.dev_attr.attr,
- &iio_dev_attr_t_average.dev_attr.attr,
- &iio_dev_attr_voltage.dev_attr.attr,
- &iio_dev_attr_channel_mask.dev_attr.attr,
- &iio_dev_attr_name.dev_attr.attr,
- NULL,
-};
-
-static const struct attribute_group ad7298_attribute_group = {
- .attrs = ad7298_attributes,
-};
-
-/*
- * device probe and remove
- */
-static int __devinit ad7298_probe(struct spi_device *spi_dev)
-{
- struct ad7298_chip_info *chip;
- unsigned short *pins = spi_dev->dev.platform_data;
- int ret = 0;
-
- chip = kzalloc(sizeof(struct ad7298_chip_info), GFP_KERNEL);
-
- if (chip == NULL)
- return -ENOMEM;
-
- /* this is only used for device removal purposes */
- dev_set_drvdata(&spi_dev->dev, chip);
-
- chip->spi_dev = spi_dev;
- chip->name = spi_dev->modalias;
- chip->busy_pin = pins[0];
-
- ret = gpio_request(chip->busy_pin, chip->name);
- if (ret) {
- dev_err(&spi_dev->dev, "Fail to request busy gpio PIN %d.\n",
- chip->busy_pin);
- goto error_free_chip;
- }
- gpio_direction_input(chip->busy_pin);
-
- chip->indio_dev = iio_allocate_device();
- if (chip->indio_dev == NULL) {
- ret = -ENOMEM;
- goto error_free_gpio;
- }
-
- chip->indio_dev->dev.parent = &spi_dev->dev;
- chip->indio_dev->attrs = &ad7298_attribute_group;
- chip->indio_dev->dev_data = (void *)chip;
- chip->indio_dev->driver_module = THIS_MODULE;
- chip->indio_dev->modes = INDIO_DIRECT_MODE;
-
- ret = iio_device_register(chip->indio_dev);
- if (ret)
- goto error_free_dev;
-
- dev_info(&spi_dev->dev, "%s temperature sensor and ADC registered.\n",
- chip->name);
-
- return 0;
-
-error_free_dev:
- iio_free_device(chip->indio_dev);
-error_free_gpio:
- gpio_free(chip->busy_pin);
-error_free_chip:
- kfree(chip);
-
- return ret;
-}
-
-static int __devexit ad7298_remove(struct spi_device *spi_dev)
-{
- struct ad7298_chip_info *chip = dev_get_drvdata(&spi_dev->dev);
- struct iio_dev *indio_dev = chip->indio_dev;
-
- dev_set_drvdata(&spi_dev->dev, NULL);
- iio_device_unregister(indio_dev);
- iio_free_device(chip->indio_dev);
- gpio_free(chip->busy_pin);
- kfree(chip);
-
- return 0;
-}
-
-static const struct spi_device_id ad7298_id[] = {
- { "ad7298", 0 },
- {}
-};
-
-MODULE_DEVICE_TABLE(spi, ad7298_id);
-
-static struct spi_driver ad7298_driver = {
- .driver = {
- .name = "ad7298",
- .bus = &spi_bus_type,
- .owner = THIS_MODULE,
- },
- .probe = ad7298_probe,
- .remove = __devexit_p(ad7298_remove),
- .id_table = ad7298_id,
-};
-
-static __init int ad7298_init(void)
-{
- return spi_register_driver(&ad7298_driver);
-}
-
-static __exit void ad7298_exit(void)
-{
- spi_unregister_driver(&ad7298_driver);
-}
-
-MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
-MODULE_DESCRIPTION("Analog Devices AD7298 digital"
- " temperature sensor and ADC driver");
-MODULE_LICENSE("GPL v2");
-
-module_init(ad7298_init);
-module_exit(ad7298_exit);
diff --git a/drivers/staging/iio/adc/ad7298.h b/drivers/staging/iio/adc/ad7298.h
new file mode 100644
index 000000000000..fe7ed77d638f
--- /dev/null
+++ b/drivers/staging/iio/adc/ad7298.h
@@ -0,0 +1,80 @@
+/*
+ * AD7298 SPI ADC driver
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef IIO_ADC_AD7298_H_
+#define IIO_ADC_AD7298_H_
+
+#define AD7298_WRITE (1 << 15) /* write to the control register */
+#define AD7298_REPEAT (1 << 14) /* repeated conversion enable */
+#define AD7298_CH(x) (1 << (13 - (x))) /* channel select */
+#define AD7298_TSENSE (1 << 5) /* temperature conversion enable */
+#define AD7298_EXTREF (1 << 2) /* external reference enable */
+#define AD7298_TAVG (1 << 1) /* temperature sensor averaging enable */
+#define AD7298_PDD (1 << 0) /* partial power down enable */
+
+#define AD7298_CH_MASK (AD7298_CH0 | AD7298_CH1 | AD7298_CH2 | AD7298_CH3 | \
+ AD7298_CH4 | AD7298_CH5 | AD7298_CH6 | AD7298_CH7)
+
+#define AD7298_MAX_CHAN 8
+#define AD7298_BITS 12
+#define AD7298_STORAGE_BITS 16
+#define AD7298_INTREF_mV 2500
+
+#define RES_MASK(bits) ((1 << (bits)) - 1)
+
+/*
+ * TODO: struct ad7298_platform_data needs to go into include/linux/iio
+ */
+
+struct ad7298_platform_data {
+ /* External Vref voltage applied */
+ u16 vref_mv;
+};
+
+struct ad7298_state {
+ struct iio_dev *indio_dev;
+ struct spi_device *spi;
+ struct regulator *reg;
+ struct work_struct poll_work;
+ atomic_t protect_ring;
+ size_t d_size;
+ u16 int_vref_mv;
+ unsigned ext_ref;
+ struct spi_transfer ring_xfer[10];
+ struct spi_transfer scan_single_xfer[3];
+ struct spi_message ring_msg;
+ struct spi_message scan_single_msg;
+ /*
+ * DMA (thus cache coherency maintenance) requires the
+ * transfer buffers to live in their own cache lines.
+ */
+ unsigned short rx_buf[8] ____cacheline_aligned;
+ unsigned short tx_buf[2];
+};
+
+#ifdef CONFIG_IIO_RING_BUFFER
+int ad7298_scan_from_ring(struct ad7298_state *st, long ch);
+int ad7298_register_ring_funcs_and_init(struct iio_dev *indio_dev);
+void ad7298_ring_cleanup(struct iio_dev *indio_dev);
+#else /* CONFIG_IIO_RING_BUFFER */
+static inline int ad7298_scan_from_ring(struct ad7298_state *st, long ch)
+{
+ return 0;
+}
+
+static inline int
+ad7298_register_ring_funcs_and_init(struct iio_dev *indio_dev)
+{
+ return 0;
+}
+
+static inline void ad7298_ring_cleanup(struct iio_dev *indio_dev)
+{
+}
+#endif /* CONFIG_IIO_RING_BUFFER */
+#endif /* IIO_ADC_AD7298_H_ */
diff --git a/drivers/staging/iio/adc/ad7298_core.c b/drivers/staging/iio/adc/ad7298_core.c
new file mode 100644
index 000000000000..2e9154e7d887
--- /dev/null
+++ b/drivers/staging/iio/adc/ad7298_core.c
@@ -0,0 +1,287 @@
+/*
+ * AD7298 SPI ADC driver
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/spi/spi.h>
+#include <linux/regulator/consumer.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "../ring_generic.h"
+#include "adc.h"
+
+#include "ad7298.h"
+
+static int ad7298_scan_direct(struct ad7298_state *st, unsigned ch)
+{
+ int ret;
+ st->tx_buf[0] = cpu_to_be16(AD7298_WRITE | st->ext_ref |
+ (AD7298_CH(0) >> ch));
+
+ ret = spi_sync(st->spi, &st->scan_single_msg);
+ if (ret)
+ return ret;
+
+ return be16_to_cpu(st->rx_buf[0]);
+}
+
+static ssize_t ad7298_scan(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7298_state *st = dev_info->dev_data;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ int ret;
+
+ mutex_lock(&dev_info->mlock);
+ if (iio_ring_enabled(dev_info))
+ ret = ad7298_scan_from_ring(st, this_attr->address);
+ else
+ ret = ad7298_scan_direct(st, this_attr->address);
+ mutex_unlock(&dev_info->mlock);
+
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%d\n", ret & RES_MASK(AD7298_BITS));
+}
+
+static IIO_DEV_ATTR_IN_RAW(0, ad7298_scan, 0);
+static IIO_DEV_ATTR_IN_RAW(1, ad7298_scan, 1);
+static IIO_DEV_ATTR_IN_RAW(2, ad7298_scan, 2);
+static IIO_DEV_ATTR_IN_RAW(3, ad7298_scan, 3);
+static IIO_DEV_ATTR_IN_RAW(4, ad7298_scan, 4);
+static IIO_DEV_ATTR_IN_RAW(5, ad7298_scan, 5);
+static IIO_DEV_ATTR_IN_RAW(6, ad7298_scan, 6);
+static IIO_DEV_ATTR_IN_RAW(7, ad7298_scan, 7);
+
+static ssize_t ad7298_show_temp(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7298_state *st = iio_dev_get_devdata(dev_info);
+ int tmp;
+
+ tmp = cpu_to_be16(AD7298_WRITE | AD7298_TSENSE |
+ AD7298_TAVG | st->ext_ref);
+
+ mutex_lock(&dev_info->mlock);
+ spi_write(st->spi, (u8 *)&tmp, 2);
+ tmp = 0;
+ spi_write(st->spi, (u8 *)&tmp, 2);
+ usleep_range(101, 1000); /* sleep > 100us */
+ spi_read(st->spi, (u8 *)&tmp, 2);
+ mutex_unlock(&dev_info->mlock);
+
+ tmp = be16_to_cpu(tmp) & RES_MASK(AD7298_BITS);
+
+ /*
+ * One LSB of the ADC corresponds to 0.25 deg C.
+ * The temperature reading is in 12-bit twos complement format
+ */
+
+ if (tmp & (1 << (AD7298_BITS - 1))) {
+ tmp = (4096 - tmp) * 250;
+ tmp -= (2 * tmp);
+
+ } else {
+ tmp *= 250; /* temperature in milli degrees Celsius */
+ }
+
+ return sprintf(buf, "%d\n", tmp);
+}
+
+static IIO_DEVICE_ATTR(temp0_input, S_IRUGO, ad7298_show_temp, NULL, 0);
+
+static ssize_t ad7298_show_scale(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7298_state *st = iio_dev_get_devdata(dev_info);
+ /* Corresponds to Vref / 2^(bits) */
+ unsigned int scale_uv = (st->int_vref_mv * 1000) >> AD7298_BITS;
+
+ return sprintf(buf, "%d.%03d\n", scale_uv / 1000, scale_uv % 1000);
+}
+static IIO_DEVICE_ATTR(in_scale, S_IRUGO, ad7298_show_scale, NULL, 0);
+
+static ssize_t ad7298_show_name(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7298_state *st = iio_dev_get_devdata(dev_info);
+
+ return sprintf(buf, "%s\n", spi_get_device_id(st->spi)->name);
+}
+static IIO_DEVICE_ATTR(name, S_IRUGO, ad7298_show_name, NULL, 0);
+
+static struct attribute *ad7298_attributes[] = {
+ &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_in_scale.dev_attr.attr,
+ &iio_dev_attr_temp0_input.dev_attr.attr,
+ &iio_dev_attr_name.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ad7298_attribute_group = {
+ .attrs = ad7298_attributes,
+};
+
+static int __devinit ad7298_probe(struct spi_device *spi)
+{
+ struct ad7298_platform_data *pdata = spi->dev.platform_data;
+ struct ad7298_state *st;
+ int ret;
+
+ st = kzalloc(sizeof(*st), GFP_KERNEL);
+ if (st == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+
+ st->reg = regulator_get(&spi->dev, "vcc");
+ if (!IS_ERR(st->reg)) {
+ ret = regulator_enable(st->reg);
+ if (ret)
+ goto error_put_reg;
+ }
+
+ spi_set_drvdata(spi, st);
+
+ atomic_set(&st->protect_ring, 0);
+ st->spi = spi;
+
+ st->indio_dev = iio_allocate_device();
+ if (st->indio_dev == NULL) {
+ ret = -ENOMEM;
+ goto error_disable_reg;
+ }
+
+ st->indio_dev->dev.parent = &spi->dev;
+ st->indio_dev->attrs = &ad7298_attribute_group;
+ st->indio_dev->dev_data = (void *)(st);
+ st->indio_dev->driver_module = THIS_MODULE;
+ st->indio_dev->modes = INDIO_DIRECT_MODE;
+
+ /* Setup default message */
+
+ st->scan_single_xfer[0].tx_buf = &st->tx_buf[0];
+ st->scan_single_xfer[0].len = 2;
+ st->scan_single_xfer[0].cs_change = 1;
+ st->scan_single_xfer[1].tx_buf = &st->tx_buf[1];
+ st->scan_single_xfer[1].len = 2;
+ st->scan_single_xfer[1].cs_change = 1;
+ st->scan_single_xfer[2].rx_buf = &st->rx_buf[0];
+ st->scan_single_xfer[2].len = 2;
+
+ spi_message_init(&st->scan_single_msg);
+ spi_message_add_tail(&st->scan_single_xfer[0], &st->scan_single_msg);
+ spi_message_add_tail(&st->scan_single_xfer[1], &st->scan_single_msg);
+ spi_message_add_tail(&st->scan_single_xfer[2], &st->scan_single_msg);
+
+ if (pdata && pdata->vref_mv) {
+ st->int_vref_mv = pdata->vref_mv;
+ st->ext_ref = AD7298_EXTREF;
+ } else {
+ st->int_vref_mv = AD7298_INTREF_mV;
+ }
+
+ ret = ad7298_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_free_device;
+
+ ret = iio_ring_buffer_register(st->indio_dev->ring, 0);
+ if (ret)
+ goto error_cleanup_ring;
+ return 0;
+
+error_cleanup_ring:
+ ad7298_ring_cleanup(st->indio_dev);
+ iio_device_unregister(st->indio_dev);
+error_free_device:
+ iio_free_device(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 int __devexit ad7298_remove(struct spi_device *spi)
+{
+ struct ad7298_state *st = spi_get_drvdata(spi);
+ struct iio_dev *indio_dev = st->indio_dev;
+
+ iio_ring_buffer_unregister(indio_dev->ring);
+ ad7298_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 spi_device_id ad7298_id[] = {
+ {"ad7298", 0},
+ {}
+};
+
+static struct spi_driver ad7298_driver = {
+ .driver = {
+ .name = "ad7298",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = ad7298_probe,
+ .remove = __devexit_p(ad7298_remove),
+ .id_table = ad7298_id,
+};
+
+static int __init ad7298_init(void)
+{
+ return spi_register_driver(&ad7298_driver);
+}
+module_init(ad7298_init);
+
+static void __exit ad7298_exit(void)
+{
+ spi_unregister_driver(&ad7298_driver);
+}
+module_exit(ad7298_exit);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Analog Devices AD7298 ADC");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("spi:ad7298");
diff --git a/drivers/staging/iio/adc/ad7298_ring.c b/drivers/staging/iio/adc/ad7298_ring.c
new file mode 100644
index 000000000000..19d1aced1e6c
--- /dev/null
+++ b/drivers/staging/iio/adc/ad7298_ring.c
@@ -0,0 +1,258 @@
+/*
+ * AD7298 SPI ADC driver
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/spi/spi.h>
+
+#include "../iio.h"
+#include "../ring_generic.h"
+#include "../ring_sw.h"
+#include "../trigger.h"
+#include "../sysfs.h"
+
+#include "ad7298.h"
+
+static IIO_SCAN_EL_C(in0, 0, 0, NULL);
+static IIO_SCAN_EL_C(in1, 1, 0, NULL);
+static IIO_SCAN_EL_C(in2, 2, 0, NULL);
+static IIO_SCAN_EL_C(in3, 3, 0, NULL);
+static IIO_SCAN_EL_C(in4, 4, 0, NULL);
+static IIO_SCAN_EL_C(in5, 5, 0, NULL);
+static IIO_SCAN_EL_C(in6, 6, 0, NULL);
+static IIO_SCAN_EL_C(in7, 7, 0, NULL);
+
+static IIO_SCAN_EL_TIMESTAMP(8);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(timestamp, s, 64, 64);
+
+static IIO_CONST_ATTR(in_type, "u12/16") ;
+
+static struct attribute *ad7298_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_const_attr_timestamp_index.dev_attr.attr,
+ &iio_scan_el_timestamp.dev_attr.attr,
+ &iio_const_attr_timestamp_type.dev_attr.attr,
+ &iio_const_attr_in_type.dev_attr.attr,
+ NULL,
+};
+
+static struct attribute_group ad7298_scan_el_group = {
+ .name = "scan_elements",
+ .attrs = ad7298_scan_el_attrs,
+};
+
+int ad7298_scan_from_ring(struct ad7298_state *st, long ch)
+{
+ struct iio_ring_buffer *ring = st->indio_dev->ring;
+ int ret;
+ u16 *ring_data;
+
+ if (!(ring->scan_mask & (1 << ch))) {
+ ret = -EBUSY;
+ goto error_ret;
+ }
+
+ ring_data = kmalloc(ring->access.get_bytes_per_datum(ring), GFP_KERNEL);
+ if (ring_data == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+ ret = ring->access.read_last(ring, (u8 *) ring_data);
+ if (ret)
+ goto error_free_ring_data;
+
+ ret = be16_to_cpu(ring_data[ch]);
+
+error_free_ring_data:
+ kfree(ring_data);
+error_ret:
+ return ret;
+}
+
+/**
+ * ad7298_ring_preenable() setup the parameters of the ring before enabling
+ *
+ * The complex nature of the setting of the number of bytes per datum is due
+ * to this driver currently ensuring that the timestamp is stored at an 8
+ * byte boundary.
+ **/
+static int ad7298_ring_preenable(struct iio_dev *indio_dev)
+{
+ struct ad7298_state *st = indio_dev->dev_data;
+ struct iio_ring_buffer *ring = indio_dev->ring;
+ size_t d_size;
+ int i, m;
+ unsigned short command;
+
+ d_size = ring->scan_count * (AD7298_STORAGE_BITS / 8);
+
+ if (ring->scan_timestamp) {
+ d_size += sizeof(s64);
+
+ if (d_size % sizeof(s64))
+ d_size += sizeof(s64) - (d_size % sizeof(s64));
+ }
+
+ if (ring->access.set_bytes_per_datum)
+ ring->access.set_bytes_per_datum(ring, d_size);
+
+ st->d_size = d_size;
+
+ command = AD7298_WRITE | st->ext_ref;
+
+ for (i = 0, m = AD7298_CH(0); i < AD7298_MAX_CHAN; i++, m >>= 1)
+ if (ring->scan_mask & (1 << i))
+ command |= m;
+
+ st->tx_buf[0] = cpu_to_be16(command);
+
+ /* build spi ring message */
+ st->ring_xfer[0].tx_buf = &st->tx_buf[0];
+ st->ring_xfer[0].len = 2;
+ st->ring_xfer[0].cs_change = 1;
+ st->ring_xfer[1].tx_buf = &st->tx_buf[1];
+ st->ring_xfer[1].len = 2;
+ st->ring_xfer[1].cs_change = 1;
+
+ spi_message_init(&st->ring_msg);
+ spi_message_add_tail(&st->ring_xfer[0], &st->ring_msg);
+ spi_message_add_tail(&st->ring_xfer[1], &st->ring_msg);
+
+ for (i = 0; i < ring->scan_count; i++) {
+ st->ring_xfer[i + 2].rx_buf = &st->rx_buf[i];
+ st->ring_xfer[i + 2].len = 2;
+ st->ring_xfer[i + 2].cs_change = 1;
+ spi_message_add_tail(&st->ring_xfer[i + 2], &st->ring_msg);
+ }
+ /* make sure last transfer cs_change is not set */
+ st->ring_xfer[i + 1].cs_change = 0;
+
+ return 0;
+}
+
+/**
+ * ad7298_poll_func_th() th of trigger launched polling to ring buffer
+ *
+ * As sampling only occurs on spi 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 ad7298_poll_func_th(struct iio_dev *indio_dev, s64 time)
+{
+ struct ad7298_state *st = indio_dev->dev_data;
+
+ schedule_work(&st->poll_work);
+ return;
+}
+
+/**
+ * ad7298_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 ad7298_poll_bh_to_ring(struct work_struct *work_s)
+{
+ struct ad7298_state *st = container_of(work_s, struct ad7298_state,
+ poll_work);
+ struct iio_dev *indio_dev = st->indio_dev;
+ struct iio_sw_ring_buffer *sw_ring = iio_to_sw_ring(indio_dev->ring);
+ struct iio_ring_buffer *ring = indio_dev->ring;
+ s64 time_ns;
+ __u16 buf[16];
+ int b_sent, i;
+
+ /* Ensure only one copy of this function running at a time */
+ if (atomic_inc_return(&st->protect_ring) > 1)
+ return;
+
+ b_sent = spi_sync(st->spi, &st->ring_msg);
+ if (b_sent)
+ goto done;
+
+ if (ring->scan_timestamp) {
+ time_ns = iio_get_time_ns();
+ memcpy((u8 *)buf + st->d_size - sizeof(s64),
+ &time_ns, sizeof(time_ns));
+ }
+
+ for (i = 0; i < ring->scan_count; i++)
+ buf[i] = be16_to_cpu(st->rx_buf[i]);
+
+ indio_dev->ring->access.store_to(&sw_ring->buf, (u8 *)buf, time_ns);
+done:
+ atomic_dec(&st->protect_ring);
+}
+
+int ad7298_register_ring_funcs_and_init(struct iio_dev *indio_dev)
+{
+ struct ad7298_state *st = indio_dev->dev_data;
+ int ret;
+
+ 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(&indio_dev->ring->access);
+ ret = iio_alloc_pollfunc(indio_dev, NULL, &ad7298_poll_func_th);
+ if (ret)
+ goto error_deallocate_sw_rb;
+
+ /* Ring buffer functions - here trigger setup related */
+
+ indio_dev->ring->preenable = &ad7298_ring_preenable;
+ indio_dev->ring->postenable = &iio_triggered_ring_postenable;
+ indio_dev->ring->predisable = &iio_triggered_ring_predisable;
+ indio_dev->ring->scan_el_attrs = &ad7298_scan_el_group;
+ indio_dev->ring->scan_timestamp = true;
+
+ INIT_WORK(&st->poll_work, &ad7298_poll_bh_to_ring);
+
+ /* 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 ad7298_ring_cleanup(struct iio_dev *indio_dev)
+{
+ 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);
+}
diff --git a/drivers/staging/iio/adc/ad7476.h b/drivers/staging/iio/adc/ad7476.h
index b51b49e4abd6..f917e9c3d54f 100644
--- a/drivers/staging/iio/adc/ad7476.h
+++ b/drivers/staging/iio/adc/ad7476.h
@@ -33,6 +33,7 @@ struct ad7476_state {
struct regulator *reg;
struct work_struct poll_work;
atomic_t protect_ring;
+ size_t d_size;
u16 int_vref_mv;
struct spi_transfer xfer;
struct spi_message msg;
diff --git a/drivers/staging/iio/adc/ad7476_core.c b/drivers/staging/iio/adc/ad7476_core.c
index b8b54da67c63..d263904b3d1d 100644
--- a/drivers/staging/iio/adc/ad7476_core.c
+++ b/drivers/staging/iio/adc/ad7476_core.c
@@ -190,7 +190,7 @@ static int __devinit ad7476_probe(struct spi_device *spi)
goto error_disable_reg;
}
- /* Estabilish that the iio_dev is a child of the i2c device */
+ /* Establish that the iio_dev is a child of the spi device */
st->indio_dev->dev.parent = &spi->dev;
st->indio_dev->attrs = &ad7476_attribute_group;
st->indio_dev->dev_data = (void *)(st);
diff --git a/drivers/staging/iio/adc/ad7476_ring.c b/drivers/staging/iio/adc/ad7476_ring.c
index 85de14274ad7..1d654c86099d 100644
--- a/drivers/staging/iio/adc/ad7476_ring.c
+++ b/drivers/staging/iio/adc/ad7476_ring.c
@@ -26,6 +26,8 @@
#include "ad7476.h"
static IIO_SCAN_EL_C(in0, 0, 0, NULL);
+static IIO_SCAN_EL_TIMESTAMP(1);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(timestamp, s, 64, 64);
static ssize_t ad7476_show_type(struct device *dev,
struct device_attribute *attr,
@@ -44,6 +46,9 @@ static IIO_DEVICE_ATTR(in_type, S_IRUGO, ad7476_show_type, NULL, 0);
static struct attribute *ad7476_scan_el_attrs[] = {
&iio_scan_el_in0.dev_attr.attr,
&iio_const_attr_in0_index.dev_attr.attr,
+ &iio_const_attr_timestamp_index.dev_attr.attr,
+ &iio_scan_el_timestamp.dev_attr.attr,
+ &iio_const_attr_timestamp_type.dev_attr.attr,
&iio_dev_attr_in_type.dev_attr.attr,
NULL,
};
@@ -86,16 +91,21 @@ error_ret:
static int ad7476_ring_preenable(struct iio_dev *indio_dev)
{
struct ad7476_state *st = indio_dev->dev_data;
- size_t d_size;
+ struct iio_ring_buffer *ring = indio_dev->ring;
- if (indio_dev->ring->access.set_bytes_per_datum) {
- d_size = st->chip_info->storagebits / 8 + 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);
+ st->d_size = ring->scan_count * st->chip_info->storagebits / 8;
+
+ if (ring->scan_timestamp) {
+ st->d_size += sizeof(s64);
+
+ if (st->d_size % sizeof(s64))
+ st->d_size += sizeof(s64) - (st->d_size % sizeof(s64));
}
+ if (indio_dev->ring->access.set_bytes_per_datum)
+ indio_dev->ring->access.set_bytes_per_datum(indio_dev->ring,
+ st->d_size);
+
return 0;
}
@@ -131,18 +141,12 @@ static void ad7476_poll_bh_to_ring(struct work_struct *work_s)
s64 time_ns;
__u8 *rxbuf;
int b_sent;
- size_t d_size;
-
- /* Ensure the timestamp is 8 byte aligned */
- d_size = st->chip_info->storagebits / 8 + 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;
- rxbuf = kzalloc(d_size, GFP_KERNEL);
+ rxbuf = kzalloc(st->d_size, GFP_KERNEL);
if (rxbuf == NULL)
return;
@@ -152,7 +156,9 @@ static void ad7476_poll_bh_to_ring(struct work_struct *work_s)
time_ns = iio_get_time_ns();
- memcpy(rxbuf + d_size - sizeof(s64), &time_ns, sizeof(time_ns));
+ if (indio_dev->ring->scan_timestamp)
+ memcpy(rxbuf + st->d_size - sizeof(s64),
+ &time_ns, sizeof(time_ns));
indio_dev->ring->access.store_to(&sw_ring->buf, rxbuf, time_ns);
done:
@@ -182,6 +188,7 @@ int ad7476_register_ring_funcs_and_init(struct iio_dev *indio_dev)
indio_dev->ring->postenable = &iio_triggered_ring_postenable;
indio_dev->ring->predisable = &iio_triggered_ring_predisable;
indio_dev->ring->scan_el_attrs = &ad7476_scan_el_group;
+ indio_dev->ring->scan_timestamp = true;
INIT_WORK(&st->poll_work, &ad7476_poll_bh_to_ring);
diff --git a/drivers/staging/iio/adc/ad7606.h b/drivers/staging/iio/adc/ad7606.h
new file mode 100644
index 000000000000..338bade801a7
--- /dev/null
+++ b/drivers/staging/iio/adc/ad7606.h
@@ -0,0 +1,117 @@
+/*
+ * AD7606 ADC driver
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef IIO_ADC_AD7606_H_
+#define IIO_ADC_AD7606_H_
+
+/*
+ * TODO: struct ad7606_platform_data needs to go into include/linux/iio
+ */
+
+/**
+ * struct ad7606_platform_data - platform/board specifc information
+ * @default_os: default oversampling value {0, 2, 4, 8, 16, 32, 64}
+ * @default_range: default range +/-{5000, 10000} mVolt
+ * @gpio_convst: number of gpio connected to the CONVST pin
+ * @gpio_reset: gpio connected to the RESET pin, if not used set to -1
+ * @gpio_range: gpio connected to the RANGE pin, if not used set to -1
+ * @gpio_os0: gpio connected to the OS0 pin, if not used set to -1
+ * @gpio_os1: gpio connected to the OS1 pin, if not used set to -1
+ * @gpio_os2: gpio connected to the OS2 pin, if not used set to -1
+ * @gpio_frstdata: gpio connected to the FRSTDAT pin, if not used set to -1
+ * @gpio_stby: gpio connected to the STBY pin, if not used set to -1
+ */
+
+struct ad7606_platform_data {
+ unsigned default_os;
+ unsigned default_range;
+ unsigned gpio_convst;
+ unsigned gpio_reset;
+ unsigned gpio_range;
+ unsigned gpio_os0;
+ unsigned gpio_os1;
+ unsigned gpio_os2;
+ unsigned gpio_frstdata;
+ unsigned gpio_stby;
+};
+
+/**
+ * struct ad7606_chip_info - chip specifc information
+ * @name: indentification string for chip
+ * @bits: accuracy of the adc in bits
+ * @bits: output coding [s]igned or [u]nsigned
+ * @int_vref_mv: the internal reference voltage
+ * @num_channels: number of physical inputs on chip
+ */
+
+struct ad7606_chip_info {
+ char name[10];
+ u8 bits;
+ char sign;
+ u16 int_vref_mv;
+ unsigned num_channels;
+};
+
+/**
+ * struct ad7606_state - driver instance specific data
+ */
+
+struct ad7606_state {
+ struct iio_dev *indio_dev;
+ struct device *dev;
+ const struct ad7606_chip_info *chip_info;
+ struct ad7606_platform_data *pdata;
+ struct regulator *reg;
+ struct work_struct poll_work;
+ wait_queue_head_t wq_data_avail;
+ atomic_t protect_ring;
+ size_t d_size;
+ const struct ad7606_bus_ops *bops;
+ int irq;
+ unsigned id;
+ unsigned range;
+ unsigned oversampling;
+ bool done;
+ bool have_frstdata;
+ bool have_os;
+ bool have_stby;
+ bool have_reset;
+ bool have_range;
+ void __iomem *base_address;
+
+ /*
+ * DMA (thus cache coherency maintenance) requires the
+ * transfer buffers to live in their own cache lines.
+ */
+
+ unsigned short data[8] ____cacheline_aligned;
+};
+
+struct ad7606_bus_ops {
+ /* more methods added in future? */
+ int (*read_block)(struct device *, int, void *);
+};
+
+void ad7606_suspend(struct ad7606_state *st);
+void ad7606_resume(struct ad7606_state *st);
+struct ad7606_state *ad7606_probe(struct device *dev, int irq,
+ void __iomem *base_address, unsigned id,
+ const struct ad7606_bus_ops *bops);
+int ad7606_remove(struct ad7606_state *st);
+int ad7606_reset(struct ad7606_state *st);
+
+enum ad7606_supported_device_ids {
+ ID_AD7606_8,
+ ID_AD7606_6,
+ ID_AD7606_4
+};
+
+int ad7606_scan_from_ring(struct ad7606_state *st, unsigned ch);
+int ad7606_register_ring_funcs_and_init(struct iio_dev *indio_dev);
+void ad7606_ring_cleanup(struct iio_dev *indio_dev);
+#endif /* IIO_ADC_AD7606_H_ */
diff --git a/drivers/staging/iio/adc/ad7606_core.c b/drivers/staging/iio/adc/ad7606_core.c
new file mode 100644
index 000000000000..4c700f07fb83
--- /dev/null
+++ b/drivers/staging/iio/adc/ad7606_core.c
@@ -0,0 +1,556 @@
+/*
+ * AD7606 SPI ADC driver
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/regulator/consumer.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "../ring_generic.h"
+#include "adc.h"
+
+#include "ad7606.h"
+
+int ad7606_reset(struct ad7606_state *st)
+{
+ if (st->have_reset) {
+ gpio_set_value(st->pdata->gpio_reset, 1);
+ ndelay(100); /* t_reset >= 100ns */
+ gpio_set_value(st->pdata->gpio_reset, 0);
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
+static int ad7606_scan_direct(struct ad7606_state *st, unsigned ch)
+{
+ int ret;
+
+ st->done = false;
+ gpio_set_value(st->pdata->gpio_convst, 1);
+
+ ret = wait_event_interruptible(st->wq_data_avail, st->done);
+ if (ret)
+ goto error_ret;
+
+ if (st->have_frstdata) {
+ ret = st->bops->read_block(st->dev, 1, st->data);
+ if (ret)
+ goto error_ret;
+ if (!gpio_get_value(st->pdata->gpio_frstdata)) {
+ /* This should never happen */
+ ad7606_reset(st);
+ ret = -EIO;
+ goto error_ret;
+ }
+ ret = st->bops->read_block(st->dev,
+ st->chip_info->num_channels - 1, &st->data[1]);
+ if (ret)
+ goto error_ret;
+ } else {
+ ret = st->bops->read_block(st->dev,
+ st->chip_info->num_channels, st->data);
+ if (ret)
+ goto error_ret;
+ }
+
+ ret = st->data[ch];
+
+error_ret:
+ gpio_set_value(st->pdata->gpio_convst, 0);
+
+ return ret;
+}
+
+static ssize_t ad7606_scan(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7606_state *st = dev_info->dev_data;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ int ret;
+
+ mutex_lock(&dev_info->mlock);
+ if (iio_ring_enabled(dev_info))
+ ret = ad7606_scan_from_ring(st, this_attr->address);
+ else
+ ret = ad7606_scan_direct(st, this_attr->address);
+ mutex_unlock(&dev_info->mlock);
+
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%d\n", (short) ret);
+}
+
+static IIO_DEV_ATTR_IN_RAW(0, ad7606_scan, 0);
+static IIO_DEV_ATTR_IN_RAW(1, ad7606_scan, 1);
+static IIO_DEV_ATTR_IN_RAW(2, ad7606_scan, 2);
+static IIO_DEV_ATTR_IN_RAW(3, ad7606_scan, 3);
+static IIO_DEV_ATTR_IN_RAW(4, ad7606_scan, 4);
+static IIO_DEV_ATTR_IN_RAW(5, ad7606_scan, 5);
+static IIO_DEV_ATTR_IN_RAW(6, ad7606_scan, 6);
+static IIO_DEV_ATTR_IN_RAW(7, ad7606_scan, 7);
+
+static ssize_t ad7606_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 ad7606_state *st = iio_dev_get_devdata(dev_info);
+ unsigned int scale_uv = (st->range * 1000 * 2) >> st->chip_info->bits;
+
+ return sprintf(buf, "%d.%03d\n", scale_uv / 1000, scale_uv % 1000);
+}
+static IIO_DEVICE_ATTR(in_scale, S_IRUGO, ad7606_show_scale, NULL, 0);
+
+static ssize_t ad7606_show_name(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7606_state *st = iio_dev_get_devdata(dev_info);
+
+ return sprintf(buf, "%s\n", st->chip_info->name);
+}
+
+static IIO_DEVICE_ATTR(name, S_IRUGO, ad7606_show_name, NULL, 0);
+
+static ssize_t ad7606_show_range(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7606_state *st = iio_dev_get_devdata(dev_info);
+
+ return sprintf(buf, "%u\n", st->range);
+}
+
+static ssize_t ad7606_store_range(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7606_state *st = iio_dev_get_devdata(dev_info);
+ unsigned long lval;
+
+ if (strict_strtoul(buf, 10, &lval))
+ return -EINVAL;
+ if (!(lval == 5000 || lval == 10000)) {
+ dev_err(dev, "range is not supported\n");
+ return -EINVAL;
+ }
+ mutex_lock(&dev_info->mlock);
+ gpio_set_value(st->pdata->gpio_range, lval == 10000);
+ st->range = lval;
+ mutex_unlock(&dev_info->mlock);
+
+ return count;
+}
+
+static IIO_DEVICE_ATTR(range, S_IRUGO | S_IWUSR, \
+ ad7606_show_range, ad7606_store_range, 0);
+static IIO_CONST_ATTR(range_available, "5000 10000");
+
+static ssize_t ad7606_show_oversampling_ratio(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7606_state *st = iio_dev_get_devdata(dev_info);
+
+ return sprintf(buf, "%u\n", st->oversampling);
+}
+
+static int ad7606_oversampling_get_index(unsigned val)
+{
+ unsigned char supported[] = {0, 2, 4, 8, 16, 32, 64};
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(supported); i++)
+ if (val == supported[i])
+ return i;
+
+ return -EINVAL;
+}
+
+static ssize_t ad7606_store_oversampling_ratio(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7606_state *st = iio_dev_get_devdata(dev_info);
+ unsigned long lval;
+ int ret;
+
+ if (strict_strtoul(buf, 10, &lval))
+ return -EINVAL;
+
+ ret = ad7606_oversampling_get_index(lval);
+ if (ret < 0) {
+ dev_err(dev, "oversampling %lu is not supported\n", lval);
+ return ret;
+ }
+
+ mutex_lock(&dev_info->mlock);
+ gpio_set_value(st->pdata->gpio_os0, (ret >> 0) & 1);
+ gpio_set_value(st->pdata->gpio_os1, (ret >> 1) & 1);
+ gpio_set_value(st->pdata->gpio_os1, (ret >> 2) & 1);
+ st->oversampling = lval;
+ mutex_unlock(&dev_info->mlock);
+
+ return count;
+}
+
+static IIO_DEVICE_ATTR(oversampling_ratio, S_IRUGO | S_IWUSR,
+ ad7606_show_oversampling_ratio,
+ ad7606_store_oversampling_ratio, 0);
+static IIO_CONST_ATTR(oversampling_ratio_available, "0 2 4 8 16 32 64");
+
+static struct attribute *ad7606_attributes[] = {
+ &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_in_scale.dev_attr.attr,
+ &iio_dev_attr_name.dev_attr.attr,
+ &iio_dev_attr_range.dev_attr.attr,
+ &iio_const_attr_range_available.dev_attr.attr,
+ &iio_dev_attr_oversampling_ratio.dev_attr.attr,
+ &iio_const_attr_oversampling_ratio_available.dev_attr.attr,
+ NULL,
+};
+
+static mode_t ad7606_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr, int n)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad7606_state *st = iio_dev_get_devdata(dev_info);
+
+ mode_t mode = attr->mode;
+
+ if (st->chip_info->num_channels <= 6 &&
+ (attr == &iio_dev_attr_in7_raw.dev_attr.attr ||
+ attr == &iio_dev_attr_in6_raw.dev_attr.attr))
+ mode = 0;
+ else if (st->chip_info->num_channels <= 4 &&
+ (attr == &iio_dev_attr_in5_raw.dev_attr.attr ||
+ attr == &iio_dev_attr_in4_raw.dev_attr.attr))
+ mode = 0;
+ else if (!st->have_os &&
+ (attr == &iio_dev_attr_oversampling_ratio.dev_attr.attr ||
+ attr ==
+ &iio_const_attr_oversampling_ratio_available.dev_attr.attr))
+ mode = 0;
+ else if (!st->have_range &&
+ (attr == &iio_dev_attr_range.dev_attr.attr ||
+ attr == &iio_const_attr_range_available.dev_attr.attr))
+ mode = 0;
+
+ return mode;
+}
+
+static const struct attribute_group ad7606_attribute_group = {
+ .attrs = ad7606_attributes,
+ .is_visible = ad7606_attr_is_visible,
+};
+
+static const struct ad7606_chip_info ad7606_chip_info_tbl[] = {
+ /*
+ * More devices added in future
+ */
+ [ID_AD7606_8] = {
+ .name = "ad7606",
+ .bits = 16,
+ .sign = IIO_SCAN_EL_TYPE_SIGNED,
+ .int_vref_mv = 2500,
+ .num_channels = 8,
+ },
+ [ID_AD7606_6] = {
+ .name = "ad7606-6",
+ .bits = 16,
+ .sign = IIO_SCAN_EL_TYPE_SIGNED,
+ .int_vref_mv = 2500,
+ .num_channels = 6,
+ },
+ [ID_AD7606_4] = {
+ .name = "ad7606-4",
+ .bits = 16,
+ .sign = IIO_SCAN_EL_TYPE_SIGNED,
+ .int_vref_mv = 2500,
+ .num_channels = 4,
+ },
+};
+
+static int ad7606_request_gpios(struct ad7606_state *st)
+{
+ struct gpio gpio_array[3] = {
+ [0] = {
+ .gpio = st->pdata->gpio_os0,
+ .flags = GPIOF_DIR_OUT | ((st->oversampling & 1) ?
+ GPIOF_INIT_HIGH : GPIOF_INIT_LOW),
+ .label = "AD7606_OS0",
+ },
+ [1] = {
+ .gpio = st->pdata->gpio_os1,
+ .flags = GPIOF_DIR_OUT | ((st->oversampling & 2) ?
+ GPIOF_INIT_HIGH : GPIOF_INIT_LOW),
+ .label = "AD7606_OS1",
+ },
+ [2] = {
+ .gpio = st->pdata->gpio_os2,
+ .flags = GPIOF_DIR_OUT | ((st->oversampling & 4) ?
+ GPIOF_INIT_HIGH : GPIOF_INIT_LOW),
+ .label = "AD7606_OS2",
+ },
+ };
+ int ret;
+
+ ret = gpio_request_one(st->pdata->gpio_convst, GPIOF_OUT_INIT_LOW,
+ "AD7606_CONVST");
+ if (ret) {
+ dev_err(st->dev, "failed to request GPIO CONVST\n");
+ return ret;
+ }
+
+ ret = gpio_request_array(gpio_array, ARRAY_SIZE(gpio_array));
+ if (!ret) {
+ st->have_os = true;
+ }
+
+ ret = gpio_request_one(st->pdata->gpio_reset, GPIOF_OUT_INIT_LOW,
+ "AD7606_RESET");
+ if (!ret)
+ st->have_reset = true;
+
+ ret = gpio_request_one(st->pdata->gpio_range, GPIOF_DIR_OUT |
+ ((st->range == 10000) ? GPIOF_INIT_HIGH :
+ GPIOF_INIT_LOW), "AD7606_RANGE");
+ if (!ret)
+ st->have_range = true;
+
+ ret = gpio_request_one(st->pdata->gpio_stby, GPIOF_OUT_INIT_HIGH,
+ "AD7606_STBY");
+ if (!ret)
+ st->have_stby = true;
+
+ if (gpio_is_valid(st->pdata->gpio_frstdata)) {
+ ret = gpio_request_one(st->pdata->gpio_frstdata, GPIOF_IN,
+ "AD7606_FRSTDATA");
+ if (!ret)
+ st->have_frstdata = true;
+ }
+
+ return 0;
+}
+
+static void ad7606_free_gpios(struct ad7606_state *st)
+{
+ if (st->have_range)
+ gpio_free(st->pdata->gpio_range);
+
+ if (st->have_stby)
+ gpio_free(st->pdata->gpio_stby);
+
+ if (st->have_os) {
+ gpio_free(st->pdata->gpio_os0);
+ gpio_free(st->pdata->gpio_os1);
+ gpio_free(st->pdata->gpio_os2);
+ }
+
+ if (st->have_reset)
+ gpio_free(st->pdata->gpio_reset);
+
+ if (st->have_frstdata)
+ gpio_free(st->pdata->gpio_frstdata);
+
+ gpio_free(st->pdata->gpio_convst);
+}
+
+/**
+ * Interrupt handler
+ */
+static irqreturn_t ad7606_interrupt(int irq, void *dev_id)
+{
+ struct ad7606_state *st = dev_id;
+
+ if (iio_ring_enabled(st->indio_dev)) {
+ if (!work_pending(&st->poll_work))
+ schedule_work(&st->poll_work);
+ } else {
+ st->done = true;
+ wake_up_interruptible(&st->wq_data_avail);
+ }
+
+ return IRQ_HANDLED;
+};
+
+struct ad7606_state *ad7606_probe(struct device *dev, int irq,
+ void __iomem *base_address,
+ unsigned id,
+ const struct ad7606_bus_ops *bops)
+{
+ struct ad7606_platform_data *pdata = dev->platform_data;
+ struct ad7606_state *st;
+ int ret;
+
+ st = kzalloc(sizeof(*st), GFP_KERNEL);
+ if (st == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+
+ st->dev = dev;
+ st->id = id;
+ st->irq = irq;
+ st->bops = bops;
+ st->base_address = base_address;
+ st->range = pdata->default_range == 10000 ? 10000 : 5000;
+
+ ret = ad7606_oversampling_get_index(pdata->default_os);
+ if (ret < 0) {
+ dev_warn(dev, "oversampling %d is not supported\n",
+ pdata->default_os);
+ st->oversampling = 0;
+ } else {
+ st->oversampling = pdata->default_os;
+ }
+
+ st->reg = regulator_get(dev, "vcc");
+ if (!IS_ERR(st->reg)) {
+ ret = regulator_enable(st->reg);
+ if (ret)
+ goto error_put_reg;
+ }
+
+ st->pdata = pdata;
+ st->chip_info = &ad7606_chip_info_tbl[id];
+
+ atomic_set(&st->protect_ring, 0);
+
+ st->indio_dev = iio_allocate_device();
+ if (st->indio_dev == NULL) {
+ ret = -ENOMEM;
+ goto error_disable_reg;
+ }
+
+ st->indio_dev->dev.parent = dev;
+ st->indio_dev->attrs = &ad7606_attribute_group;
+ st->indio_dev->dev_data = (void *)(st);
+ st->indio_dev->driver_module = THIS_MODULE;
+ st->indio_dev->modes = INDIO_DIRECT_MODE;
+
+ init_waitqueue_head(&st->wq_data_avail);
+
+ ret = ad7606_request_gpios(st);
+ if (ret)
+ goto error_free_device;
+
+ ret = ad7606_reset(st);
+ if (ret)
+ dev_warn(st->dev, "failed to RESET: no RESET GPIO specified\n");
+
+ ret = request_irq(st->irq, ad7606_interrupt,
+ IRQF_TRIGGER_FALLING, st->chip_info->name, st);
+ if (ret)
+ goto error_free_gpios;
+
+ ret = ad7606_register_ring_funcs_and_init(st->indio_dev);
+ if (ret)
+ goto error_free_irq;
+
+ ret = iio_device_register(st->indio_dev);
+ if (ret)
+ goto error_free_irq;
+
+ ret = iio_ring_buffer_register(st->indio_dev->ring, 0);
+ if (ret)
+ goto error_cleanup_ring;
+
+ return st;
+
+error_cleanup_ring:
+ ad7606_ring_cleanup(st->indio_dev);
+ iio_device_unregister(st->indio_dev);
+
+error_free_irq:
+ free_irq(st->irq, st);
+
+error_free_gpios:
+ ad7606_free_gpios(st);
+
+error_free_device:
+ iio_free_device(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 ERR_PTR(ret);
+}
+
+int ad7606_remove(struct ad7606_state *st)
+{
+ struct iio_dev *indio_dev = st->indio_dev;
+ iio_ring_buffer_unregister(indio_dev->ring);
+ ad7606_ring_cleanup(indio_dev);
+ iio_device_unregister(indio_dev);
+ free_irq(st->irq, st);
+ if (!IS_ERR(st->reg)) {
+ regulator_disable(st->reg);
+ regulator_put(st->reg);
+ }
+
+ ad7606_free_gpios(st);
+
+ kfree(st);
+ return 0;
+}
+
+void ad7606_suspend(struct ad7606_state *st)
+{
+ if (st->have_stby) {
+ if (st->have_range)
+ gpio_set_value(st->pdata->gpio_range, 1);
+ gpio_set_value(st->pdata->gpio_stby, 0);
+ }
+}
+
+void ad7606_resume(struct ad7606_state *st)
+{
+ if (st->have_stby) {
+ if (st->have_range)
+ gpio_set_value(st->pdata->gpio_range,
+ st->range == 10000);
+
+ gpio_set_value(st->pdata->gpio_stby, 1);
+ ad7606_reset(st);
+ }
+}
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Analog Devices AD7606 ADC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/adc/ad7606_par.c b/drivers/staging/iio/adc/ad7606_par.c
new file mode 100644
index 000000000000..43a554ce753d
--- /dev/null
+++ b/drivers/staging/iio/adc/ad7606_par.c
@@ -0,0 +1,188 @@
+/*
+ * AD7606 Parallel Interface ADC driver
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+#include "ad7606.h"
+
+static int ad7606_par16_read_block(struct device *dev,
+ int count, void *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ad7606_state *st = platform_get_drvdata(pdev);
+
+ insw((unsigned long) st->base_address, buf, count);
+
+ return 0;
+}
+
+static const struct ad7606_bus_ops ad7606_par16_bops = {
+ .read_block = ad7606_par16_read_block,
+};
+
+static int ad7606_par8_read_block(struct device *dev,
+ int count, void *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ad7606_state *st = platform_get_drvdata(pdev);
+
+ insb((unsigned long) st->base_address, buf, count * 2);
+
+ return 0;
+}
+
+static const struct ad7606_bus_ops ad7606_par8_bops = {
+ .read_block = ad7606_par8_read_block,
+};
+
+static int __devinit ad7606_par_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct ad7606_state *st;
+ void __iomem *addr;
+ resource_size_t remap_size;
+ int ret, irq;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "no irq\n");
+ return -ENODEV;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ remap_size = resource_size(res);
+
+ /* Request the regions */
+ if (!request_mem_region(res->start, remap_size, "iio-ad7606")) {
+ ret = -EBUSY;
+ goto out1;
+ }
+ addr = ioremap(res->start, remap_size);
+ if (!addr) {
+ ret = -ENOMEM;
+ goto out1;
+ }
+
+ st = ad7606_probe(&pdev->dev, irq, addr,
+ platform_get_device_id(pdev)->driver_data,
+ remap_size > 1 ? &ad7606_par16_bops :
+ &ad7606_par8_bops);
+
+ if (IS_ERR(st)) {
+ ret = PTR_ERR(st);
+ goto out2;
+ }
+
+ platform_set_drvdata(pdev, st);
+
+ return 0;
+
+out2:
+ iounmap(addr);
+out1:
+ release_mem_region(res->start, remap_size);
+
+ return ret;
+}
+
+static int __devexit ad7606_par_remove(struct platform_device *pdev)
+{
+ struct ad7606_state *st = platform_get_drvdata(pdev);
+ struct resource *res;
+
+ ad7606_remove(st);
+
+ iounmap(st->base_address);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(res->start, resource_size(res));
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int ad7606_par_suspend(struct device *dev)
+{
+ struct ad7606_state *st = dev_get_drvdata(dev);
+
+ ad7606_suspend(st);
+
+ return 0;
+}
+
+static int ad7606_par_resume(struct device *dev)
+{
+ struct ad7606_state *st = dev_get_drvdata(dev);
+
+ ad7606_resume(st);
+
+ return 0;
+}
+
+static const struct dev_pm_ops ad7606_pm_ops = {
+ .suspend = ad7606_par_suspend,
+ .resume = ad7606_par_resume,
+};
+#define AD7606_PAR_PM_OPS (&ad7606_pm_ops)
+
+#else
+#define AD7606_PAR_PM_OPS NULL
+#endif /* CONFIG_PM */
+
+static struct platform_device_id ad7606_driver_ids[] = {
+ {
+ .name = "ad7606-8",
+ .driver_data = ID_AD7606_8,
+ }, {
+ .name = "ad7606-6",
+ .driver_data = ID_AD7606_6,
+ }, {
+ .name = "ad7606-4",
+ .driver_data = ID_AD7606_4,
+ },
+ { }
+};
+
+MODULE_DEVICE_TABLE(platform, ad7606_driver_ids);
+
+static struct platform_driver ad7606_driver = {
+ .probe = ad7606_par_probe,
+ .remove = __devexit_p(ad7606_par_remove),
+ .id_table = ad7606_driver_ids,
+ .driver = {
+ .name = "ad7606",
+ .owner = THIS_MODULE,
+ .pm = AD7606_PAR_PM_OPS,
+ },
+};
+
+static int __init ad7606_init(void)
+{
+ return platform_driver_register(&ad7606_driver);
+}
+
+static void __exit ad7606_cleanup(void)
+{
+ platform_driver_unregister(&ad7606_driver);
+}
+
+module_init(ad7606_init);
+module_exit(ad7606_cleanup);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Analog Devices AD7606 ADC");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:ad7606_par");
diff --git a/drivers/staging/iio/adc/ad7606_ring.c b/drivers/staging/iio/adc/ad7606_ring.c
new file mode 100644
index 000000000000..b32cb0dea6d8
--- /dev/null
+++ b/drivers/staging/iio/adc/ad7606_ring.c
@@ -0,0 +1,280 @@
+/*
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ *
+ */
+
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+
+#include "../iio.h"
+#include "../ring_generic.h"
+#include "../ring_sw.h"
+#include "../trigger.h"
+#include "../sysfs.h"
+
+#include "ad7606.h"
+
+static IIO_SCAN_EL_C(in0, 0, 0, NULL);
+static IIO_SCAN_EL_C(in1, 1, 0, NULL);
+static IIO_SCAN_EL_C(in2, 2, 0, NULL);
+static IIO_SCAN_EL_C(in3, 3, 0, NULL);
+static IIO_SCAN_EL_C(in4, 4, 0, NULL);
+static IIO_SCAN_EL_C(in5, 5, 0, NULL);
+static IIO_SCAN_EL_C(in6, 6, 0, NULL);
+static IIO_SCAN_EL_C(in7, 7, 0, NULL);
+
+static IIO_SCAN_EL_TIMESTAMP(8);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(timestamp, s, 64, 64);
+
+static ssize_t ad7606_show_type(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_ring_buffer *ring = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = ring->indio_dev;
+ struct ad7606_state *st = indio_dev->dev_data;
+
+ return sprintf(buf, "%c%d/%d\n", st->chip_info->sign,
+ st->chip_info->bits, st->chip_info->bits);
+}
+static IIO_DEVICE_ATTR(in_type, S_IRUGO, ad7606_show_type, NULL, 0);
+
+static struct attribute *ad7606_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_const_attr_timestamp_index.dev_attr.attr,
+ &iio_scan_el_timestamp.dev_attr.attr,
+ &iio_const_attr_timestamp_type.dev_attr.attr,
+ &iio_dev_attr_in_type.dev_attr.attr,
+ NULL,
+};
+
+static mode_t ad7606_scan_el_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr, int n)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct iio_ring_buffer *ring = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = ring->indio_dev;
+ struct ad7606_state *st = indio_dev->dev_data;
+
+ mode_t mode = attr->mode;
+
+ if (st->chip_info->num_channels <= 6 &&
+ (attr == &iio_scan_el_in7.dev_attr.attr ||
+ attr == &iio_const_attr_in7_index.dev_attr.attr ||
+ attr == &iio_scan_el_in6.dev_attr.attr ||
+ attr == &iio_const_attr_in6_index.dev_attr.attr))
+ mode = 0;
+ else if (st->chip_info->num_channels <= 4 &&
+ (attr == &iio_scan_el_in5.dev_attr.attr ||
+ attr == &iio_const_attr_in5_index.dev_attr.attr ||
+ attr == &iio_scan_el_in4.dev_attr.attr ||
+ attr == &iio_const_attr_in4_index.dev_attr.attr))
+ mode = 0;
+
+ return mode;
+}
+
+static struct attribute_group ad7606_scan_el_group = {
+ .name = "scan_elements",
+ .attrs = ad7606_scan_el_attrs,
+ .is_visible = ad7606_scan_el_attr_is_visible,
+};
+
+int ad7606_scan_from_ring(struct ad7606_state *st, unsigned ch)
+{
+ struct iio_ring_buffer *ring = st->indio_dev->ring;
+ int ret;
+ u16 *ring_data;
+
+ ring_data = kmalloc(ring->access.get_bytes_per_datum(ring), GFP_KERNEL);
+ if (ring_data == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+ ret = ring->access.read_last(ring, (u8 *) ring_data);
+ if (ret)
+ goto error_free_ring_data;
+
+ ret = ring_data[ch];
+
+error_free_ring_data:
+ kfree(ring_data);
+error_ret:
+ return ret;
+}
+
+/**
+ * ad7606_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 ad7606_ring_preenable(struct iio_dev *indio_dev)
+{
+ struct ad7606_state *st = indio_dev->dev_data;
+ struct iio_ring_buffer *ring = indio_dev->ring;
+ size_t d_size;
+
+ d_size = st->chip_info->num_channels *
+ st->chip_info->bits / 8;
+
+ if (ring->scan_timestamp) {
+ d_size += sizeof(s64);
+
+ if (d_size % sizeof(s64))
+ d_size += sizeof(s64) - (d_size % sizeof(s64));
+ }
+
+ if (ring->access.set_bytes_per_datum)
+ ring->access.set_bytes_per_datum(ring, d_size);
+
+ st->d_size = d_size;
+
+ return 0;
+}
+
+/**
+ * ad7606_poll_func_th() th of trigger launched polling to ring buffer
+ *
+ **/
+static void ad7606_poll_func_th(struct iio_dev *indio_dev, s64 time)
+{
+ struct ad7606_state *st = indio_dev->dev_data;
+ gpio_set_value(st->pdata->gpio_convst, 1);
+
+ return;
+}
+/**
+ * ad7606_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 ad7606_poll_bh_to_ring(struct work_struct *work_s)
+{
+ struct ad7606_state *st = container_of(work_s, struct ad7606_state,
+ poll_work);
+ struct iio_dev *indio_dev = st->indio_dev;
+ struct iio_sw_ring_buffer *sw_ring = iio_to_sw_ring(indio_dev->ring);
+ struct iio_ring_buffer *ring = indio_dev->ring;
+ s64 time_ns;
+ __u8 *buf;
+ int ret;
+
+ /* Ensure only one copy of this function running at a time */
+ if (atomic_inc_return(&st->protect_ring) > 1)
+ return;
+
+ buf = kzalloc(st->d_size, GFP_KERNEL);
+ if (buf == NULL)
+ return;
+
+ if (st->have_frstdata) {
+ ret = st->bops->read_block(st->dev, 1, buf);
+ if (ret)
+ goto done;
+ if (!gpio_get_value(st->pdata->gpio_frstdata)) {
+ /* This should never happen. However
+ * some signal glitch caused by bad PCB desgin or
+ * electrostatic discharge, could cause an extra read
+ * or clock. This allows recovery.
+ */
+ ad7606_reset(st);
+ goto done;
+ }
+ ret = st->bops->read_block(st->dev,
+ st->chip_info->num_channels - 1, buf + 2);
+ if (ret)
+ goto done;
+ } else {
+ ret = st->bops->read_block(st->dev,
+ st->chip_info->num_channels, buf);
+ if (ret)
+ goto done;
+ }
+
+ time_ns = iio_get_time_ns();
+
+ if (ring->scan_timestamp)
+ memcpy(buf + st->d_size - sizeof(s64),
+ &time_ns, sizeof(time_ns));
+
+ ring->access.store_to(&sw_ring->buf, buf, time_ns);
+done:
+ gpio_set_value(st->pdata->gpio_convst, 0);
+ kfree(buf);
+ atomic_dec(&st->protect_ring);
+}
+
+int ad7606_register_ring_funcs_and_init(struct iio_dev *indio_dev)
+{
+ struct ad7606_state *st = indio_dev->dev_data;
+ int ret;
+
+ 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(&indio_dev->ring->access);
+ ret = iio_alloc_pollfunc(indio_dev, NULL, &ad7606_poll_func_th);
+ if (ret)
+ goto error_deallocate_sw_rb;
+
+ /* Ring buffer functions - here trigger setup related */
+
+ indio_dev->ring->preenable = &ad7606_ring_preenable;
+ indio_dev->ring->postenable = &iio_triggered_ring_postenable;
+ indio_dev->ring->predisable = &iio_triggered_ring_predisable;
+ indio_dev->ring->scan_el_attrs = &ad7606_scan_el_group;
+ indio_dev->ring->scan_timestamp = true ;
+
+ INIT_WORK(&st->poll_work, &ad7606_poll_bh_to_ring);
+
+ /* 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 ad7606_ring_cleanup(struct iio_dev *indio_dev)
+{
+ 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);
+}
diff --git a/drivers/staging/iio/adc/ad7606_spi.c b/drivers/staging/iio/adc/ad7606_spi.c
new file mode 100644
index 000000000000..d738491222f2
--- /dev/null
+++ b/drivers/staging/iio/adc/ad7606_spi.c
@@ -0,0 +1,126 @@
+/*
+ * AD7606 SPI ADC driver
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/types.h>
+#include <linux/err.h>
+#include "ad7606.h"
+
+#define MAX_SPI_FREQ_HZ 23500000 /* VDRIVE above 4.75 V */
+
+static int ad7606_spi_read_block(struct device *dev,
+ int count, void *buf)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ int i, ret;
+ unsigned short *data = buf;
+
+ ret = spi_read(spi, (u8 *)buf, count * 2);
+ if (ret < 0) {
+ dev_err(&spi->dev, "SPI read error\n");
+ return ret;
+ }
+
+ for (i = 0; i < count; i++)
+ data[i] = be16_to_cpu(data[i]);
+
+ return 0;
+}
+
+static const struct ad7606_bus_ops ad7606_spi_bops = {
+ .read_block = ad7606_spi_read_block,
+};
+
+static int __devinit ad7606_spi_probe(struct spi_device *spi)
+{
+ struct ad7606_state *st;
+
+ st = ad7606_probe(&spi->dev, spi->irq, NULL,
+ spi_get_device_id(spi)->driver_data,
+ &ad7606_spi_bops);
+
+ if (IS_ERR(st))
+ return PTR_ERR(st);
+
+ spi_set_drvdata(spi, st);
+
+ return 0;
+}
+
+static int __devexit ad7606_spi_remove(struct spi_device *spi)
+{
+ struct ad7606_state *st = dev_get_drvdata(&spi->dev);
+
+ return ad7606_remove(st);
+}
+
+#ifdef CONFIG_PM
+static int ad7606_spi_suspend(struct device *dev)
+{
+ struct ad7606_state *st = dev_get_drvdata(dev);
+
+ ad7606_suspend(st);
+
+ return 0;
+}
+
+static int ad7606_spi_resume(struct device *dev)
+{
+ struct ad7606_state *st = dev_get_drvdata(dev);
+
+ ad7606_resume(st);
+
+ return 0;
+}
+
+static const struct dev_pm_ops ad7606_pm_ops = {
+ .suspend = ad7606_spi_suspend,
+ .resume = ad7606_spi_resume,
+};
+#define AD7606_SPI_PM_OPS (&ad7606_pm_ops)
+
+#else
+#define AD7606_SPI_PM_OPS NULL
+#endif
+
+static const struct spi_device_id ad7606_id[] = {
+ {"ad7606-8", ID_AD7606_8},
+ {"ad7606-6", ID_AD7606_6},
+ {"ad7606-4", ID_AD7606_4},
+ {}
+};
+
+static struct spi_driver ad7606_driver = {
+ .driver = {
+ .name = "ad7606",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ .pm = AD7606_SPI_PM_OPS,
+ },
+ .probe = ad7606_spi_probe,
+ .remove = __devexit_p(ad7606_spi_remove),
+ .id_table = ad7606_id,
+};
+
+static int __init ad7606_spi_init(void)
+{
+ return spi_register_driver(&ad7606_driver);
+}
+module_init(ad7606_spi_init);
+
+static void __exit ad7606_spi_exit(void)
+{
+ spi_unregister_driver(&ad7606_driver);
+}
+module_exit(ad7606_spi_exit);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Analog Devices AD7606 ADC");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("spi:ad7606_spi");
diff --git a/drivers/staging/iio/adc/ad7887.h b/drivers/staging/iio/adc/ad7887.h
index 8c2a218c9496..439c802b38f2 100644
--- a/drivers/staging/iio/adc/ad7887.h
+++ b/drivers/staging/iio/adc/ad7887.h
@@ -63,6 +63,7 @@ struct ad7887_state {
struct regulator *reg;
struct work_struct poll_work;
atomic_t protect_ring;
+ size_t d_size;
u16 int_vref_mv;
bool en_dual;
struct spi_transfer xfer[4];
diff --git a/drivers/staging/iio/adc/ad7887_ring.c b/drivers/staging/iio/adc/ad7887_ring.c
index 6b9cb1f95a1e..2d7fe65049dd 100644
--- a/drivers/staging/iio/adc/ad7887_ring.c
+++ b/drivers/staging/iio/adc/ad7887_ring.c
@@ -27,6 +27,8 @@
static IIO_SCAN_EL_C(in0, 0, 0, NULL);
static IIO_SCAN_EL_C(in1, 1, 0, NULL);
+static IIO_SCAN_EL_TIMESTAMP(2);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(timestamp, s, 64, 64);
static ssize_t ad7887_show_type(struct device *dev,
struct device_attribute *attr,
@@ -47,6 +49,9 @@ static struct attribute *ad7887_scan_el_attrs[] = {
&iio_const_attr_in0_index.dev_attr.attr,
&iio_scan_el_in1.dev_attr.attr,
&iio_const_attr_in1_index.dev_attr.attr,
+ &iio_const_attr_timestamp_index.dev_attr.attr,
+ &iio_scan_el_timestamp.dev_attr.attr,
+ &iio_const_attr_timestamp_type.dev_attr.attr,
&iio_dev_attr_in_type.dev_attr.attr,
NULL,
};
@@ -118,16 +123,20 @@ static int ad7887_ring_preenable(struct iio_dev *indio_dev)
{
struct ad7887_state *st = indio_dev->dev_data;
struct iio_ring_buffer *ring = indio_dev->ring;
- size_t d_size;
- if (indio_dev->ring->access.set_bytes_per_datum) {
- d_size = st->chip_info->storagebits / 8 + 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);
+ st->d_size = ring->scan_count * st->chip_info->storagebits / 8;
+
+ if (ring->scan_timestamp) {
+ st->d_size += sizeof(s64);
+
+ if (st->d_size % sizeof(s64))
+ st->d_size += sizeof(s64) - (st->d_size % sizeof(s64));
}
+ if (indio_dev->ring->access.set_bytes_per_datum)
+ indio_dev->ring->access.set_bytes_per_datum(indio_dev->ring,
+ st->d_size);
+
switch (ring->scan_mask) {
case (1 << 0):
st->ring_msg = &st->msg[AD7887_CH0];
@@ -186,20 +195,14 @@ static void ad7887_poll_bh_to_ring(struct work_struct *work_s)
s64 time_ns;
__u8 *buf;
int b_sent;
- size_t d_size;
unsigned int bytes = ring->scan_count * st->chip_info->storagebits / 8;
- /* Ensure the timestamp is 8 byte aligned */
- d_size = bytes + 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;
- buf = kzalloc(d_size, GFP_KERNEL);
+ buf = kzalloc(st->d_size, GFP_KERNEL);
if (buf == NULL)
return;
@@ -210,7 +213,9 @@ static void ad7887_poll_bh_to_ring(struct work_struct *work_s)
time_ns = iio_get_time_ns();
memcpy(buf, st->data, bytes);
- memcpy(buf + d_size - sizeof(s64), &time_ns, sizeof(time_ns));
+ if (ring->scan_timestamp)
+ memcpy(buf + st->d_size - sizeof(s64),
+ &time_ns, sizeof(time_ns));
indio_dev->ring->access.store_to(&sw_ring->buf, buf, time_ns);
done:
@@ -241,6 +246,7 @@ int ad7887_register_ring_funcs_and_init(struct iio_dev *indio_dev)
indio_dev->ring->predisable = &iio_triggered_ring_predisable;
indio_dev->ring->postdisable = &ad7887_ring_postdisable;
indio_dev->ring->scan_el_attrs = &ad7887_scan_el_group;
+ indio_dev->ring->scan_timestamp = true;
INIT_WORK(&st->poll_work, &ad7887_poll_bh_to_ring);
diff --git a/drivers/staging/iio/adc/ad799x.h b/drivers/staging/iio/adc/ad799x.h
index 81a20d524b77..a421362c77f9 100644
--- a/drivers/staging/iio/adc/ad799x.h
+++ b/drivers/staging/iio/adc/ad799x.h
@@ -116,6 +116,7 @@ struct ad799x_state {
struct work_struct poll_work;
struct work_struct work_thresh;
atomic_t protect_ring;
+ size_t d_size;
struct iio_trigger *trig;
struct regulator *reg;
s64 last_timestamp;
diff --git a/drivers/staging/iio/adc/ad799x_core.c b/drivers/staging/iio/adc/ad799x_core.c
index 89ccf375a188..e50841b3ac69 100644
--- a/drivers/staging/iio/adc/ad799x_core.c
+++ b/drivers/staging/iio/adc/ad799x_core.c
@@ -123,6 +123,9 @@ static AD799X_SCAN_EL(5);
static AD799X_SCAN_EL(6);
static AD799X_SCAN_EL(7);
+static IIO_SCAN_EL_TIMESTAMP(8);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(timestamp, s, 64, 64)
+
static ssize_t ad799x_show_type(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -471,6 +474,9 @@ static struct attribute *ad7991_5_9_3_4_scan_el_attrs[] = {
&iio_const_attr_in2_index.dev_attr.attr,
&iio_scan_el_in3.dev_attr.attr,
&iio_const_attr_in3_index.dev_attr.attr,
+ &iio_const_attr_timestamp_index.dev_attr.attr,
+ &iio_scan_el_timestamp.dev_attr.attr,
+ &iio_const_attr_timestamp_type.dev_attr.attr,
&iio_dev_attr_in_type.dev_attr.attr,
NULL,
};
@@ -497,6 +503,9 @@ static struct attribute *ad7992_scan_el_attrs[] = {
&iio_const_attr_in0_index.dev_attr.attr,
&iio_scan_el_in1.dev_attr.attr,
&iio_const_attr_in1_index.dev_attr.attr,
+ &iio_const_attr_timestamp_index.dev_attr.attr,
+ &iio_scan_el_timestamp.dev_attr.attr,
+ &iio_const_attr_timestamp_type.dev_attr.attr,
&iio_dev_attr_in_type.dev_attr.attr,
NULL,
};
@@ -541,6 +550,9 @@ static struct attribute *ad7997_8_scan_el_attrs[] = {
&iio_const_attr_in6_index.dev_attr.attr,
&iio_scan_el_in7.dev_attr.attr,
&iio_const_attr_in7_index.dev_attr.attr,
+ &iio_const_attr_timestamp_index.dev_attr.attr,
+ &iio_scan_el_timestamp.dev_attr.attr,
+ &iio_const_attr_timestamp_type.dev_attr.attr,
&iio_dev_attr_in_type.dev_attr.attr,
NULL,
};
diff --git a/drivers/staging/iio/adc/ad799x_ring.c b/drivers/staging/iio/adc/ad799x_ring.c
index 975cdcbf0830..56abc395f177 100644
--- a/drivers/staging/iio/adc/ad799x_ring.c
+++ b/drivers/staging/iio/adc/ad799x_ring.c
@@ -73,8 +73,6 @@ static int ad799x_ring_preenable(struct iio_dev *indio_dev)
{
struct iio_ring_buffer *ring = indio_dev->ring;
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
@@ -84,15 +82,19 @@ static int ad799x_ring_preenable(struct iio_dev *indio_dev)
if (st->id == ad7997 || st->id == ad7998)
ad799x_set_scan_mode(st, ring->scan_mask);
- numvals = ring->scan_count;
+ st->d_size = ring->scan_count * 2;
- if (ring->access.set_bytes_per_datum) {
- d_size = numvals*2 + sizeof(s64);
- if (d_size % 8)
- d_size += 8 - (d_size % 8);
- ring->access.set_bytes_per_datum(ring, d_size);
+ if (ring->scan_timestamp) {
+ st->d_size += sizeof(s64);
+
+ if (st->d_size % sizeof(s64))
+ st->d_size += sizeof(s64) - (st->d_size % sizeof(s64));
}
+ if (indio_dev->ring->access.set_bytes_per_datum)
+ indio_dev->ring->access.set_bytes_per_datum(indio_dev->ring,
+ st->d_size);
+
return 0;
}
@@ -130,29 +132,13 @@ static void ad799x_poll_bh_to_ring(struct work_struct *work_s)
s64 time_ns;
__u8 *rxbuf;
int b_sent;
- size_t d_size;
u8 cmd;
- unsigned long numvals = 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);
+ rxbuf = kmalloc(st->d_size, GFP_KERNEL);
if (rxbuf == NULL)
return;
@@ -177,13 +163,15 @@ static void ad799x_poll_bh_to_ring(struct work_struct *work_s)
}
b_sent = i2c_smbus_read_i2c_block_data(st->client,
- cmd, numvals*2, rxbuf);
+ cmd, ring->scan_count * 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));
+ if (ring->scan_timestamp)
+ memcpy(rxbuf + st->d_size - sizeof(s64),
+ &time_ns, sizeof(time_ns));
ring->access.store_to(&ring_sw->buf, rxbuf, time_ns);
done:
@@ -213,6 +201,7 @@ int ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev)
indio_dev->ring->preenable = &ad799x_ring_preenable;
indio_dev->ring->postenable = &iio_triggered_ring_postenable;
indio_dev->ring->predisable = &iio_triggered_ring_predisable;
+ indio_dev->ring->scan_timestamp = true;
INIT_WORK(&st->poll_work, &ad799x_poll_bh_to_ring);