aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iio
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-12-11 13:59:44 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2012-12-11 13:59:44 -0800
commit8966961b31c251b854169e9886394c2a20f2cea7 (patch)
tree248a625b23335acbd5ca4b55eb136fe0dc8ba0aa /drivers/iio
parentMerge tag 'char-misc-3.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc (diff)
parentMerge tag 'iio-for-3.8f' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next (diff)
downloadlinux-dev-8966961b31c251b854169e9886394c2a20f2cea7.tar.xz
linux-dev-8966961b31c251b854169e9886394c2a20f2cea7.zip
Merge tag 'staging-3.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging
Pull staging driver tree merge from Greg Kroah-Hartman: "Here's the big staging tree merge for 3.8-rc1 There's a lot of patches in here, the majority being the comedi rework/cleanup that has been ongoing and is causing a huge reduction in overall code size, which is amazing to watch. We also removed some older drivers (telephony and rts_pstor), and added a new one (fwserial which also came in through the tty tree due to tty api changes, take that one if you get merge conflicts.) The iio and ipack drivers are moving out of the staging area into their own part of the kernel as they have been cleaned up sufficiently and are working well. Overall, again a reduction of code: 768 files changed, 31887 insertions(+), 82166 deletions(-) All of this has been in the linux-next tree for a while. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>" * tag 'staging-3.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (1298 commits) iio: imu: adis16480: remove duplicated include from adis16480.c iio: gyro: adis16136: remove duplicated include from adis16136.c iio:imu: adis16480: show_firmware() buffer too small iio:gyro: adis16136: divide by zero in write_frequency() iio: adc: Add Texas Instruments ADC081C021/027 support iio:ad7793: Add support for the ad7796 and ad7797 iio:ad7793: Add support for the ad7798 and ad7799 staging:iio: Move ad7793 driver out of staging staging:iio:ad7793: Implement stricter id checking staging:iio:ad7793: Move register definitions from header to source staging:iio:ad7793: Rework regulator handling staging:iio:ad7793: Rework platform data staging:iio:ad7793: Use kstrtol instead of strict_strtol staging:iio:ad7793: Use usleep_range instead of msleep staging:iio:ad7793: Fix temperature scale staging:iio:ad7793: Fix VDD monitor scale staging: gdm72xx: unlock on error in init_usb() staging: panel: pass correct lengths to keypad_send_key() staging: comedi: addi_apci_2032: fix interrupt support staging: comedi: addi_apci_2032: move i_APCI2032_ConfigDigitalOutput() ...
Diffstat (limited to 'drivers/iio')
-rw-r--r--drivers/iio/Kconfig13
-rw-r--r--drivers/iio/Makefile8
-rw-r--r--drivers/iio/accel/Kconfig2
-rw-r--r--drivers/iio/accel/hid-sensor-accel-3d.c21
-rw-r--r--drivers/iio/adc/Kconfig65
-rw-r--r--drivers/iio/adc/Makefile6
-rw-r--r--drivers/iio/adc/ad7266.c3
-rw-r--r--drivers/iio/adc/ad7298.c408
-rw-r--r--drivers/iio/adc/ad7476.c2
-rw-r--r--drivers/iio/adc/ad7793.c876
-rw-r--r--drivers/iio/adc/ad7887.c378
-rw-r--r--drivers/iio/adc/ad_sigma_delta.c2
-rw-r--r--drivers/iio/adc/at91_adc.c6
-rw-r--r--drivers/iio/adc/max1363.c1700
-rw-r--r--drivers/iio/adc/ti-adc081c.c161
-rw-r--r--drivers/iio/buffer_cb.c113
-rw-r--r--drivers/iio/common/hid-sensors/Kconfig2
-rw-r--r--drivers/iio/common/hid-sensors/hid-sensor-trigger.c6
-rw-r--r--drivers/iio/dac/Kconfig12
-rw-r--r--drivers/iio/dac/Makefile1
-rw-r--r--drivers/iio/dac/ad5449.c376
-rw-r--r--drivers/iio/dac/ad5686.c2
-rw-r--r--drivers/iio/gyro/Kconfig9
-rw-r--r--drivers/iio/gyro/Makefile1
-rw-r--r--drivers/iio/gyro/adis16136.c580
-rw-r--r--drivers/iio/gyro/hid-sensor-gyro-3d.c21
-rw-r--r--drivers/iio/imu/Kconfig27
-rw-r--r--drivers/iio/imu/Makefile10
-rw-r--r--drivers/iio/imu/adis.c440
-rw-r--r--drivers/iio/imu/adis16480.c924
-rw-r--r--drivers/iio/imu/adis_buffer.c176
-rw-r--r--drivers/iio/imu/adis_trigger.c89
-rw-r--r--drivers/iio/industrialio-buffer.c386
-rw-r--r--drivers/iio/industrialio-core.c105
-rw-r--r--drivers/iio/industrialio-event.c11
-rw-r--r--drivers/iio/inkern.c6
-rw-r--r--drivers/iio/light/adjd_s311.c3
-rw-r--r--drivers/iio/light/hid-sensor-als.c20
-rw-r--r--drivers/iio/magnetometer/hid-sensor-magn-3d.c21
39 files changed, 6735 insertions, 257 deletions
diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
index fc937aca71fb..b2f963be3993 100644
--- a/drivers/iio/Kconfig
+++ b/drivers/iio/Kconfig
@@ -20,6 +20,12 @@ config IIO_BUFFER
if IIO_BUFFER
+config IIO_BUFFER_CB
+boolean "IIO callback buffer used for push in-kernel interfaces"
+ help
+ Should be selected by any drivers that do-inkernel push
+ usage. That is, those where the data is pushed to the consumer.
+
config IIO_KFIFO_BUF
select IIO_TRIGGER
tristate "Industrial I/O buffering based on kfifo"
@@ -57,11 +63,12 @@ config IIO_CONSUMERS_PER_TRIGGER
source "drivers/iio/accel/Kconfig"
source "drivers/iio/adc/Kconfig"
source "drivers/iio/amplifiers/Kconfig"
-source "drivers/iio/light/Kconfig"
-source "drivers/iio/frequency/Kconfig"
-source "drivers/iio/dac/Kconfig"
source "drivers/iio/common/Kconfig"
+source "drivers/iio/dac/Kconfig"
+source "drivers/iio/frequency/Kconfig"
source "drivers/iio/gyro/Kconfig"
+source "drivers/iio/imu/Kconfig"
+source "drivers/iio/light/Kconfig"
source "drivers/iio/magnetometer/Kconfig"
endif # IIO
diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
index 761f2b65ac52..a0e8cdd67e4d 100644
--- a/drivers/iio/Makefile
+++ b/drivers/iio/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_IIO) += industrialio.o
industrialio-y := industrialio-core.o industrialio-event.o inkern.o
industrialio-$(CONFIG_IIO_BUFFER) += industrialio-buffer.o
industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o
+industrialio-$(CONFIG_IIO_BUFFER_CB) += buffer_cb.o
obj-$(CONFIG_IIO_TRIGGERED_BUFFER) += industrialio-triggered-buffer.o
obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o
@@ -13,9 +14,10 @@ obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o
obj-y += accel/
obj-y += adc/
obj-y += amplifiers/
-obj-y += light/
-obj-y += frequency/
-obj-y += dac/
obj-y += common/
+obj-y += dac/
obj-y += gyro/
+obj-y += frequency/
+obj-y += imu/
+obj-y += light/
obj-y += magnetometer/
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index b2510c4d9a5a..fe4bcd7c5b12 100644
--- a/drivers/iio/accel/Kconfig
+++ b/drivers/iio/accel/Kconfig
@@ -8,7 +8,7 @@ config HID_SENSOR_ACCEL_3D
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
select HID_SENSOR_IIO_COMMON
- tristate "HID Acelerometers 3D"
+ tristate "HID Accelerometers 3D"
help
Say yes here to build support for the HID SENSOR
accelerometers 3D.
diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c
index 314a4057879e..e67bb912bd19 100644
--- a/drivers/iio/accel/hid-sensor-accel-3d.c
+++ b/drivers/iio/accel/hid-sensor-accel-3d.c
@@ -197,21 +197,8 @@ static const struct iio_info accel_3d_info = {
/* Function to push data to buffer */
static void hid_sensor_push_data(struct iio_dev *indio_dev, u8 *data, int len)
{
- struct iio_buffer *buffer = indio_dev->buffer;
- int datum_sz;
-
dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n");
- if (!buffer) {
- dev_err(&indio_dev->dev, "Buffer == NULL\n");
- return;
- }
- datum_sz = buffer->access->get_bytes_per_datum(buffer);
- if (len > datum_sz) {
- dev_err(&indio_dev->dev, "Datum size mismatch %d:%d\n", len,
- datum_sz);
- return;
- }
- iio_push_to_buffer(buffer, (u8 *)data);
+ iio_push_to_buffers(indio_dev, (u8 *)data);
}
/* Callback handler to send event after all samples are received and captured */
@@ -319,10 +306,10 @@ static int __devinit hid_accel_3d_probe(struct platform_device *pdev)
goto error_free_dev;
}
- channels = kmemdup(accel_3d_channels,
- sizeof(accel_3d_channels),
- GFP_KERNEL);
+ channels = kmemdup(accel_3d_channels, sizeof(accel_3d_channels),
+ GFP_KERNEL);
if (!channels) {
+ ret = -ENOMEM;
dev_err(&pdev->dev, "failed to duplicate channels\n");
goto error_free_dev;
}
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 492758120338..961b8d0a4bac 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -18,6 +18,18 @@ config AD7266
Say yes here to build support for Analog Devices AD7265 and AD7266
ADCs.
+config AD7298
+ tristate "Analog Devices AD7298 ADC driver"
+ depends on SPI
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ help
+ Say yes here to build support for Analog Devices AD7298
+ 8 Channel ADC with temperature sensor.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ad7298.
+
config AD7791
tristate "Analog Devices AD7791 ADC driver"
depends on SPI
@@ -30,6 +42,18 @@ config AD7791
To compile this driver as a module, choose M here: the module will be
called ad7791.
+config AD7793
+ tristate "Analog Devices AD7793 and similar ADCs driver"
+ depends on SPI
+ select AD_SIGMA_DELTA
+ help
+ Say yes here to build support for Analog Devices AD7785, AD7792, AD7793,
+ AD7794 and AD7795 SPI analog to digital converters (ADC).
+ If unsure, say N (but it's safe to say "Y").
+
+ To compile this driver as a module, choose M here: the
+ module will be called AD7793.
+
config AD7476
tristate "Analog Devices AD7476 and similar 1-channel ADCs driver"
depends on SPI
@@ -45,6 +69,19 @@ config AD7476
To compile this driver as a module, choose M here: the
module will be called ad7476.
+config AD7887
+ tristate "Analog Devices AD7887 ADC driver"
+ depends on SPI
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ help
+ Say yes here to build support for Analog Devices
+ AD7887 SPI analog to digital converter (ADC).
+ If unsure, say N (but it's safe to say "Y").
+
+ To compile this driver as a module, choose M here: the
+ module will be called ad7887.
+
config AT91_ADC
tristate "Atmel AT91 ADC"
depends on ARCH_AT91
@@ -60,4 +97,32 @@ config LP8788_ADC
help
Say yes here to build support for TI LP8788 ADC.
+config MAX1363
+ tristate "Maxim max1363 ADC driver"
+ depends on I2C
+ select IIO_TRIGGER
+ select MAX1363_RING_BUFFER
+ select IIO_BUFFER
+ select IIO_KFIFO_BUF
+ help
+ Say yes here to build support for many Maxim i2c analog to digital
+ converters (ADC). (max1361, max1362, max1363, max1364, max1036,
+ max1037, max1038, max1039, max1136, max1136, max1137, max1138,
+ max1139, max1236, max1237, max11238, max1239, max11600, max11601,
+ max11602, max11603, max11604, max11605, max11606, max11607,
+ max11608, max11609, max11610, max11611, max11612, max11613,
+ max11614, max11615, max11616, max11617, max11644, max11645,
+ max11646, max11647) Provides direct access via sysfs and buffered
+ data via the iio dev interface.
+
+config TI_ADC081C
+ tristate "Texas Instruments ADC081C021/027"
+ depends on I2C
+ help
+ If you say yes here you get support for Texas Instruments ADC081C021
+ and ADC081C027 ADC chips.
+
+ This driver can also be built as a module. If so, the module will be
+ called ti-adc081c.
+
endmenu
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 900995d5e179..472fd7cd2417 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -4,7 +4,13 @@
obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o
obj-$(CONFIG_AD7266) += ad7266.o
+obj-$(CONFIG_AD7298) += ad7298.o
obj-$(CONFIG_AD7476) += ad7476.o
obj-$(CONFIG_AD7791) += ad7791.o
+obj-$(CONFIG_AD7793) += ad7793.o
+obj-$(CONFIG_AD7887) += ad7887.o
obj-$(CONFIG_AT91_ADC) += at91_adc.o
obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
+obj-$(CONFIG_MAX1363) += max1363.o
+obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o
+
diff --git a/drivers/iio/adc/ad7266.c b/drivers/iio/adc/ad7266.c
index b11f214779a2..a6f4fc5f8201 100644
--- a/drivers/iio/adc/ad7266.c
+++ b/drivers/iio/adc/ad7266.c
@@ -91,7 +91,6 @@ static irqreturn_t ad7266_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
- struct iio_buffer *buffer = indio_dev->buffer;
struct ad7266_state *st = iio_priv(indio_dev);
int ret;
@@ -99,7 +98,7 @@ static irqreturn_t ad7266_trigger_handler(int irq, void *p)
if (ret == 0) {
if (indio_dev->scan_timestamp)
((s64 *)st->data)[1] = pf->timestamp;
- iio_push_to_buffer(buffer, (u8 *)st->data);
+ iio_push_to_buffers(indio_dev, (u8 *)st->data);
}
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/adc/ad7298.c b/drivers/iio/adc/ad7298.c
new file mode 100644
index 000000000000..2364807a5d6c
--- /dev/null
+++ b/drivers/iio/adc/ad7298.c
@@ -0,0 +1,408 @@
+/*
+ * AD7298 SPI ADC driver
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#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 <linux/module.h>
+#include <linux/interrupt.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#include <linux/platform_data/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_MAX_CHAN 8
+#define AD7298_BITS 12
+#define AD7298_STORAGE_BITS 16
+#define AD7298_INTREF_mV 2500
+
+#define AD7298_CH_TEMP 9
+
+#define RES_MASK(bits) ((1 << (bits)) - 1)
+
+struct ad7298_state {
+ struct spi_device *spi;
+ struct regulator *reg;
+ 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.
+ */
+ __be16 rx_buf[12] ____cacheline_aligned;
+ __be16 tx_buf[2];
+};
+
+#define AD7298_V_CHAN(index) \
+ { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = index, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+ .address = index, \
+ .scan_index = index, \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 12, \
+ .storagebits = 16, \
+ .endianness = IIO_BE, \
+ }, \
+ }
+
+static const struct iio_chan_spec ad7298_channels[] = {
+ {
+ .type = IIO_TEMP,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
+ .address = AD7298_CH_TEMP,
+ .scan_index = -1,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 32,
+ .storagebits = 32,
+ },
+ },
+ AD7298_V_CHAN(0),
+ AD7298_V_CHAN(1),
+ AD7298_V_CHAN(2),
+ AD7298_V_CHAN(3),
+ AD7298_V_CHAN(4),
+ AD7298_V_CHAN(5),
+ AD7298_V_CHAN(6),
+ AD7298_V_CHAN(7),
+ IIO_CHAN_SOFT_TIMESTAMP(8),
+};
+
+/**
+ * ad7298_update_scan_mode() setup the spi transfer buffer for the new scan mask
+ **/
+static int ad7298_update_scan_mode(struct iio_dev *indio_dev,
+ const unsigned long *active_scan_mask)
+{
+ struct ad7298_state *st = iio_priv(indio_dev);
+ int i, m;
+ unsigned short command;
+ int scan_count;
+
+ /* Now compute overall size */
+ scan_count = bitmap_weight(active_scan_mask, indio_dev->masklength);
+
+ command = AD7298_WRITE | st->ext_ref;
+
+ for (i = 0, m = AD7298_CH(0); i < AD7298_MAX_CHAN; i++, m >>= 1)
+ if (test_bit(i, active_scan_mask))
+ 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 < 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_trigger_handler() bh of trigger launched polling to ring buffer
+ *
+ * Currently there is no option in this driver to disable the saving of
+ * timestamps within the ring.
+ **/
+static irqreturn_t ad7298_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct ad7298_state *st = iio_priv(indio_dev);
+ s64 time_ns = 0;
+ int b_sent;
+
+ b_sent = spi_sync(st->spi, &st->ring_msg);
+ if (b_sent)
+ goto done;
+
+ if (indio_dev->scan_timestamp) {
+ time_ns = iio_get_time_ns();
+ memcpy((u8 *)st->rx_buf + indio_dev->scan_bytes - sizeof(s64),
+ &time_ns, sizeof(time_ns));
+ }
+
+ iio_push_to_buffers(indio_dev, (u8 *)st->rx_buf);
+
+done:
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+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 int ad7298_scan_temp(struct ad7298_state *st, int *val)
+{
+ int ret;
+ __be16 buf;
+
+ buf = cpu_to_be16(AD7298_WRITE | AD7298_TSENSE |
+ AD7298_TAVG | st->ext_ref);
+
+ ret = spi_write(st->spi, (u8 *)&buf, 2);
+ if (ret)
+ return ret;
+
+ buf = cpu_to_be16(0);
+
+ ret = spi_write(st->spi, (u8 *)&buf, 2);
+ if (ret)
+ return ret;
+
+ usleep_range(101, 1000); /* sleep > 100us */
+
+ ret = spi_read(st->spi, (u8 *)&buf, 2);
+ if (ret)
+ return ret;
+
+ *val = sign_extend32(be16_to_cpu(buf), 11);
+
+ return 0;
+}
+
+static int ad7298_get_ref_voltage(struct ad7298_state *st)
+{
+ int vref;
+
+ if (st->ext_ref) {
+ vref = regulator_get_voltage(st->reg);
+ if (vref < 0)
+ return vref;
+
+ return vref / 1000;
+ } else {
+ return AD7298_INTREF_mV;
+ }
+}
+
+static int ad7298_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val,
+ int *val2,
+ long m)
+{
+ int ret;
+ struct ad7298_state *st = iio_priv(indio_dev);
+
+ switch (m) {
+ case IIO_CHAN_INFO_RAW:
+ mutex_lock(&indio_dev->mlock);
+ if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) {
+ ret = -EBUSY;
+ } else {
+ if (chan->address == AD7298_CH_TEMP)
+ ret = ad7298_scan_temp(st, val);
+ else
+ ret = ad7298_scan_direct(st, chan->address);
+ }
+ mutex_unlock(&indio_dev->mlock);
+
+ if (ret < 0)
+ return ret;
+
+ if (chan->address != AD7298_CH_TEMP)
+ *val = ret & RES_MASK(AD7298_BITS);
+
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->type) {
+ case IIO_VOLTAGE:
+ *val = ad7298_get_ref_voltage(st);
+ *val2 = chan->scan_type.realbits;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ case IIO_TEMP:
+ *val = ad7298_get_ref_voltage(st);
+ *val2 = 10;
+ return IIO_VAL_FRACTIONAL;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_OFFSET:
+ *val = 1093 - 2732500 / ad7298_get_ref_voltage(st);
+ return IIO_VAL_INT;
+ }
+ return -EINVAL;
+}
+
+static const struct iio_info ad7298_info = {
+ .read_raw = &ad7298_read_raw,
+ .update_scan_mode = ad7298_update_scan_mode,
+ .driver_module = THIS_MODULE,
+};
+
+static int __devinit ad7298_probe(struct spi_device *spi)
+{
+ struct ad7298_platform_data *pdata = spi->dev.platform_data;
+ struct ad7298_state *st;
+ struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
+ int ret;
+
+ if (indio_dev == NULL)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+
+ if (pdata && pdata->ext_ref)
+ st->ext_ref = AD7298_EXTREF;
+
+ if (st->ext_ref) {
+ st->reg = regulator_get(&spi->dev, "vref");
+ if (IS_ERR(st->reg)) {
+ ret = PTR_ERR(st->reg);
+ goto error_free;
+ }
+ ret = regulator_enable(st->reg);
+ if (ret)
+ goto error_put_reg;
+ }
+
+ spi_set_drvdata(spi, indio_dev);
+
+ st->spi = spi;
+
+ indio_dev->name = spi_get_device_id(spi)->name;
+ indio_dev->dev.parent = &spi->dev;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = ad7298_channels;
+ indio_dev->num_channels = ARRAY_SIZE(ad7298_channels);
+ indio_dev->info = &ad7298_info;
+
+ /* 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);
+
+ ret = iio_triggered_buffer_setup(indio_dev, NULL,
+ &ad7298_trigger_handler, NULL);
+ if (ret)
+ goto error_disable_reg;
+
+ ret = iio_device_register(indio_dev);
+ if (ret)
+ goto error_cleanup_ring;
+
+ return 0;
+
+error_cleanup_ring:
+ iio_triggered_buffer_cleanup(indio_dev);
+error_disable_reg:
+ if (st->ext_ref)
+ regulator_disable(st->reg);
+error_put_reg:
+ if (st->ext_ref)
+ regulator_put(st->reg);
+error_free:
+ iio_device_free(indio_dev);
+
+ return ret;
+}
+
+static int __devexit ad7298_remove(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev = spi_get_drvdata(spi);
+ struct ad7298_state *st = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+ iio_triggered_buffer_cleanup(indio_dev);
+ if (st->ext_ref) {
+ regulator_disable(st->reg);
+ regulator_put(st->reg);
+ }
+ iio_device_free(indio_dev);
+
+ 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",
+ .owner = THIS_MODULE,
+ },
+ .probe = ad7298_probe,
+ .remove = __devexit_p(ad7298_remove),
+ .id_table = ad7298_id,
+};
+module_spi_driver(ad7298_driver);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Analog Devices AD7298 ADC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c
index 7f2f45a0a48d..330248bfebae 100644
--- a/drivers/iio/adc/ad7476.c
+++ b/drivers/iio/adc/ad7476.c
@@ -76,7 +76,7 @@ static irqreturn_t ad7476_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
((s64 *)st->data)[1] = time_ns;
- iio_push_to_buffer(indio_dev->buffer, st->data);
+ iio_push_to_buffers(indio_dev, st->data);
done:
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/adc/ad7793.c b/drivers/iio/adc/ad7793.c
new file mode 100644
index 000000000000..334e31ff7a4e
--- /dev/null
+++ b/drivers/iio/adc/ad7793.c
@@ -0,0 +1,876 @@
+/*
+ * AD7785/AD7792/AD7793/AD7794/AD7795 SPI ADC driver
+ *
+ * Copyright 2011-2012 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/interrupt.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/sched.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/adc/ad_sigma_delta.h>
+#include <linux/platform_data/ad7793.h>
+
+/* Registers */
+#define AD7793_REG_COMM 0 /* Communications Register (WO, 8-bit) */
+#define AD7793_REG_STAT 0 /* Status Register (RO, 8-bit) */
+#define AD7793_REG_MODE 1 /* Mode Register (RW, 16-bit */
+#define AD7793_REG_CONF 2 /* Configuration Register (RW, 16-bit) */
+#define AD7793_REG_DATA 3 /* Data Register (RO, 16-/24-bit) */
+#define AD7793_REG_ID 4 /* ID Register (RO, 8-bit) */
+#define AD7793_REG_IO 5 /* IO Register (RO, 8-bit) */
+#define AD7793_REG_OFFSET 6 /* Offset Register (RW, 16-bit
+ * (AD7792)/24-bit (AD7793)) */
+#define AD7793_REG_FULLSALE 7 /* Full-Scale Register
+ * (RW, 16-bit (AD7792)/24-bit (AD7793)) */
+
+/* Communications Register Bit Designations (AD7793_REG_COMM) */
+#define AD7793_COMM_WEN (1 << 7) /* Write Enable */
+#define AD7793_COMM_WRITE (0 << 6) /* Write Operation */
+#define AD7793_COMM_READ (1 << 6) /* Read Operation */
+#define AD7793_COMM_ADDR(x) (((x) & 0x7) << 3) /* Register Address */
+#define AD7793_COMM_CREAD (1 << 2) /* Continuous Read of Data Register */
+
+/* Status Register Bit Designations (AD7793_REG_STAT) */
+#define AD7793_STAT_RDY (1 << 7) /* Ready */
+#define AD7793_STAT_ERR (1 << 6) /* Error (Overrange, Underrange) */
+#define AD7793_STAT_CH3 (1 << 2) /* Channel 3 */
+#define AD7793_STAT_CH2 (1 << 1) /* Channel 2 */
+#define AD7793_STAT_CH1 (1 << 0) /* Channel 1 */
+
+/* Mode Register Bit Designations (AD7793_REG_MODE) */
+#define AD7793_MODE_SEL(x) (((x) & 0x7) << 13) /* Operation Mode Select */
+#define AD7793_MODE_SEL_MASK (0x7 << 13) /* Operation Mode Select mask */
+#define AD7793_MODE_CLKSRC(x) (((x) & 0x3) << 6) /* ADC Clock Source Select */
+#define AD7793_MODE_RATE(x) ((x) & 0xF) /* Filter Update Rate Select */
+
+#define AD7793_MODE_CONT 0 /* Continuous Conversion Mode */
+#define AD7793_MODE_SINGLE 1 /* Single Conversion Mode */
+#define AD7793_MODE_IDLE 2 /* Idle Mode */
+#define AD7793_MODE_PWRDN 3 /* Power-Down Mode */
+#define AD7793_MODE_CAL_INT_ZERO 4 /* Internal Zero-Scale Calibration */
+#define AD7793_MODE_CAL_INT_FULL 5 /* Internal Full-Scale Calibration */
+#define AD7793_MODE_CAL_SYS_ZERO 6 /* System Zero-Scale Calibration */
+#define AD7793_MODE_CAL_SYS_FULL 7 /* System Full-Scale Calibration */
+
+#define AD7793_CLK_INT 0 /* Internal 64 kHz Clock not
+ * available at the CLK pin */
+#define AD7793_CLK_INT_CO 1 /* Internal 64 kHz Clock available
+ * at the CLK pin */
+#define AD7793_CLK_EXT 2 /* External 64 kHz Clock */
+#define AD7793_CLK_EXT_DIV2 3 /* External Clock divided by 2 */
+
+/* Configuration Register Bit Designations (AD7793_REG_CONF) */
+#define AD7793_CONF_VBIAS(x) (((x) & 0x3) << 14) /* Bias Voltage
+ * Generator Enable */
+#define AD7793_CONF_BO_EN (1 << 13) /* Burnout Current Enable */
+#define AD7793_CONF_UNIPOLAR (1 << 12) /* Unipolar/Bipolar Enable */
+#define AD7793_CONF_BOOST (1 << 11) /* Boost Enable */
+#define AD7793_CONF_GAIN(x) (((x) & 0x7) << 8) /* Gain Select */
+#define AD7793_CONF_REFSEL(x) ((x) << 6) /* INT/EXT Reference Select */
+#define AD7793_CONF_BUF (1 << 4) /* Buffered Mode Enable */
+#define AD7793_CONF_CHAN(x) ((x) & 0xf) /* Channel select */
+#define AD7793_CONF_CHAN_MASK 0xf /* Channel select mask */
+
+#define AD7793_CH_AIN1P_AIN1M 0 /* AIN1(+) - AIN1(-) */
+#define AD7793_CH_AIN2P_AIN2M 1 /* AIN2(+) - AIN2(-) */
+#define AD7793_CH_AIN3P_AIN3M 2 /* AIN3(+) - AIN3(-) */
+#define AD7793_CH_AIN1M_AIN1M 3 /* AIN1(-) - AIN1(-) */
+#define AD7793_CH_TEMP 6 /* Temp Sensor */
+#define AD7793_CH_AVDD_MONITOR 7 /* AVDD Monitor */
+
+#define AD7795_CH_AIN4P_AIN4M 4 /* AIN4(+) - AIN4(-) */
+#define AD7795_CH_AIN5P_AIN5M 5 /* AIN5(+) - AIN5(-) */
+#define AD7795_CH_AIN6P_AIN6M 6 /* AIN6(+) - AIN6(-) */
+#define AD7795_CH_AIN1M_AIN1M 8 /* AIN1(-) - AIN1(-) */
+
+/* ID Register Bit Designations (AD7793_REG_ID) */
+#define AD7785_ID 0xB
+#define AD7792_ID 0xA
+#define AD7793_ID 0xB
+#define AD7794_ID 0xF
+#define AD7795_ID 0xF
+#define AD7796_ID 0xA
+#define AD7797_ID 0xB
+#define AD7798_ID 0x8
+#define AD7799_ID 0x9
+#define AD7793_ID_MASK 0xF
+
+/* IO (Excitation Current Sources) Register Bit Designations (AD7793_REG_IO) */
+#define AD7793_IO_IEXC1_IOUT1_IEXC2_IOUT2 0 /* IEXC1 connect to IOUT1,
+ * IEXC2 connect to IOUT2 */
+#define AD7793_IO_IEXC1_IOUT2_IEXC2_IOUT1 1 /* IEXC1 connect to IOUT2,
+ * IEXC2 connect to IOUT1 */
+#define AD7793_IO_IEXC1_IEXC2_IOUT1 2 /* Both current sources
+ * IEXC1,2 connect to IOUT1 */
+#define AD7793_IO_IEXC1_IEXC2_IOUT2 3 /* Both current sources
+ * IEXC1,2 connect to IOUT2 */
+
+#define AD7793_IO_IXCEN_10uA (1 << 0) /* Excitation Current 10uA */
+#define AD7793_IO_IXCEN_210uA (2 << 0) /* Excitation Current 210uA */
+#define AD7793_IO_IXCEN_1mA (3 << 0) /* Excitation Current 1mA */
+
+/* NOTE:
+ * The AD7792/AD7793 features a dual use data out ready DOUT/RDY output.
+ * In order to avoid contentions on the SPI bus, it's therefore necessary
+ * to use spi bus locking.
+ *
+ * The DOUT/RDY output must also be wired to an interrupt capable GPIO.
+ */
+
+#define AD7793_FLAG_HAS_CLKSEL BIT(0)
+#define AD7793_FLAG_HAS_REFSEL BIT(1)
+#define AD7793_FLAG_HAS_VBIAS BIT(2)
+#define AD7793_HAS_EXITATION_CURRENT BIT(3)
+#define AD7793_FLAG_HAS_GAIN BIT(4)
+#define AD7793_FLAG_HAS_BUFFER BIT(5)
+
+struct ad7793_chip_info {
+ unsigned int id;
+ const struct iio_chan_spec *channels;
+ unsigned int num_channels;
+ unsigned int flags;
+
+ const struct iio_info *iio_info;
+ const u16 *sample_freq_avail;
+};
+
+struct ad7793_state {
+ const struct ad7793_chip_info *chip_info;
+ struct regulator *reg;
+ u16 int_vref_mv;
+ u16 mode;
+ u16 conf;
+ u32 scale_avail[8][2];
+
+ struct ad_sigma_delta sd;
+
+};
+
+enum ad7793_supported_device_ids {
+ ID_AD7785,
+ ID_AD7792,
+ ID_AD7793,
+ ID_AD7794,
+ ID_AD7795,
+ ID_AD7796,
+ ID_AD7797,
+ ID_AD7798,
+ ID_AD7799,
+};
+
+static struct ad7793_state *ad_sigma_delta_to_ad7793(struct ad_sigma_delta *sd)
+{
+ return container_of(sd, struct ad7793_state, sd);
+}
+
+static int ad7793_set_channel(struct ad_sigma_delta *sd, unsigned int channel)
+{
+ struct ad7793_state *st = ad_sigma_delta_to_ad7793(sd);
+
+ st->conf &= ~AD7793_CONF_CHAN_MASK;
+ st->conf |= AD7793_CONF_CHAN(channel);
+
+ return ad_sd_write_reg(&st->sd, AD7793_REG_CONF, 2, st->conf);
+}
+
+static int ad7793_set_mode(struct ad_sigma_delta *sd,
+ enum ad_sigma_delta_mode mode)
+{
+ struct ad7793_state *st = ad_sigma_delta_to_ad7793(sd);
+
+ st->mode &= ~AD7793_MODE_SEL_MASK;
+ st->mode |= AD7793_MODE_SEL(mode);
+
+ return ad_sd_write_reg(&st->sd, AD7793_REG_MODE, 2, st->mode);
+}
+
+static const struct ad_sigma_delta_info ad7793_sigma_delta_info = {
+ .set_channel = ad7793_set_channel,
+ .set_mode = ad7793_set_mode,
+ .has_registers = true,
+ .addr_shift = 3,
+ .read_mask = BIT(6),
+};
+
+static const struct ad_sd_calib_data ad7793_calib_arr[6] = {
+ {AD7793_MODE_CAL_INT_ZERO, AD7793_CH_AIN1P_AIN1M},
+ {AD7793_MODE_CAL_INT_FULL, AD7793_CH_AIN1P_AIN1M},
+ {AD7793_MODE_CAL_INT_ZERO, AD7793_CH_AIN2P_AIN2M},
+ {AD7793_MODE_CAL_INT_FULL, AD7793_CH_AIN2P_AIN2M},
+ {AD7793_MODE_CAL_INT_ZERO, AD7793_CH_AIN3P_AIN3M},
+ {AD7793_MODE_CAL_INT_FULL, AD7793_CH_AIN3P_AIN3M}
+};
+
+static int ad7793_calibrate_all(struct ad7793_state *st)
+{
+ return ad_sd_calibrate_all(&st->sd, ad7793_calib_arr,
+ ARRAY_SIZE(ad7793_calib_arr));
+}
+
+static int ad7793_check_platform_data(struct ad7793_state *st,
+ const struct ad7793_platform_data *pdata)
+{
+ if ((pdata->current_source_direction == AD7793_IEXEC1_IEXEC2_IOUT1 ||
+ pdata->current_source_direction == AD7793_IEXEC1_IEXEC2_IOUT2) &&
+ ((pdata->exitation_current != AD7793_IX_10uA) &&
+ (pdata->exitation_current != AD7793_IX_210uA)))
+ return -EINVAL;
+
+ if (!(st->chip_info->flags & AD7793_FLAG_HAS_CLKSEL) &&
+ pdata->clock_src != AD7793_CLK_SRC_INT)
+ return -EINVAL;
+
+ if (!(st->chip_info->flags & AD7793_FLAG_HAS_REFSEL) &&
+ pdata->refsel != AD7793_REFSEL_REFIN1)
+ return -EINVAL;
+
+ if (!(st->chip_info->flags & AD7793_FLAG_HAS_VBIAS) &&
+ pdata->bias_voltage != AD7793_BIAS_VOLTAGE_DISABLED)
+ return -EINVAL;
+
+ if (!(st->chip_info->flags & AD7793_HAS_EXITATION_CURRENT) &&
+ pdata->exitation_current != AD7793_IX_DISABLED)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int ad7793_setup(struct iio_dev *indio_dev,
+ const struct ad7793_platform_data *pdata,
+ unsigned int vref_mv)
+{
+ struct ad7793_state *st = iio_priv(indio_dev);
+ int i, ret = -1;
+ unsigned long long scale_uv;
+ u32 id;
+
+ ret = ad7793_check_platform_data(st, pdata);
+ if (ret)
+ return ret;
+
+ /* reset the serial interface */
+ ret = spi_write(st->sd.spi, (u8 *)&ret, sizeof(ret));
+ if (ret < 0)
+ goto out;
+ usleep_range(500, 2000); /* Wait for at least 500us */
+
+ /* write/read test for device presence */
+ ret = ad_sd_read_reg(&st->sd, AD7793_REG_ID, 1, &id);
+ if (ret)
+ goto out;
+
+ id &= AD7793_ID_MASK;
+
+ if (id != st->chip_info->id) {
+ dev_err(&st->sd.spi->dev, "device ID query failed\n");
+ goto out;
+ }
+
+ st->mode = AD7793_MODE_RATE(1);
+ st->conf = 0;
+
+ if (st->chip_info->flags & AD7793_FLAG_HAS_CLKSEL)
+ st->mode |= AD7793_MODE_CLKSRC(pdata->clock_src);
+ if (st->chip_info->flags & AD7793_FLAG_HAS_REFSEL)
+ st->conf |= AD7793_CONF_REFSEL(pdata->refsel);
+ if (st->chip_info->flags & AD7793_FLAG_HAS_VBIAS)
+ st->conf |= AD7793_CONF_VBIAS(pdata->bias_voltage);
+ if (pdata->buffered || !(st->chip_info->flags & AD7793_FLAG_HAS_BUFFER))
+ st->conf |= AD7793_CONF_BUF;
+ if (pdata->boost_enable &&
+ (st->chip_info->flags & AD7793_FLAG_HAS_VBIAS))
+ st->conf |= AD7793_CONF_BOOST;
+ if (pdata->burnout_current)
+ st->conf |= AD7793_CONF_BO_EN;
+ if (pdata->unipolar)
+ st->conf |= AD7793_CONF_UNIPOLAR;
+
+ if (!(st->chip_info->flags & AD7793_FLAG_HAS_GAIN))
+ st->conf |= AD7793_CONF_GAIN(7);
+
+ ret = ad7793_set_mode(&st->sd, AD_SD_MODE_IDLE);
+ if (ret)
+ goto out;
+
+ ret = ad7793_set_channel(&st->sd, 0);
+ if (ret)
+ goto out;
+
+ if (st->chip_info->flags & AD7793_HAS_EXITATION_CURRENT) {
+ ret = ad_sd_write_reg(&st->sd, AD7793_REG_IO, 1,
+ pdata->exitation_current |
+ (pdata->current_source_direction << 2));
+ if (ret)
+ goto out;
+ }
+
+ ret = ad7793_calibrate_all(st);
+ if (ret)
+ goto out;
+
+ /* Populate available ADC input ranges */
+ for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++) {
+ scale_uv = ((u64)vref_mv * 100000000)
+ >> (st->chip_info->channels[0].scan_type.realbits -
+ (!!(st->conf & AD7793_CONF_UNIPOLAR) ? 0 : 1));
+ scale_uv >>= i;
+
+ st->scale_avail[i][1] = do_div(scale_uv, 100000000) * 10;
+ st->scale_avail[i][0] = scale_uv;
+ }
+
+ return 0;
+out:
+ dev_err(&st->sd.spi->dev, "setup failed\n");
+ return ret;
+}
+
+static const u16 ad7793_sample_freq_avail[16] = {0, 470, 242, 123, 62, 50, 39,
+ 33, 19, 17, 16, 12, 10, 8, 6, 4};
+
+static const u16 ad7797_sample_freq_avail[16] = {0, 0, 0, 123, 62, 50, 0,
+ 33, 0, 17, 16, 12, 10, 8, 6, 4};
+
+static ssize_t ad7793_read_frequency(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct ad7793_state *st = iio_priv(indio_dev);
+
+ return sprintf(buf, "%d\n",
+ st->chip_info->sample_freq_avail[AD7793_MODE_RATE(st->mode)]);
+}
+
+static ssize_t ad7793_write_frequency(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct ad7793_state *st = iio_priv(indio_dev);
+ long lval;
+ int i, ret;
+
+ mutex_lock(&indio_dev->mlock);
+ if (iio_buffer_enabled(indio_dev)) {
+ mutex_unlock(&indio_dev->mlock);
+ return -EBUSY;
+ }
+ mutex_unlock(&indio_dev->mlock);
+
+ ret = kstrtol(buf, 10, &lval);
+ if (ret)
+ return ret;
+
+ if (lval == 0)
+ return -EINVAL;
+
+ ret = -EINVAL;
+
+ for (i = 0; i < 16; i++)
+ if (lval == st->chip_info->sample_freq_avail[i]) {
+ mutex_lock(&indio_dev->mlock);
+ st->mode &= ~AD7793_MODE_RATE(-1);
+ st->mode |= AD7793_MODE_RATE(i);
+ ad_sd_write_reg(&st->sd, AD7793_REG_MODE,
+ sizeof(st->mode), st->mode);
+ mutex_unlock(&indio_dev->mlock);
+ ret = 0;
+ }
+
+ return ret ? ret : len;
+}
+
+static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
+ ad7793_read_frequency,
+ ad7793_write_frequency);
+
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(
+ "470 242 123 62 50 39 33 19 17 16 12 10 8 6 4");
+
+static IIO_CONST_ATTR_NAMED(sampling_frequency_available_ad7797,
+ sampling_frequency_available, "123 62 50 33 17 16 12 10 8 6 4");
+
+static ssize_t ad7793_show_scale_available(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct ad7793_state *st = iio_priv(indio_dev);
+ int i, len = 0;
+
+ for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++)
+ len += sprintf(buf + len, "%d.%09u ", st->scale_avail[i][0],
+ st->scale_avail[i][1]);
+
+ len += sprintf(buf + len, "\n");
+
+ return len;
+}
+
+static IIO_DEVICE_ATTR_NAMED(in_m_in_scale_available,
+ in_voltage-voltage_scale_available, S_IRUGO,
+ ad7793_show_scale_available, NULL, 0);
+
+static struct attribute *ad7793_attributes[] = {
+ &iio_dev_attr_sampling_frequency.dev_attr.attr,
+ &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+ &iio_dev_attr_in_m_in_scale_available.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group ad7793_attribute_group = {
+ .attrs = ad7793_attributes,
+};
+
+static struct attribute *ad7797_attributes[] = {
+ &iio_dev_attr_sampling_frequency.dev_attr.attr,
+ &iio_const_attr_sampling_frequency_available_ad7797.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group ad7797_attribute_group = {
+ .attrs = ad7797_attributes,
+};
+
+static int ad7793_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val,
+ int *val2,
+ long m)
+{
+ struct ad7793_state *st = iio_priv(indio_dev);
+ int ret;
+ unsigned long long scale_uv;
+ bool unipolar = !!(st->conf & AD7793_CONF_UNIPOLAR);
+
+ switch (m) {
+ case IIO_CHAN_INFO_RAW:
+ ret = ad_sigma_delta_single_conversion(indio_dev, chan, val);
+ if (ret < 0)
+ return ret;
+
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->type) {
+ case IIO_VOLTAGE:
+ if (chan->differential) {
+ *val = st->
+ scale_avail[(st->conf >> 8) & 0x7][0];
+ *val2 = st->
+ scale_avail[(st->conf >> 8) & 0x7][1];
+ return IIO_VAL_INT_PLUS_NANO;
+ } else {
+ /* 1170mV / 2^23 * 6 */
+ scale_uv = (1170ULL * 1000000000ULL * 6ULL);
+ }
+ break;
+ case IIO_TEMP:
+ /* 1170mV / 0.81 mV/C / 2^23 */
+ scale_uv = 1444444444444444ULL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ scale_uv >>= (chan->scan_type.realbits - (unipolar ? 0 : 1));
+ *val = 0;
+ *val2 = scale_uv;
+ return IIO_VAL_INT_PLUS_NANO;
+ case IIO_CHAN_INFO_OFFSET:
+ if (!unipolar)
+ *val = -(1 << (chan->scan_type.realbits - 1));
+ else
+ *val = 0;
+
+ /* Kelvin to Celsius */
+ if (chan->type == IIO_TEMP) {
+ unsigned long long offset;
+ unsigned int shift;
+
+ shift = chan->scan_type.realbits - (unipolar ? 0 : 1);
+ offset = 273ULL << shift;
+ do_div(offset, 1444);
+ *val -= offset;
+ }
+ return IIO_VAL_INT;
+ }
+ return -EINVAL;
+}
+
+static int ad7793_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val,
+ int val2,
+ long mask)
+{
+ struct ad7793_state *st = iio_priv(indio_dev);
+ int ret, i;
+ unsigned int tmp;
+
+ mutex_lock(&indio_dev->mlock);
+ if (iio_buffer_enabled(indio_dev)) {
+ mutex_unlock(&indio_dev->mlock);
+ return -EBUSY;
+ }
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ ret = -EINVAL;
+ for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++)
+ if (val2 == st->scale_avail[i][1]) {
+ ret = 0;
+ tmp = st->conf;
+ st->conf &= ~AD7793_CONF_GAIN(-1);
+ st->conf |= AD7793_CONF_GAIN(i);
+
+ if (tmp == st->conf)
+ break;
+
+ ad_sd_write_reg(&st->sd, AD7793_REG_CONF,
+ sizeof(st->conf), st->conf);
+ ad7793_calibrate_all(st);
+ break;
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ mutex_unlock(&indio_dev->mlock);
+ return ret;
+}
+
+static int ad7793_write_raw_get_fmt(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ long mask)
+{
+ return IIO_VAL_INT_PLUS_NANO;
+}
+
+static const struct iio_info ad7793_info = {
+ .read_raw = &ad7793_read_raw,
+ .write_raw = &ad7793_write_raw,
+ .write_raw_get_fmt = &ad7793_write_raw_get_fmt,
+ .attrs = &ad7793_attribute_group,
+ .validate_trigger = ad_sd_validate_trigger,
+ .driver_module = THIS_MODULE,
+};
+
+static const struct iio_info ad7797_info = {
+ .read_raw = &ad7793_read_raw,
+ .write_raw = &ad7793_write_raw,
+ .write_raw_get_fmt = &ad7793_write_raw_get_fmt,
+ .attrs = &ad7793_attribute_group,
+ .validate_trigger = ad_sd_validate_trigger,
+ .driver_module = THIS_MODULE,
+};
+
+#define DECLARE_AD7793_CHANNELS(_name, _b, _sb, _s) \
+const struct iio_chan_spec _name##_channels[] = { \
+ AD_SD_DIFF_CHANNEL(0, 0, 0, AD7793_CH_AIN1P_AIN1M, (_b), (_sb), (_s)), \
+ AD_SD_DIFF_CHANNEL(1, 1, 1, AD7793_CH_AIN2P_AIN2M, (_b), (_sb), (_s)), \
+ AD_SD_DIFF_CHANNEL(2, 2, 2, AD7793_CH_AIN3P_AIN3M, (_b), (_sb), (_s)), \
+ AD_SD_SHORTED_CHANNEL(3, 0, AD7793_CH_AIN1M_AIN1M, (_b), (_sb), (_s)), \
+ AD_SD_TEMP_CHANNEL(4, AD7793_CH_TEMP, (_b), (_sb), (_s)), \
+ AD_SD_SUPPLY_CHANNEL(5, 3, AD7793_CH_AVDD_MONITOR, (_b), (_sb), (_s)), \
+ IIO_CHAN_SOFT_TIMESTAMP(6), \
+}
+
+#define DECLARE_AD7795_CHANNELS(_name, _b, _sb) \
+const struct iio_chan_spec _name##_channels[] = { \
+ AD_SD_DIFF_CHANNEL(0, 0, 0, AD7793_CH_AIN1P_AIN1M, (_b), (_sb), 0), \
+ AD_SD_DIFF_CHANNEL(1, 1, 1, AD7793_CH_AIN2P_AIN2M, (_b), (_sb), 0), \
+ AD_SD_DIFF_CHANNEL(2, 2, 2, AD7793_CH_AIN3P_AIN3M, (_b), (_sb), 0), \
+ AD_SD_DIFF_CHANNEL(3, 3, 3, AD7795_CH_AIN4P_AIN4M, (_b), (_sb), 0), \
+ AD_SD_DIFF_CHANNEL(4, 4, 4, AD7795_CH_AIN5P_AIN5M, (_b), (_sb), 0), \
+ AD_SD_DIFF_CHANNEL(5, 5, 5, AD7795_CH_AIN6P_AIN6M, (_b), (_sb), 0), \
+ AD_SD_SHORTED_CHANNEL(6, 0, AD7795_CH_AIN1M_AIN1M, (_b), (_sb), 0), \
+ AD_SD_TEMP_CHANNEL(7, AD7793_CH_TEMP, (_b), (_sb), 0), \
+ AD_SD_SUPPLY_CHANNEL(8, 3, AD7793_CH_AVDD_MONITOR, (_b), (_sb), 0), \
+ IIO_CHAN_SOFT_TIMESTAMP(9), \
+}
+
+#define DECLARE_AD7797_CHANNELS(_name, _b, _sb) \
+const struct iio_chan_spec _name##_channels[] = { \
+ AD_SD_DIFF_CHANNEL(0, 0, 0, AD7793_CH_AIN1P_AIN1M, (_b), (_sb), 0), \
+ AD_SD_SHORTED_CHANNEL(1, 0, AD7793_CH_AIN1M_AIN1M, (_b), (_sb), 0), \
+ AD_SD_TEMP_CHANNEL(2, AD7793_CH_TEMP, (_b), (_sb), 0), \
+ AD_SD_SUPPLY_CHANNEL(3, 3, AD7793_CH_AVDD_MONITOR, (_b), (_sb), 0), \
+ IIO_CHAN_SOFT_TIMESTAMP(4), \
+}
+
+#define DECLARE_AD7799_CHANNELS(_name, _b, _sb) \
+const struct iio_chan_spec _name##_channels[] = { \
+ AD_SD_DIFF_CHANNEL(0, 0, 0, AD7793_CH_AIN1P_AIN1M, (_b), (_sb), 0), \
+ AD_SD_DIFF_CHANNEL(1, 1, 1, AD7793_CH_AIN2P_AIN2M, (_b), (_sb), 0), \
+ AD_SD_DIFF_CHANNEL(2, 2, 2, AD7793_CH_AIN3P_AIN3M, (_b), (_sb), 0), \
+ AD_SD_SHORTED_CHANNEL(3, 0, AD7793_CH_AIN1M_AIN1M, (_b), (_sb), 0), \
+ AD_SD_SUPPLY_CHANNEL(4, 3, AD7793_CH_AVDD_MONITOR, (_b), (_sb), 0), \
+ IIO_CHAN_SOFT_TIMESTAMP(5), \
+}
+
+static DECLARE_AD7793_CHANNELS(ad7785, 20, 32, 4);
+static DECLARE_AD7793_CHANNELS(ad7792, 16, 32, 0);
+static DECLARE_AD7793_CHANNELS(ad7793, 24, 32, 0);
+static DECLARE_AD7795_CHANNELS(ad7794, 16, 32);
+static DECLARE_AD7795_CHANNELS(ad7795, 24, 32);
+static DECLARE_AD7797_CHANNELS(ad7796, 16, 16);
+static DECLARE_AD7797_CHANNELS(ad7797, 24, 32);
+static DECLARE_AD7799_CHANNELS(ad7798, 16, 16);
+static DECLARE_AD7799_CHANNELS(ad7799, 24, 32);
+
+static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
+ [ID_AD7785] = {
+ .id = AD7785_ID,
+ .channels = ad7785_channels,
+ .num_channels = ARRAY_SIZE(ad7785_channels),
+ .iio_info = &ad7793_info,
+ .sample_freq_avail = ad7793_sample_freq_avail,
+ .flags = AD7793_FLAG_HAS_CLKSEL |
+ AD7793_FLAG_HAS_REFSEL |
+ AD7793_FLAG_HAS_VBIAS |
+ AD7793_HAS_EXITATION_CURRENT |
+ AD7793_FLAG_HAS_GAIN |
+ AD7793_FLAG_HAS_BUFFER,
+ },
+ [ID_AD7792] = {
+ .id = AD7792_ID,
+ .channels = ad7792_channels,
+ .num_channels = ARRAY_SIZE(ad7792_channels),
+ .iio_info = &ad7793_info,
+ .sample_freq_avail = ad7793_sample_freq_avail,
+ .flags = AD7793_FLAG_HAS_CLKSEL |
+ AD7793_FLAG_HAS_REFSEL |
+ AD7793_FLAG_HAS_VBIAS |
+ AD7793_HAS_EXITATION_CURRENT |
+ AD7793_FLAG_HAS_GAIN |
+ AD7793_FLAG_HAS_BUFFER,
+ },
+ [ID_AD7793] = {
+ .id = AD7793_ID,
+ .channels = ad7793_channels,
+ .num_channels = ARRAY_SIZE(ad7793_channels),
+ .iio_info = &ad7793_info,
+ .sample_freq_avail = ad7793_sample_freq_avail,
+ .flags = AD7793_FLAG_HAS_CLKSEL |
+ AD7793_FLAG_HAS_REFSEL |
+ AD7793_FLAG_HAS_VBIAS |
+ AD7793_HAS_EXITATION_CURRENT |
+ AD7793_FLAG_HAS_GAIN |
+ AD7793_FLAG_HAS_BUFFER,
+ },
+ [ID_AD7794] = {
+ .id = AD7794_ID,
+ .channels = ad7794_channels,
+ .num_channels = ARRAY_SIZE(ad7794_channels),
+ .iio_info = &ad7793_info,
+ .sample_freq_avail = ad7793_sample_freq_avail,
+ .flags = AD7793_FLAG_HAS_CLKSEL |
+ AD7793_FLAG_HAS_REFSEL |
+ AD7793_FLAG_HAS_VBIAS |
+ AD7793_HAS_EXITATION_CURRENT |
+ AD7793_FLAG_HAS_GAIN |
+ AD7793_FLAG_HAS_BUFFER,
+ },
+ [ID_AD7795] = {
+ .id = AD7795_ID,
+ .channels = ad7795_channels,
+ .num_channels = ARRAY_SIZE(ad7795_channels),
+ .iio_info = &ad7793_info,
+ .sample_freq_avail = ad7793_sample_freq_avail,
+ .flags = AD7793_FLAG_HAS_CLKSEL |
+ AD7793_FLAG_HAS_REFSEL |
+ AD7793_FLAG_HAS_VBIAS |
+ AD7793_HAS_EXITATION_CURRENT |
+ AD7793_FLAG_HAS_GAIN |
+ AD7793_FLAG_HAS_BUFFER,
+ },
+ [ID_AD7796] = {
+ .id = AD7796_ID,
+ .channels = ad7796_channels,
+ .num_channels = ARRAY_SIZE(ad7796_channels),
+ .iio_info = &ad7797_info,
+ .sample_freq_avail = ad7797_sample_freq_avail,
+ .flags = AD7793_FLAG_HAS_CLKSEL,
+ },
+ [ID_AD7797] = {
+ .id = AD7797_ID,
+ .channels = ad7797_channels,
+ .num_channels = ARRAY_SIZE(ad7797_channels),
+ .iio_info = &ad7797_info,
+ .sample_freq_avail = ad7797_sample_freq_avail,
+ .flags = AD7793_FLAG_HAS_CLKSEL,
+ },
+ [ID_AD7798] = {
+ .id = AD7798_ID,
+ .channels = ad7798_channels,
+ .num_channels = ARRAY_SIZE(ad7798_channels),
+ .iio_info = &ad7793_info,
+ .sample_freq_avail = ad7793_sample_freq_avail,
+ .flags = AD7793_FLAG_HAS_GAIN |
+ AD7793_FLAG_HAS_BUFFER,
+ },
+ [ID_AD7799] = {
+ .id = AD7799_ID,
+ .channels = ad7799_channels,
+ .num_channels = ARRAY_SIZE(ad7799_channels),
+ .iio_info = &ad7793_info,
+ .sample_freq_avail = ad7793_sample_freq_avail,
+ .flags = AD7793_FLAG_HAS_GAIN |
+ AD7793_FLAG_HAS_BUFFER,
+ },
+};
+
+static int ad7793_probe(struct spi_device *spi)
+{
+ const struct ad7793_platform_data *pdata = spi->dev.platform_data;
+ struct ad7793_state *st;
+ struct iio_dev *indio_dev;
+ int ret, vref_mv = 0;
+
+ if (!pdata) {
+ dev_err(&spi->dev, "no platform data?\n");
+ return -ENODEV;
+ }
+
+ if (!spi->irq) {
+ dev_err(&spi->dev, "no IRQ?\n");
+ return -ENODEV;
+ }
+
+ indio_dev = iio_device_alloc(sizeof(*st));
+ if (indio_dev == NULL)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+
+ ad_sd_init(&st->sd, indio_dev, spi, &ad7793_sigma_delta_info);
+
+ if (pdata->refsel != AD7793_REFSEL_INTERNAL) {
+ st->reg = regulator_get(&spi->dev, "refin");
+ if (IS_ERR(st->reg)) {
+ ret = PTR_ERR(st->reg);
+ goto error_device_free;
+ }
+
+ ret = regulator_enable(st->reg);
+ if (ret)
+ goto error_put_reg;
+
+ vref_mv = regulator_get_voltage(st->reg);
+ if (vref_mv < 0) {
+ ret = vref_mv;
+ goto error_disable_reg;
+ }
+
+ vref_mv /= 1000;
+ } else {
+ vref_mv = 1170; /* Build-in ref */
+ }
+
+ st->chip_info =
+ &ad7793_chip_info_tbl[spi_get_device_id(spi)->driver_data];
+
+ spi_set_drvdata(spi, indio_dev);
+
+ indio_dev->dev.parent = &spi->dev;
+ indio_dev->name = spi_get_device_id(spi)->name;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = st->chip_info->channels;
+ indio_dev->num_channels = st->chip_info->num_channels;
+ indio_dev->info = st->chip_info->iio_info;
+
+ ret = ad_sd_setup_buffer_and_trigger(indio_dev);
+ if (ret)
+ goto error_disable_reg;
+
+ ret = ad7793_setup(indio_dev, pdata, vref_mv);
+ if (ret)
+ goto error_remove_trigger;
+
+ ret = iio_device_register(indio_dev);
+ if (ret)
+ goto error_remove_trigger;
+
+ return 0;
+
+error_remove_trigger:
+ ad_sd_cleanup_buffer_and_trigger(indio_dev);
+error_disable_reg:
+ if (pdata->refsel != AD7793_REFSEL_INTERNAL)
+ regulator_disable(st->reg);
+error_put_reg:
+ if (pdata->refsel != AD7793_REFSEL_INTERNAL)
+ regulator_put(st->reg);
+error_device_free:
+ iio_device_free(indio_dev);
+
+ return ret;
+}
+
+static int ad7793_remove(struct spi_device *spi)
+{
+ const struct ad7793_platform_data *pdata = spi->dev.platform_data;
+ struct iio_dev *indio_dev = spi_get_drvdata(spi);
+ struct ad7793_state *st = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+ ad_sd_cleanup_buffer_and_trigger(indio_dev);
+
+ if (pdata->refsel != AD7793_REFSEL_INTERNAL) {
+ regulator_disable(st->reg);
+ regulator_put(st->reg);
+ }
+
+ iio_device_free(indio_dev);
+
+ return 0;
+}
+
+static const struct spi_device_id ad7793_id[] = {
+ {"ad7785", ID_AD7785},
+ {"ad7792", ID_AD7792},
+ {"ad7793", ID_AD7793},
+ {"ad7794", ID_AD7794},
+ {"ad7795", ID_AD7795},
+ {"ad7796", ID_AD7796},
+ {"ad7797", ID_AD7797},
+ {"ad7798", ID_AD7798},
+ {"ad7799", ID_AD7799},
+ {}
+};
+MODULE_DEVICE_TABLE(spi, ad7793_id);
+
+static struct spi_driver ad7793_driver = {
+ .driver = {
+ .name = "ad7793",
+ .owner = THIS_MODULE,
+ },
+ .probe = ad7793_probe,
+ .remove = ad7793_remove,
+ .id_table = ad7793_id,
+};
+module_spi_driver(ad7793_driver);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Analog Devices AD7793 and simialr ADCs");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/ad7887.c b/drivers/iio/adc/ad7887.c
new file mode 100644
index 000000000000..81153fafac7a
--- /dev/null
+++ b/drivers/iio/adc/ad7887.c
@@ -0,0 +1,378 @@
+/*
+ * AD7887 SPI ADC driver
+ *
+ * Copyright 2010-2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#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/module.h>
+#include <linux/interrupt.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#include <linux/platform_data/ad7887.h>
+
+#define AD7887_REF_DIS (1 << 5) /* on-chip reference disable */
+#define AD7887_DUAL (1 << 4) /* dual-channel mode */
+#define AD7887_CH_AIN1 (1 << 3) /* convert on channel 1, DUAL=1 */
+#define AD7887_CH_AIN0 (0 << 3) /* convert on channel 0, DUAL=0,1 */
+#define AD7887_PM_MODE1 (0) /* CS based shutdown */
+#define AD7887_PM_MODE2 (1) /* full on */
+#define AD7887_PM_MODE3 (2) /* auto shutdown after conversion */
+#define AD7887_PM_MODE4 (3) /* standby mode */
+
+enum ad7887_channels {
+ AD7887_CH0,
+ AD7887_CH0_CH1,
+ AD7887_CH1,
+};
+
+#define RES_MASK(bits) ((1 << (bits)) - 1)
+
+/**
+ * struct ad7887_chip_info - chip specifc information
+ * @int_vref_mv: the internal reference voltage
+ * @channel: channel specification
+ */
+struct ad7887_chip_info {
+ u16 int_vref_mv;
+ struct iio_chan_spec channel[3];
+};
+
+struct ad7887_state {
+ struct spi_device *spi;
+ const struct ad7887_chip_info *chip_info;
+ struct regulator *reg;
+ struct spi_transfer xfer[4];
+ struct spi_message msg[3];
+ struct spi_message *ring_msg;
+ unsigned char tx_cmd_buf[4];
+
+ /*
+ * DMA (thus cache coherency maintenance) requires the
+ * transfer buffers to live in their own cache lines.
+ * Buffer needs to be large enough to hold two 16 bit samples and a
+ * 64 bit aligned 64 bit timestamp.
+ */
+ unsigned char data[ALIGN(4, sizeof(s64)) + sizeof(s64)]
+ ____cacheline_aligned;
+};
+
+enum ad7887_supported_device_ids {
+ ID_AD7887
+};
+
+static int ad7887_ring_preenable(struct iio_dev *indio_dev)
+{
+ struct ad7887_state *st = iio_priv(indio_dev);
+ int ret;
+
+ ret = iio_sw_buffer_preenable(indio_dev);
+ if (ret < 0)
+ return ret;
+
+ /* We know this is a single long so can 'cheat' */
+ switch (*indio_dev->active_scan_mask) {
+ case (1 << 0):
+ st->ring_msg = &st->msg[AD7887_CH0];
+ break;
+ case (1 << 1):
+ st->ring_msg = &st->msg[AD7887_CH1];
+ /* Dummy read: push CH1 setting down to hardware */
+ spi_sync(st->spi, st->ring_msg);
+ break;
+ case ((1 << 1) | (1 << 0)):
+ st->ring_msg = &st->msg[AD7887_CH0_CH1];
+ break;
+ }
+
+ return 0;
+}
+
+static int ad7887_ring_postdisable(struct iio_dev *indio_dev)
+{
+ struct ad7887_state *st = iio_priv(indio_dev);
+
+ /* dummy read: restore default CH0 settin */
+ return spi_sync(st->spi, &st->msg[AD7887_CH0]);
+}
+
+/**
+ * ad7887_trigger_handler() bh of trigger launched polling to ring buffer
+ *
+ * Currently there is no option in this driver to disable the saving of
+ * timestamps within the ring.
+ **/
+static irqreturn_t ad7887_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct ad7887_state *st = iio_priv(indio_dev);
+ s64 time_ns;
+ int b_sent;
+
+ b_sent = spi_sync(st->spi, st->ring_msg);
+ if (b_sent)
+ goto done;
+
+ time_ns = iio_get_time_ns();
+
+ if (indio_dev->scan_timestamp)
+ memcpy(st->data + indio_dev->scan_bytes - sizeof(s64),
+ &time_ns, sizeof(time_ns));
+
+ iio_push_to_buffers(indio_dev, st->data);
+done:
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+static const struct iio_buffer_setup_ops ad7887_ring_setup_ops = {
+ .preenable = &ad7887_ring_preenable,
+ .postenable = &iio_triggered_buffer_postenable,
+ .predisable = &iio_triggered_buffer_predisable,
+ .postdisable = &ad7887_ring_postdisable,
+};
+
+static int ad7887_scan_direct(struct ad7887_state *st, unsigned ch)
+{
+ int ret = spi_sync(st->spi, &st->msg[ch]);
+ if (ret)
+ return ret;
+
+ return (st->data[(ch * 2)] << 8) | st->data[(ch * 2) + 1];
+}
+
+static int ad7887_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val,
+ int *val2,
+ long m)
+{
+ int ret;
+ struct ad7887_state *st = iio_priv(indio_dev);
+
+ switch (m) {
+ case IIO_CHAN_INFO_RAW:
+ mutex_lock(&indio_dev->mlock);
+ if (iio_buffer_enabled(indio_dev))
+ ret = -EBUSY;
+ else
+ ret = ad7887_scan_direct(st, chan->address);
+ mutex_unlock(&indio_dev->mlock);
+
+ if (ret < 0)
+ return ret;
+ *val = ret >> chan->scan_type.shift;
+ *val &= RES_MASK(chan->scan_type.realbits);
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ if (st->reg) {
+ *val = regulator_get_voltage(st->reg);
+ if (*val < 0)
+ return *val;
+ *val /= 1000;
+ } else {
+ *val = st->chip_info->int_vref_mv;
+ }
+
+ *val2 = chan->scan_type.realbits;
+
+ return IIO_VAL_FRACTIONAL_LOG2;
+ }
+ return -EINVAL;
+}
+
+
+static const struct ad7887_chip_info ad7887_chip_info_tbl[] = {
+ /*
+ * More devices added in future
+ */
+ [ID_AD7887] = {
+ .channel[0] = {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 1,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .address = 1,
+ .scan_index = 1,
+ .scan_type = IIO_ST('u', 12, 16, 0),
+ },
+ .channel[1] = {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .address = 0,
+ .scan_index = 0,
+ .scan_type = IIO_ST('u', 12, 16, 0),
+ },
+ .channel[2] = IIO_CHAN_SOFT_TIMESTAMP(2),
+ .int_vref_mv = 2500,
+ },
+};
+
+static const struct iio_info ad7887_info = {
+ .read_raw = &ad7887_read_raw,
+ .driver_module = THIS_MODULE,
+};
+
+static int __devinit ad7887_probe(struct spi_device *spi)
+{
+ struct ad7887_platform_data *pdata = spi->dev.platform_data;
+ struct ad7887_state *st;
+ struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
+ uint8_t mode;
+ int ret;
+
+ if (indio_dev == NULL)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+
+ if (!pdata || !pdata->use_onchip_ref) {
+ st->reg = regulator_get(&spi->dev, "vref");
+ if (IS_ERR(st->reg)) {
+ ret = PTR_ERR(st->reg);
+ goto error_free;
+ }
+
+ ret = regulator_enable(st->reg);
+ if (ret)
+ goto error_put_reg;
+ }
+
+ st->chip_info =
+ &ad7887_chip_info_tbl[spi_get_device_id(spi)->driver_data];
+
+ spi_set_drvdata(spi, indio_dev);
+ st->spi = spi;
+
+ /* Estabilish that the iio_dev is a child of the spi device */
+ indio_dev->dev.parent = &spi->dev;
+ indio_dev->name = spi_get_device_id(spi)->name;
+ indio_dev->info = &ad7887_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ /* Setup default message */
+
+ mode = AD7887_PM_MODE4;
+ if (!pdata || !pdata->use_onchip_ref)
+ mode |= AD7887_REF_DIS;
+ if (pdata && pdata->en_dual)
+ mode |= AD7887_DUAL;
+
+ st->tx_cmd_buf[0] = AD7887_CH_AIN0 | mode;
+
+ st->xfer[0].rx_buf = &st->data[0];
+ st->xfer[0].tx_buf = &st->tx_cmd_buf[0];
+ st->xfer[0].len = 2;
+
+ spi_message_init(&st->msg[AD7887_CH0]);
+ spi_message_add_tail(&st->xfer[0], &st->msg[AD7887_CH0]);
+
+ if (pdata && pdata->en_dual) {
+ st->tx_cmd_buf[2] = AD7887_CH_AIN1 | mode;
+
+ st->xfer[1].rx_buf = &st->data[0];
+ st->xfer[1].tx_buf = &st->tx_cmd_buf[2];
+ st->xfer[1].len = 2;
+
+ st->xfer[2].rx_buf = &st->data[2];
+ st->xfer[2].tx_buf = &st->tx_cmd_buf[0];
+ st->xfer[2].len = 2;
+
+ spi_message_init(&st->msg[AD7887_CH0_CH1]);
+ spi_message_add_tail(&st->xfer[1], &st->msg[AD7887_CH0_CH1]);
+ spi_message_add_tail(&st->xfer[2], &st->msg[AD7887_CH0_CH1]);
+
+ st->xfer[3].rx_buf = &st->data[2];
+ st->xfer[3].tx_buf = &st->tx_cmd_buf[2];
+ st->xfer[3].len = 2;
+
+ spi_message_init(&st->msg[AD7887_CH1]);
+ spi_message_add_tail(&st->xfer[3], &st->msg[AD7887_CH1]);
+
+ indio_dev->channels = st->chip_info->channel;
+ indio_dev->num_channels = 3;
+ } else {
+ indio_dev->channels = &st->chip_info->channel[1];
+ indio_dev->num_channels = 2;
+ }
+
+ ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
+ &ad7887_trigger_handler, &ad7887_ring_setup_ops);
+ if (ret)
+ goto error_disable_reg;
+
+ ret = iio_device_register(indio_dev);
+ if (ret)
+ goto error_unregister_ring;
+
+ return 0;
+error_unregister_ring:
+ iio_triggered_buffer_cleanup(indio_dev);
+error_disable_reg:
+ if (st->reg)
+ regulator_disable(st->reg);
+error_put_reg:
+ if (st->reg)
+ regulator_put(st->reg);
+error_free:
+ iio_device_free(indio_dev);
+
+ return ret;
+}
+
+static int __devexit ad7887_remove(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev = spi_get_drvdata(spi);
+ struct ad7887_state *st = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+ iio_triggered_buffer_cleanup(indio_dev);
+ if (st->reg) {
+ regulator_disable(st->reg);
+ regulator_put(st->reg);
+ }
+ iio_device_free(indio_dev);
+
+ return 0;
+}
+
+static const struct spi_device_id ad7887_id[] = {
+ {"ad7887", ID_AD7887},
+ {}
+};
+MODULE_DEVICE_TABLE(spi, ad7887_id);
+
+static struct spi_driver ad7887_driver = {
+ .driver = {
+ .name = "ad7887",
+ .owner = THIS_MODULE,
+ },
+ .probe = ad7887_probe,
+ .remove = __devexit_p(ad7887_remove),
+ .id_table = ad7887_id,
+};
+module_spi_driver(ad7887_driver);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Analog Devices AD7887 ADC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c
index 67baa1363d7a..afe6d78c8ff0 100644
--- a/drivers/iio/adc/ad_sigma_delta.c
+++ b/drivers/iio/adc/ad_sigma_delta.c
@@ -391,7 +391,7 @@ static irqreturn_t ad_sd_trigger_handler(int irq, void *p)
break;
}
- iio_push_to_buffer(indio_dev->buffer, (uint8_t *)data);
+ iio_push_to_buffers(indio_dev, (uint8_t *)data);
iio_trigger_notify_done(indio_dev->trig);
sigma_delta->irq_dis = false;
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index 3ed94bf80596..03b85940f4ba 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -46,7 +46,6 @@ struct at91_adc_state {
struct clk *clk;
bool done;
int irq;
- bool irq_enabled;
u16 last_value;
struct mutex lock;
u8 num_channels;
@@ -66,7 +65,6 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *idev = pf->indio_dev;
struct at91_adc_state *st = iio_priv(idev);
- struct iio_buffer *buffer = idev->buffer;
int i, j = 0;
for (i = 0; i < idev->masklength; i++) {
@@ -82,10 +80,9 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
*timestamp = pf->timestamp;
}
- buffer->access->store_to(buffer, (u8 *)st->buffer);
+ iio_push_to_buffers(indio_dev, (u8 *)st->buffer);
iio_trigger_notify_done(idev->trig);
- st->irq_enabled = true;
/* Needed to ACK the DRDY interruption */
at91_adc_readl(st, AT91_ADC_LCDR);
@@ -106,7 +103,6 @@ static irqreturn_t at91_adc_eoc_trigger(int irq, void *private)
if (iio_buffer_enabled(idev)) {
disable_irq_nosync(irq);
- st->irq_enabled = false;
iio_trigger_poll(idev->trig, iio_get_time_ns());
} else {
st->last_value = at91_adc_readl(st, AT91_ADC_LCDR);
diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c
new file mode 100644
index 000000000000..1e84b5b55093
--- /dev/null
+++ b/drivers/iio/adc/max1363.c
@@ -0,0 +1,1700 @@
+ /*
+ * iio/adc/max1363.c
+ * 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.
+ *
+ * max1363.c
+ *
+ * Partial support for max1363 and similar chips.
+ *
+ * Not currently implemented.
+ *
+ * - Control of internal reference.
+ */
+
+#include <linux/interrupt.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/err.h>
+#include <linux/module.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/driver.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/trigger_consumer.h>
+
+#define MAX1363_SETUP_BYTE(a) ((a) | 0x80)
+
+/* There is a fair bit more defined here than currently
+ * used, but the intention is to support everything these
+ * chips do in the long run */
+
+/* see data sheets */
+/* max1363 and max1236, max1237, max1238, max1239 */
+#define MAX1363_SETUP_AIN3_IS_AIN3_REF_IS_VDD 0x00
+#define MAX1363_SETUP_AIN3_IS_REF_EXT_TO_REF 0x20
+#define MAX1363_SETUP_AIN3_IS_AIN3_REF_IS_INT 0x40
+#define MAX1363_SETUP_AIN3_IS_REF_REF_IS_INT 0x60
+#define MAX1363_SETUP_POWER_UP_INT_REF 0x10
+#define MAX1363_SETUP_POWER_DOWN_INT_REF 0x00
+
+/* think about includeing max11600 etc - more settings */
+#define MAX1363_SETUP_EXT_CLOCK 0x08
+#define MAX1363_SETUP_INT_CLOCK 0x00
+#define MAX1363_SETUP_UNIPOLAR 0x00
+#define MAX1363_SETUP_BIPOLAR 0x04
+#define MAX1363_SETUP_RESET 0x00
+#define MAX1363_SETUP_NORESET 0x02
+/* max1363 only - though don't care on others.
+ * For now monitor modes are not implemented as the relevant
+ * line is not connected on my test board.
+ * The definitions are here as I intend to add this soon.
+ */
+#define MAX1363_SETUP_MONITOR_SETUP 0x01
+
+/* Specific to the max1363 */
+#define MAX1363_MON_RESET_CHAN(a) (1 << ((a) + 4))
+#define MAX1363_MON_INT_ENABLE 0x01
+
+/* defined for readability reasons */
+/* All chips */
+#define MAX1363_CONFIG_BYTE(a) ((a))
+
+#define MAX1363_CONFIG_SE 0x01
+#define MAX1363_CONFIG_DE 0x00
+#define MAX1363_CONFIG_SCAN_TO_CS 0x00
+#define MAX1363_CONFIG_SCAN_SINGLE_8 0x20
+#define MAX1363_CONFIG_SCAN_MONITOR_MODE 0x40
+#define MAX1363_CONFIG_SCAN_SINGLE_1 0x60
+/* max123{6-9} only */
+#define MAX1236_SCAN_MID_TO_CHANNEL 0x40
+
+/* max1363 only - merely part of channel selects or don't care for others*/
+#define MAX1363_CONFIG_EN_MON_MODE_READ 0x18
+
+#define MAX1363_CHANNEL_SEL(a) ((a) << 1)
+
+/* max1363 strictly 0x06 - but doesn't matter */
+#define MAX1363_CHANNEL_SEL_MASK 0x1E
+#define MAX1363_SCAN_MASK 0x60
+#define MAX1363_SE_DE_MASK 0x01
+
+#define MAX1363_MAX_CHANNELS 25
+/**
+ * struct max1363_mode - scan mode information
+ * @conf: The corresponding value of the configuration register
+ * @modemask: Bit mask corresponding to channels enabled in this mode
+ */
+struct max1363_mode {
+ int8_t conf;
+ DECLARE_BITMAP(modemask, MAX1363_MAX_CHANNELS);
+};
+
+/* This must be maintained along side the max1363_mode_table in max1363_core */
+enum max1363_modes {
+ /* Single read of a single channel */
+ _s0, _s1, _s2, _s3, _s4, _s5, _s6, _s7, _s8, _s9, _s10, _s11,
+ /* Differential single read */
+ d0m1, d2m3, d4m5, d6m7, d8m9, d10m11,
+ d1m0, d3m2, d5m4, d7m6, d9m8, d11m10,
+ /* Scan to channel and mid to channel where overlapping */
+ s0to1, s0to2, s2to3, s0to3, s0to4, s0to5, s0to6,
+ s6to7, s0to7, s6to8, s0to8, s6to9,
+ s0to9, s6to10, s0to10, s6to11, s0to11,
+ /* Differential scan to channel and mid to channel where overlapping */
+ d0m1to2m3, d0m1to4m5, d0m1to6m7, d6m7to8m9,
+ d0m1to8m9, d6m7to10m11, d0m1to10m11, d1m0to3m2,
+ d1m0to5m4, d1m0to7m6, d7m6to9m8, d1m0to9m8,
+ d7m6to11m10, d1m0to11m10,
+};
+
+/**
+ * struct max1363_chip_info - chip specifc information
+ * @info: iio core function callbacks structure
+ * @channels: channel specification
+ * @num_channels: number of channels
+ * @mode_list: array of available scan modes
+ * @default_mode: the scan mode in which the chip starts up
+ * @int_vref_mv: the internal reference voltage
+ * @num_channels: number of channels
+ * @bits: accuracy of the adc in bits
+ */
+struct max1363_chip_info {
+ const struct iio_info *info;
+ const struct iio_chan_spec *channels;
+ int num_channels;
+ const enum max1363_modes *mode_list;
+ enum max1363_modes default_mode;
+ u16 int_vref_mv;
+ u8 num_modes;
+ u8 bits;
+};
+
+/**
+ * struct max1363_state - driver instance specific data
+ * @client: i2c_client
+ * @setupbyte: cache of current device setup byte
+ * @configbyte: cache of current device config byte
+ * @chip_info: chip model specific constants, available modes etc
+ * @current_mode: the scan mode of this chip
+ * @requestedmask: a valid requested set of channels
+ * @reg: supply regulator
+ * @monitor_on: whether monitor mode is enabled
+ * @monitor_speed: parameter corresponding to device monitor speed setting
+ * @mask_high: bitmask for enabled high thresholds
+ * @mask_low: bitmask for enabled low thresholds
+ * @thresh_high: high threshold values
+ * @thresh_low: low threshold values
+ */
+struct max1363_state {
+ struct i2c_client *client;
+ u8 setupbyte;
+ u8 configbyte;
+ const struct max1363_chip_info *chip_info;
+ const struct max1363_mode *current_mode;
+ u32 requestedmask;
+ struct regulator *reg;
+
+ /* Using monitor modes and buffer at the same time is
+ currently not supported */
+ bool monitor_on;
+ unsigned int monitor_speed:3;
+ u8 mask_high;
+ u8 mask_low;
+ /* 4x unipolar first then the fours bipolar ones */
+ s16 thresh_high[8];
+ s16 thresh_low[8];
+};
+
+#define MAX1363_MODE_SINGLE(_num, _mask) { \
+ .conf = MAX1363_CHANNEL_SEL(_num) \
+ | MAX1363_CONFIG_SCAN_SINGLE_1 \
+ | MAX1363_CONFIG_SE, \
+ .modemask[0] = _mask, \
+ }
+
+#define MAX1363_MODE_SCAN_TO_CHANNEL(_num, _mask) { \
+ .conf = MAX1363_CHANNEL_SEL(_num) \
+ | MAX1363_CONFIG_SCAN_TO_CS \
+ | MAX1363_CONFIG_SE, \
+ .modemask[0] = _mask, \
+ }
+
+/* note not available for max1363 hence naming */
+#define MAX1236_MODE_SCAN_MID_TO_CHANNEL(_mid, _num, _mask) { \
+ .conf = MAX1363_CHANNEL_SEL(_num) \
+ | MAX1236_SCAN_MID_TO_CHANNEL \
+ | MAX1363_CONFIG_SE, \
+ .modemask[0] = _mask \
+}
+
+#define MAX1363_MODE_DIFF_SINGLE(_nump, _numm, _mask) { \
+ .conf = MAX1363_CHANNEL_SEL(_nump) \
+ | MAX1363_CONFIG_SCAN_SINGLE_1 \
+ | MAX1363_CONFIG_DE, \
+ .modemask[0] = _mask \
+ }
+
+/* Can't think how to automate naming so specify for now */
+#define MAX1363_MODE_DIFF_SCAN_TO_CHANNEL(_num, _numvals, _mask) { \
+ .conf = MAX1363_CHANNEL_SEL(_num) \
+ | MAX1363_CONFIG_SCAN_TO_CS \
+ | MAX1363_CONFIG_DE, \
+ .modemask[0] = _mask \
+ }
+
+/* note only available for max1363 hence naming */
+#define MAX1236_MODE_DIFF_SCAN_MID_TO_CHANNEL(_num, _numvals, _mask) { \
+ .conf = MAX1363_CHANNEL_SEL(_num) \
+ | MAX1236_SCAN_MID_TO_CHANNEL \
+ | MAX1363_CONFIG_SE, \
+ .modemask[0] = _mask \
+}
+
+static const struct max1363_mode max1363_mode_table[] = {
+ /* All of the single channel options first */
+ MAX1363_MODE_SINGLE(0, 1 << 0),
+ MAX1363_MODE_SINGLE(1, 1 << 1),
+ MAX1363_MODE_SINGLE(2, 1 << 2),
+ MAX1363_MODE_SINGLE(3, 1 << 3),
+ MAX1363_MODE_SINGLE(4, 1 << 4),
+ MAX1363_MODE_SINGLE(5, 1 << 5),
+ MAX1363_MODE_SINGLE(6, 1 << 6),
+ MAX1363_MODE_SINGLE(7, 1 << 7),
+ MAX1363_MODE_SINGLE(8, 1 << 8),
+ MAX1363_MODE_SINGLE(9, 1 << 9),
+ MAX1363_MODE_SINGLE(10, 1 << 10),
+ MAX1363_MODE_SINGLE(11, 1 << 11),
+
+ MAX1363_MODE_DIFF_SINGLE(0, 1, 1 << 12),
+ MAX1363_MODE_DIFF_SINGLE(2, 3, 1 << 13),
+ MAX1363_MODE_DIFF_SINGLE(4, 5, 1 << 14),
+ MAX1363_MODE_DIFF_SINGLE(6, 7, 1 << 15),
+ MAX1363_MODE_DIFF_SINGLE(8, 9, 1 << 16),
+ MAX1363_MODE_DIFF_SINGLE(10, 11, 1 << 17),
+ MAX1363_MODE_DIFF_SINGLE(1, 0, 1 << 18),
+ MAX1363_MODE_DIFF_SINGLE(3, 2, 1 << 19),
+ MAX1363_MODE_DIFF_SINGLE(5, 4, 1 << 20),
+ MAX1363_MODE_DIFF_SINGLE(7, 6, 1 << 21),
+ MAX1363_MODE_DIFF_SINGLE(9, 8, 1 << 22),
+ MAX1363_MODE_DIFF_SINGLE(11, 10, 1 << 23),
+
+ /* The multichannel scans next */
+ MAX1363_MODE_SCAN_TO_CHANNEL(1, 0x003),
+ MAX1363_MODE_SCAN_TO_CHANNEL(2, 0x007),
+ MAX1236_MODE_SCAN_MID_TO_CHANNEL(2, 3, 0x00C),
+ MAX1363_MODE_SCAN_TO_CHANNEL(3, 0x00F),
+ MAX1363_MODE_SCAN_TO_CHANNEL(4, 0x01F),
+ MAX1363_MODE_SCAN_TO_CHANNEL(5, 0x03F),
+ MAX1363_MODE_SCAN_TO_CHANNEL(6, 0x07F),
+ MAX1236_MODE_SCAN_MID_TO_CHANNEL(6, 7, 0x0C0),
+ MAX1363_MODE_SCAN_TO_CHANNEL(7, 0x0FF),
+ MAX1236_MODE_SCAN_MID_TO_CHANNEL(6, 8, 0x1C0),
+ MAX1363_MODE_SCAN_TO_CHANNEL(8, 0x1FF),
+ MAX1236_MODE_SCAN_MID_TO_CHANNEL(6, 9, 0x3C0),
+ MAX1363_MODE_SCAN_TO_CHANNEL(9, 0x3FF),
+ MAX1236_MODE_SCAN_MID_TO_CHANNEL(6, 10, 0x7C0),
+ MAX1363_MODE_SCAN_TO_CHANNEL(10, 0x7FF),
+ MAX1236_MODE_SCAN_MID_TO_CHANNEL(6, 11, 0xFC0),
+ MAX1363_MODE_SCAN_TO_CHANNEL(11, 0xFFF),
+
+ MAX1363_MODE_DIFF_SCAN_TO_CHANNEL(2, 2, 0x003000),
+ MAX1363_MODE_DIFF_SCAN_TO_CHANNEL(4, 3, 0x007000),
+ MAX1363_MODE_DIFF_SCAN_TO_CHANNEL(6, 4, 0x00F000),
+ MAX1236_MODE_DIFF_SCAN_MID_TO_CHANNEL(8, 2, 0x018000),
+ MAX1363_MODE_DIFF_SCAN_TO_CHANNEL(8, 5, 0x01F000),
+ MAX1236_MODE_DIFF_SCAN_MID_TO_CHANNEL(10, 3, 0x038000),
+ MAX1363_MODE_DIFF_SCAN_TO_CHANNEL(10, 6, 0x3F000),
+ MAX1363_MODE_DIFF_SCAN_TO_CHANNEL(3, 2, 0x0C0000),
+ MAX1363_MODE_DIFF_SCAN_TO_CHANNEL(5, 3, 0x1C0000),
+ MAX1363_MODE_DIFF_SCAN_TO_CHANNEL(7, 4, 0x3C0000),
+ MAX1236_MODE_DIFF_SCAN_MID_TO_CHANNEL(9, 2, 0x600000),
+ MAX1363_MODE_DIFF_SCAN_TO_CHANNEL(9, 5, 0x7C0000),
+ MAX1236_MODE_DIFF_SCAN_MID_TO_CHANNEL(11, 3, 0xE00000),
+ MAX1363_MODE_DIFF_SCAN_TO_CHANNEL(11, 6, 0xFC0000),
+};
+
+static const struct max1363_mode
+*max1363_match_mode(const unsigned long *mask,
+const struct max1363_chip_info *ci)
+{
+ int i;
+ if (mask)
+ for (i = 0; i < ci->num_modes; i++)
+ if (bitmap_subset(mask,
+ max1363_mode_table[ci->mode_list[i]].
+ modemask,
+ MAX1363_MAX_CHANNELS))
+ return &max1363_mode_table[ci->mode_list[i]];
+ return NULL;
+}
+
+static int max1363_write_basic_config(struct i2c_client *client,
+ unsigned char d1,
+ unsigned char d2)
+{
+ u8 tx_buf[2] = {d1, d2};
+
+ return i2c_master_send(client, tx_buf, 2);
+}
+
+static int max1363_set_scan_mode(struct max1363_state *st)
+{
+ st->configbyte &= ~(MAX1363_CHANNEL_SEL_MASK
+ | MAX1363_SCAN_MASK
+ | MAX1363_SE_DE_MASK);
+ st->configbyte |= st->current_mode->conf;
+
+ return max1363_write_basic_config(st->client,
+ st->setupbyte,
+ st->configbyte);
+}
+
+static int max1363_read_single_chan(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val,
+ long m)
+{
+ int ret = 0;
+ s32 data;
+ char rxbuf[2];
+ struct max1363_state *st = iio_priv(indio_dev);
+ struct i2c_client *client = st->client;
+
+ mutex_lock(&indio_dev->mlock);
+ /*
+ * If monitor mode is enabled, the method for reading a single
+ * channel will have to be rather different and has not yet
+ * been implemented.
+ *
+ * Also, cannot read directly if buffered capture enabled.
+ */
+ if (st->monitor_on || iio_buffer_enabled(indio_dev)) {
+ ret = -EBUSY;
+ goto error_ret;
+ }
+
+ /* Check to see if current scan mode is correct */
+ if (st->current_mode != &max1363_mode_table[chan->address]) {
+ /* Update scan mode if needed */
+ st->current_mode = &max1363_mode_table[chan->address];
+ ret = max1363_set_scan_mode(st);
+ if (ret < 0)
+ goto error_ret;
+ }
+ if (st->chip_info->bits != 8) {
+ /* Get reading */
+ data = i2c_master_recv(client, rxbuf, 2);
+ if (data < 0) {
+ ret = data;
+ goto error_ret;
+ }
+ data = (s32)(rxbuf[1]) | ((s32)(rxbuf[0] & 0x0F)) << 8;
+ } else {
+ /* Get reading */
+ data = i2c_master_recv(client, rxbuf, 1);
+ if (data < 0) {
+ ret = data;
+ goto error_ret;
+ }
+ data = rxbuf[0];
+ }
+ *val = data;
+error_ret:
+ mutex_unlock(&indio_dev->mlock);
+ return ret;
+
+}
+
+static int max1363_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val,
+ int *val2,
+ long m)
+{
+ struct max1363_state *st = iio_priv(indio_dev);
+ int ret;
+ switch (m) {
+ case IIO_CHAN_INFO_RAW:
+ ret = max1363_read_single_chan(indio_dev, chan, val, m);
+ if (ret < 0)
+ return ret;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ if ((1 << (st->chip_info->bits + 1)) >
+ st->chip_info->int_vref_mv) {
+ *val = 0;
+ *val2 = 500000;
+ return IIO_VAL_INT_PLUS_MICRO;
+ } else {
+ *val = (st->chip_info->int_vref_mv)
+ >> st->chip_info->bits;
+ return IIO_VAL_INT;
+ }
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* Applies to max1363 */
+static const enum max1363_modes max1363_mode_list[] = {
+ _s0, _s1, _s2, _s3,
+ s0to1, s0to2, s0to3,
+ d0m1, d2m3, d1m0, d3m2,
+ d0m1to2m3, d1m0to3m2,
+};
+
+#define MAX1363_EV_M \
+ (IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) \
+ | IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING))
+#define MAX1363_INFO_MASK (IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT)
+#define MAX1363_CHAN_U(num, addr, si, bits, evmask) \
+ { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = num, \
+ .address = addr, \
+ .info_mask = MAX1363_INFO_MASK, \
+ .datasheet_name = "AIN"#num, \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = bits, \
+ .storagebits = (bits > 8) ? 16 : 8, \
+ .endianness = IIO_BE, \
+ }, \
+ .scan_index = si, \
+ .event_mask = evmask, \
+ }
+
+/* bipolar channel */
+#define MAX1363_CHAN_B(num, num2, addr, si, bits, evmask) \
+ { \
+ .type = IIO_VOLTAGE, \
+ .differential = 1, \
+ .indexed = 1, \
+ .channel = num, \
+ .channel2 = num2, \
+ .address = addr, \
+ .info_mask = MAX1363_INFO_MASK, \
+ .datasheet_name = "AIN"#num"-AIN"#num2, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = bits, \
+ .storagebits = (bits > 8) ? 16 : 8, \
+ .endianness = IIO_BE, \
+ }, \
+ .scan_index = si, \
+ .event_mask = evmask, \
+ }
+
+#define MAX1363_4X_CHANS(bits, em) { \
+ MAX1363_CHAN_U(0, _s0, 0, bits, em), \
+ MAX1363_CHAN_U(1, _s1, 1, bits, em), \
+ MAX1363_CHAN_U(2, _s2, 2, bits, em), \
+ MAX1363_CHAN_U(3, _s3, 3, bits, em), \
+ MAX1363_CHAN_B(0, 1, d0m1, 4, bits, em), \
+ MAX1363_CHAN_B(2, 3, d2m3, 5, bits, em), \
+ MAX1363_CHAN_B(1, 0, d1m0, 6, bits, em), \
+ MAX1363_CHAN_B(3, 2, d3m2, 7, bits, em), \
+ IIO_CHAN_SOFT_TIMESTAMP(8) \
+ }
+
+static const struct iio_chan_spec max1036_channels[] = MAX1363_4X_CHANS(8, 0);
+static const struct iio_chan_spec max1136_channels[] = MAX1363_4X_CHANS(10, 0);
+static const struct iio_chan_spec max1236_channels[] = MAX1363_4X_CHANS(12, 0);
+static const struct iio_chan_spec max1361_channels[] =
+ MAX1363_4X_CHANS(10, MAX1363_EV_M);
+static const struct iio_chan_spec max1363_channels[] =
+ MAX1363_4X_CHANS(12, MAX1363_EV_M);
+
+/* Applies to max1236, max1237 */
+static const enum max1363_modes max1236_mode_list[] = {
+ _s0, _s1, _s2, _s3,
+ s0to1, s0to2, s0to3,
+ d0m1, d2m3, d1m0, d3m2,
+ d0m1to2m3, d1m0to3m2,
+ s2to3,
+};
+
+/* Applies to max1238, max1239 */
+static const enum max1363_modes max1238_mode_list[] = {
+ _s0, _s1, _s2, _s3, _s4, _s5, _s6, _s7, _s8, _s9, _s10, _s11,
+ s0to1, s0to2, s0to3, s0to4, s0to5, s0to6,
+ s0to7, s0to8, s0to9, s0to10, s0to11,
+ d0m1, d2m3, d4m5, d6m7, d8m9, d10m11,
+ d1m0, d3m2, d5m4, d7m6, d9m8, d11m10,
+ d0m1to2m3, d0m1to4m5, d0m1to6m7, d0m1to8m9, d0m1to10m11,
+ d1m0to3m2, d1m0to5m4, d1m0to7m6, d1m0to9m8, d1m0to11m10,
+ s6to7, s6to8, s6to9, s6to10, s6to11,
+ d6m7to8m9, d6m7to10m11, d7m6to9m8, d7m6to11m10,
+};
+
+#define MAX1363_12X_CHANS(bits) { \
+ MAX1363_CHAN_U(0, _s0, 0, bits, 0), \
+ MAX1363_CHAN_U(1, _s1, 1, bits, 0), \
+ MAX1363_CHAN_U(2, _s2, 2, bits, 0), \
+ MAX1363_CHAN_U(3, _s3, 3, bits, 0), \
+ MAX1363_CHAN_U(4, _s4, 4, bits, 0), \
+ MAX1363_CHAN_U(5, _s5, 5, bits, 0), \
+ MAX1363_CHAN_U(6, _s6, 6, bits, 0), \
+ MAX1363_CHAN_U(7, _s7, 7, bits, 0), \
+ MAX1363_CHAN_U(8, _s8, 8, bits, 0), \
+ MAX1363_CHAN_U(9, _s9, 9, bits, 0), \
+ MAX1363_CHAN_U(10, _s10, 10, bits, 0), \
+ MAX1363_CHAN_U(11, _s11, 11, bits, 0), \
+ MAX1363_CHAN_B(0, 1, d0m1, 12, bits, 0), \
+ MAX1363_CHAN_B(2, 3, d2m3, 13, bits, 0), \
+ MAX1363_CHAN_B(4, 5, d4m5, 14, bits, 0), \
+ MAX1363_CHAN_B(6, 7, d6m7, 15, bits, 0), \
+ MAX1363_CHAN_B(8, 9, d8m9, 16, bits, 0), \
+ MAX1363_CHAN_B(10, 11, d10m11, 17, bits, 0), \
+ MAX1363_CHAN_B(1, 0, d1m0, 18, bits, 0), \
+ MAX1363_CHAN_B(3, 2, d3m2, 19, bits, 0), \
+ MAX1363_CHAN_B(5, 4, d5m4, 20, bits, 0), \
+ MAX1363_CHAN_B(7, 6, d7m6, 21, bits, 0), \
+ MAX1363_CHAN_B(9, 8, d9m8, 22, bits, 0), \
+ MAX1363_CHAN_B(11, 10, d11m10, 23, bits, 0), \
+ IIO_CHAN_SOFT_TIMESTAMP(24) \
+ }
+static const struct iio_chan_spec max1038_channels[] = MAX1363_12X_CHANS(8);
+static const struct iio_chan_spec max1138_channels[] = MAX1363_12X_CHANS(10);
+static const struct iio_chan_spec max1238_channels[] = MAX1363_12X_CHANS(12);
+
+static const enum max1363_modes max11607_mode_list[] = {
+ _s0, _s1, _s2, _s3,
+ s0to1, s0to2, s0to3,
+ s2to3,
+ d0m1, d2m3, d1m0, d3m2,
+ d0m1to2m3, d1m0to3m2,
+};
+
+static const enum max1363_modes max11608_mode_list[] = {
+ _s0, _s1, _s2, _s3, _s4, _s5, _s6, _s7,
+ s0to1, s0to2, s0to3, s0to4, s0to5, s0to6, s0to7,
+ s6to7,
+ d0m1, d2m3, d4m5, d6m7,
+ d1m0, d3m2, d5m4, d7m6,
+ d0m1to2m3, d0m1to4m5, d0m1to6m7,
+ d1m0to3m2, d1m0to5m4, d1m0to7m6,
+};
+
+#define MAX1363_8X_CHANS(bits) { \
+ MAX1363_CHAN_U(0, _s0, 0, bits, 0), \
+ MAX1363_CHAN_U(1, _s1, 1, bits, 0), \
+ MAX1363_CHAN_U(2, _s2, 2, bits, 0), \
+ MAX1363_CHAN_U(3, _s3, 3, bits, 0), \
+ MAX1363_CHAN_U(4, _s4, 4, bits, 0), \
+ MAX1363_CHAN_U(5, _s5, 5, bits, 0), \
+ MAX1363_CHAN_U(6, _s6, 6, bits, 0), \
+ MAX1363_CHAN_U(7, _s7, 7, bits, 0), \
+ MAX1363_CHAN_B(0, 1, d0m1, 8, bits, 0), \
+ MAX1363_CHAN_B(2, 3, d2m3, 9, bits, 0), \
+ MAX1363_CHAN_B(4, 5, d4m5, 10, bits, 0), \
+ MAX1363_CHAN_B(6, 7, d6m7, 11, bits, 0), \
+ MAX1363_CHAN_B(1, 0, d1m0, 12, bits, 0), \
+ MAX1363_CHAN_B(3, 2, d3m2, 13, bits, 0), \
+ MAX1363_CHAN_B(5, 4, d5m4, 14, bits, 0), \
+ MAX1363_CHAN_B(7, 6, d7m6, 15, bits, 0), \
+ IIO_CHAN_SOFT_TIMESTAMP(16) \
+}
+static const struct iio_chan_spec max11602_channels[] = MAX1363_8X_CHANS(8);
+static const struct iio_chan_spec max11608_channels[] = MAX1363_8X_CHANS(10);
+static const struct iio_chan_spec max11614_channels[] = MAX1363_8X_CHANS(12);
+
+static const enum max1363_modes max11644_mode_list[] = {
+ _s0, _s1, s0to1, d0m1, d1m0,
+};
+
+#define MAX1363_2X_CHANS(bits) { \
+ MAX1363_CHAN_U(0, _s0, 0, bits, 0), \
+ MAX1363_CHAN_U(1, _s1, 1, bits, 0), \
+ MAX1363_CHAN_B(0, 1, d0m1, 2, bits, 0), \
+ MAX1363_CHAN_B(1, 0, d1m0, 3, bits, 0), \
+ IIO_CHAN_SOFT_TIMESTAMP(4) \
+ }
+
+static const struct iio_chan_spec max11646_channels[] = MAX1363_2X_CHANS(10);
+static const struct iio_chan_spec max11644_channels[] = MAX1363_2X_CHANS(12);
+
+enum { max1361,
+ max1362,
+ max1363,
+ max1364,
+ max1036,
+ max1037,
+ max1038,
+ max1039,
+ max1136,
+ max1137,
+ max1138,
+ max1139,
+ max1236,
+ max1237,
+ max1238,
+ max1239,
+ max11600,
+ max11601,
+ max11602,
+ max11603,
+ max11604,
+ max11605,
+ max11606,
+ max11607,
+ max11608,
+ max11609,
+ max11610,
+ max11611,
+ max11612,
+ max11613,
+ max11614,
+ max11615,
+ max11616,
+ max11617,
+ max11644,
+ max11645,
+ max11646,
+ max11647
+};
+
+static const int max1363_monitor_speeds[] = { 133000, 665000, 33300, 16600,
+ 8300, 4200, 2000, 1000 };
+
+static ssize_t max1363_monitor_show_freq(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct max1363_state *st = iio_priv(dev_to_iio_dev(dev));
+ return sprintf(buf, "%d\n", max1363_monitor_speeds[st->monitor_speed]);
+}
+
+static ssize_t max1363_monitor_store_freq(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct max1363_state *st = iio_priv(indio_dev);
+ int i, ret;
+ unsigned long val;
+ bool found = false;
+
+ ret = strict_strtoul(buf, 10, &val);
+ if (ret)
+ return -EINVAL;
+ for (i = 0; i < ARRAY_SIZE(max1363_monitor_speeds); i++)
+ if (val == max1363_monitor_speeds[i]) {
+ found = true;
+ break;
+ }
+ if (!found)
+ return -EINVAL;
+
+ mutex_lock(&indio_dev->mlock);
+ st->monitor_speed = i;
+ mutex_unlock(&indio_dev->mlock);
+
+ return 0;
+}
+
+static IIO_DEV_ATTR_SAMP_FREQ(S_IRUGO | S_IWUSR,
+ max1363_monitor_show_freq,
+ max1363_monitor_store_freq);
+
+static IIO_CONST_ATTR(sampling_frequency_available,
+ "133000 665000 33300 16600 8300 4200 2000 1000");
+
+static int max1363_read_thresh(struct iio_dev *indio_dev,
+ u64 event_code,
+ int *val)
+{
+ struct max1363_state *st = iio_priv(indio_dev);
+ if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == IIO_EV_DIR_FALLING)
+ *val = st->thresh_low[IIO_EVENT_CODE_EXTRACT_CHAN(event_code)];
+ else
+ *val = st->thresh_high[IIO_EVENT_CODE_EXTRACT_CHAN(event_code)];
+ return 0;
+}
+
+static int max1363_write_thresh(struct iio_dev *indio_dev,
+ u64 event_code,
+ int val)
+{
+ struct max1363_state *st = iio_priv(indio_dev);
+ /* make it handle signed correctly as well */
+ switch (st->chip_info->bits) {
+ case 10:
+ if (val > 0x3FF)
+ return -EINVAL;
+ break;
+ case 12:
+ if (val > 0xFFF)
+ return -EINVAL;
+ break;
+ }
+
+ switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) {
+ case IIO_EV_DIR_FALLING:
+ st->thresh_low[IIO_EVENT_CODE_EXTRACT_CHAN(event_code)] = val;
+ break;
+ case IIO_EV_DIR_RISING:
+ st->thresh_high[IIO_EVENT_CODE_EXTRACT_CHAN(event_code)] = val;
+ break;
+ }
+
+ return 0;
+}
+
+static const u64 max1363_event_codes[] = {
+ IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, 0,
+ IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING),
+ IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, 1,
+ IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING),
+ IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, 2,
+ IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING),
+ IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, 3,
+ IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING),
+ IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, 0,
+ IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING),
+ IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, 1,
+ IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING),
+ IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, 2,
+ IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING),
+ IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, 3,
+ IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING),
+};
+
+static irqreturn_t max1363_event_handler(int irq, void *private)
+{
+ struct iio_dev *indio_dev = private;
+ struct max1363_state *st = iio_priv(indio_dev);
+ s64 timestamp = iio_get_time_ns();
+ unsigned long mask, loc;
+ u8 rx;
+ u8 tx[2] = { st->setupbyte,
+ MAX1363_MON_INT_ENABLE | (st->monitor_speed << 1) | 0xF0 };
+
+ i2c_master_recv(st->client, &rx, 1);
+ mask = rx;
+ for_each_set_bit(loc, &mask, 8)
+ iio_push_event(indio_dev, max1363_event_codes[loc], timestamp);
+ i2c_master_send(st->client, tx, 2);
+
+ return IRQ_HANDLED;
+}
+
+static int max1363_read_event_config(struct iio_dev *indio_dev,
+ u64 event_code)
+{
+ struct max1363_state *st = iio_priv(indio_dev);
+ int val;
+ int number = IIO_EVENT_CODE_EXTRACT_CHAN(event_code);
+
+ mutex_lock(&indio_dev->mlock);
+ if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == IIO_EV_DIR_FALLING)
+ val = (1 << number) & st->mask_low;
+ else
+ val = (1 << number) & st->mask_high;
+ mutex_unlock(&indio_dev->mlock);
+
+ return val;
+}
+
+static int max1363_monitor_mode_update(struct max1363_state *st, int enabled)
+{
+ u8 *tx_buf;
+ int ret, i = 3, j;
+ unsigned long numelements;
+ int len;
+ const long *modemask;
+
+ if (!enabled) {
+ /* transition to buffered capture is not currently supported */
+ st->setupbyte &= ~MAX1363_SETUP_MONITOR_SETUP;
+ st->configbyte &= ~MAX1363_SCAN_MASK;
+ st->monitor_on = false;
+ return max1363_write_basic_config(st->client,
+ st->setupbyte,
+ st->configbyte);
+ }
+
+ /* Ensure we are in the relevant mode */
+ st->setupbyte |= MAX1363_SETUP_MONITOR_SETUP;
+ st->configbyte &= ~(MAX1363_CHANNEL_SEL_MASK
+ | MAX1363_SCAN_MASK
+ | MAX1363_SE_DE_MASK);
+ st->configbyte |= MAX1363_CONFIG_SCAN_MONITOR_MODE;
+ if ((st->mask_low | st->mask_high) & 0x0F) {
+ st->configbyte |= max1363_mode_table[s0to3].conf;
+ modemask = max1363_mode_table[s0to3].modemask;
+ } else if ((st->mask_low | st->mask_high) & 0x30) {
+ st->configbyte |= max1363_mode_table[d0m1to2m3].conf;
+ modemask = max1363_mode_table[d0m1to2m3].modemask;
+ } else {
+ st->configbyte |= max1363_mode_table[d1m0to3m2].conf;
+ modemask = max1363_mode_table[d1m0to3m2].modemask;
+ }
+ numelements = bitmap_weight(modemask, MAX1363_MAX_CHANNELS);
+ len = 3 * numelements + 3;
+ tx_buf = kmalloc(len, GFP_KERNEL);
+ if (!tx_buf) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+ tx_buf[0] = st->configbyte;
+ tx_buf[1] = st->setupbyte;
+ tx_buf[2] = (st->monitor_speed << 1);
+
+ /*
+ * So we need to do yet another bit of nefarious scan mode
+ * setup to match what we need.
+ */
+ for (j = 0; j < 8; j++)
+ if (test_bit(j, modemask)) {
+ /* Establish the mode is in the scan */
+ if (st->mask_low & (1 << j)) {
+ tx_buf[i] = (st->thresh_low[j] >> 4) & 0xFF;
+ tx_buf[i + 1] = (st->thresh_low[j] << 4) & 0xF0;
+ } else if (j < 4) {
+ tx_buf[i] = 0;
+ tx_buf[i + 1] = 0;
+ } else {
+ tx_buf[i] = 0x80;
+ tx_buf[i + 1] = 0;
+ }
+ if (st->mask_high & (1 << j)) {
+ tx_buf[i + 1] |=
+ (st->thresh_high[j] >> 8) & 0x0F;
+ tx_buf[i + 2] = st->thresh_high[j] & 0xFF;
+ } else if (j < 4) {
+ tx_buf[i + 1] |= 0x0F;
+ tx_buf[i + 2] = 0xFF;
+ } else {
+ tx_buf[i + 1] |= 0x07;
+ tx_buf[i + 2] = 0xFF;
+ }
+ i += 3;
+ }
+
+
+ ret = i2c_master_send(st->client, tx_buf, len);
+ if (ret < 0)
+ goto error_ret;
+ if (ret != len) {
+ ret = -EIO;
+ goto error_ret;
+ }
+
+ /*
+ * Now that we hopefully have sensible thresholds in place it is
+ * time to turn the interrupts on.
+ * It is unclear from the data sheet if this should be necessary
+ * (i.e. whether monitor mode setup is atomic) but it appears to
+ * be in practice.
+ */
+ tx_buf[0] = st->setupbyte;
+ tx_buf[1] = MAX1363_MON_INT_ENABLE | (st->monitor_speed << 1) | 0xF0;
+ ret = i2c_master_send(st->client, tx_buf, 2);
+ if (ret < 0)
+ goto error_ret;
+ if (ret != 2) {
+ ret = -EIO;
+ goto error_ret;
+ }
+ ret = 0;
+ st->monitor_on = true;
+error_ret:
+
+ kfree(tx_buf);
+
+ return ret;
+}
+
+/*
+ * To keep this manageable we always use one of 3 scan modes.
+ * Scan 0...3, 0-1,2-3 and 1-0,3-2
+ */
+
+static inline int __max1363_check_event_mask(int thismask, int checkmask)
+{
+ int ret = 0;
+ /* Is it unipolar */
+ if (thismask < 4) {
+ if (checkmask & ~0x0F) {
+ ret = -EBUSY;
+ goto error_ret;
+ }
+ } else if (thismask < 6) {
+ if (checkmask & ~0x30) {
+ ret = -EBUSY;
+ goto error_ret;
+ }
+ } else if (checkmask & ~0xC0)
+ ret = -EBUSY;
+error_ret:
+ return ret;
+}
+
+static int max1363_write_event_config(struct iio_dev *indio_dev,
+ u64 event_code,
+ int state)
+{
+ int ret = 0;
+ struct max1363_state *st = iio_priv(indio_dev);
+ u16 unifiedmask;
+ int number = IIO_EVENT_CODE_EXTRACT_CHAN(event_code);
+
+ mutex_lock(&indio_dev->mlock);
+ unifiedmask = st->mask_low | st->mask_high;
+ if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == IIO_EV_DIR_FALLING) {
+
+ if (state == 0)
+ st->mask_low &= ~(1 << number);
+ else {
+ ret = __max1363_check_event_mask((1 << number),
+ unifiedmask);
+ if (ret)
+ goto error_ret;
+ st->mask_low |= (1 << number);
+ }
+ } else {
+ if (state == 0)
+ st->mask_high &= ~(1 << number);
+ else {
+ ret = __max1363_check_event_mask((1 << number),
+ unifiedmask);
+ if (ret)
+ goto error_ret;
+ st->mask_high |= (1 << number);
+ }
+ }
+
+ max1363_monitor_mode_update(st, !!(st->mask_high | st->mask_low));
+error_ret:
+ mutex_unlock(&indio_dev->mlock);
+
+ return ret;
+}
+
+/*
+ * As with scan_elements, only certain sets of these can
+ * be combined.
+ */
+static struct attribute *max1363_event_attributes[] = {
+ &iio_dev_attr_sampling_frequency.dev_attr.attr,
+ &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+ NULL,
+};
+
+static struct attribute_group max1363_event_attribute_group = {
+ .attrs = max1363_event_attributes,
+ .name = "events",
+};
+
+static int max1363_update_scan_mode(struct iio_dev *indio_dev,
+ const unsigned long *scan_mask)
+{
+ struct max1363_state *st = iio_priv(indio_dev);
+
+ /*
+ * Need to figure out the current mode based upon the requested
+ * scan mask in iio_dev
+ */
+ st->current_mode = max1363_match_mode(scan_mask, st->chip_info);
+ if (!st->current_mode)
+ return -EINVAL;
+ max1363_set_scan_mode(st);
+ return 0;
+}
+
+static const struct iio_info max1238_info = {
+ .read_raw = &max1363_read_raw,
+ .driver_module = THIS_MODULE,
+ .update_scan_mode = &max1363_update_scan_mode,
+};
+
+static const struct iio_info max1363_info = {
+ .read_event_value = &max1363_read_thresh,
+ .write_event_value = &max1363_write_thresh,
+ .read_event_config = &max1363_read_event_config,
+ .write_event_config = &max1363_write_event_config,
+ .read_raw = &max1363_read_raw,
+ .update_scan_mode = &max1363_update_scan_mode,
+ .driver_module = THIS_MODULE,
+ .event_attrs = &max1363_event_attribute_group,
+};
+
+/* max1363 and max1368 tested - rest from data sheet */
+static const struct max1363_chip_info max1363_chip_info_tbl[] = {
+ [max1361] = {
+ .bits = 10,
+ .int_vref_mv = 2048,
+ .mode_list = max1363_mode_list,
+ .num_modes = ARRAY_SIZE(max1363_mode_list),
+ .default_mode = s0to3,
+ .channels = max1361_channels,
+ .num_channels = ARRAY_SIZE(max1361_channels),
+ .info = &max1363_info,
+ },
+ [max1362] = {
+ .bits = 10,
+ .int_vref_mv = 4096,
+ .mode_list = max1363_mode_list,
+ .num_modes = ARRAY_SIZE(max1363_mode_list),
+ .default_mode = s0to3,
+ .channels = max1361_channels,
+ .num_channels = ARRAY_SIZE(max1361_channels),
+ .info = &max1363_info,
+ },
+ [max1363] = {
+ .bits = 12,
+ .int_vref_mv = 2048,
+ .mode_list = max1363_mode_list,
+ .num_modes = ARRAY_SIZE(max1363_mode_list),
+ .default_mode = s0to3,
+ .channels = max1363_channels,
+ .num_channels = ARRAY_SIZE(max1363_channels),
+ .info = &max1363_info,
+ },
+ [max1364] = {
+ .bits = 12,
+ .int_vref_mv = 4096,
+ .mode_list = max1363_mode_list,
+ .num_modes = ARRAY_SIZE(max1363_mode_list),
+ .default_mode = s0to3,
+ .channels = max1363_channels,
+ .num_channels = ARRAY_SIZE(max1363_channels),
+ .info = &max1363_info,
+ },
+ [max1036] = {
+ .bits = 8,
+ .int_vref_mv = 4096,
+ .mode_list = max1236_mode_list,
+ .num_modes = ARRAY_SIZE(max1236_mode_list),
+ .default_mode = s0to3,
+ .info = &max1238_info,
+ .channels = max1036_channels,
+ .num_channels = ARRAY_SIZE(max1036_channels),
+ },
+ [max1037] = {
+ .bits = 8,
+ .int_vref_mv = 2048,
+ .mode_list = max1236_mode_list,
+ .num_modes = ARRAY_SIZE(max1236_mode_list),
+ .default_mode = s0to3,
+ .info = &max1238_info,
+ .channels = max1036_channels,
+ .num_channels = ARRAY_SIZE(max1036_channels),
+ },
+ [max1038] = {
+ .bits = 8,
+ .int_vref_mv = 4096,
+ .mode_list = max1238_mode_list,
+ .num_modes = ARRAY_SIZE(max1238_mode_list),
+ .default_mode = s0to11,
+ .info = &max1238_info,
+ .channels = max1038_channels,
+ .num_channels = ARRAY_SIZE(max1038_channels),
+ },
+ [max1039] = {
+ .bits = 8,
+ .int_vref_mv = 2048,
+ .mode_list = max1238_mode_list,
+ .num_modes = ARRAY_SIZE(max1238_mode_list),
+ .default_mode = s0to11,
+ .info = &max1238_info,
+ .channels = max1038_channels,
+ .num_channels = ARRAY_SIZE(max1038_channels),
+ },
+ [max1136] = {
+ .bits = 10,
+ .int_vref_mv = 4096,
+ .mode_list = max1236_mode_list,
+ .num_modes = ARRAY_SIZE(max1236_mode_list),
+ .default_mode = s0to3,
+ .info = &max1238_info,
+ .channels = max1136_channels,
+ .num_channels = ARRAY_SIZE(max1136_channels),
+ },
+ [max1137] = {
+ .bits = 10,
+ .int_vref_mv = 2048,
+ .mode_list = max1236_mode_list,
+ .num_modes = ARRAY_SIZE(max1236_mode_list),
+ .default_mode = s0to3,
+ .info = &max1238_info,
+ .channels = max1136_channels,
+ .num_channels = ARRAY_SIZE(max1136_channels),
+ },
+ [max1138] = {
+ .bits = 10,
+ .int_vref_mv = 4096,
+ .mode_list = max1238_mode_list,
+ .num_modes = ARRAY_SIZE(max1238_mode_list),
+ .default_mode = s0to11,
+ .info = &max1238_info,
+ .channels = max1138_channels,
+ .num_channels = ARRAY_SIZE(max1138_channels),
+ },
+ [max1139] = {
+ .bits = 10,
+ .int_vref_mv = 2048,
+ .mode_list = max1238_mode_list,
+ .num_modes = ARRAY_SIZE(max1238_mode_list),
+ .default_mode = s0to11,
+ .info = &max1238_info,
+ .channels = max1138_channels,
+ .num_channels = ARRAY_SIZE(max1138_channels),
+ },
+ [max1236] = {
+ .bits = 12,
+ .int_vref_mv = 4096,
+ .mode_list = max1236_mode_list,
+ .num_modes = ARRAY_SIZE(max1236_mode_list),
+ .default_mode = s0to3,
+ .info = &max1238_info,
+ .channels = max1236_channels,
+ .num_channels = ARRAY_SIZE(max1236_channels),
+ },
+ [max1237] = {
+ .bits = 12,
+ .int_vref_mv = 2048,
+ .mode_list = max1236_mode_list,
+ .num_modes = ARRAY_SIZE(max1236_mode_list),
+ .default_mode = s0to3,
+ .info = &max1238_info,
+ .channels = max1236_channels,
+ .num_channels = ARRAY_SIZE(max1236_channels),
+ },
+ [max1238] = {
+ .bits = 12,
+ .int_vref_mv = 4096,
+ .mode_list = max1238_mode_list,
+ .num_modes = ARRAY_SIZE(max1238_mode_list),
+ .default_mode = s0to11,
+ .info = &max1238_info,
+ .channels = max1238_channels,
+ .num_channels = ARRAY_SIZE(max1238_channels),
+ },
+ [max1239] = {
+ .bits = 12,
+ .int_vref_mv = 2048,
+ .mode_list = max1238_mode_list,
+ .num_modes = ARRAY_SIZE(max1238_mode_list),
+ .default_mode = s0to11,
+ .info = &max1238_info,
+ .channels = max1238_channels,
+ .num_channels = ARRAY_SIZE(max1238_channels),
+ },
+ [max11600] = {
+ .bits = 8,
+ .int_vref_mv = 4096,
+ .mode_list = max11607_mode_list,
+ .num_modes = ARRAY_SIZE(max11607_mode_list),
+ .default_mode = s0to3,
+ .info = &max1238_info,
+ .channels = max1036_channels,
+ .num_channels = ARRAY_SIZE(max1036_channels),
+ },
+ [max11601] = {
+ .bits = 8,
+ .int_vref_mv = 2048,
+ .mode_list = max11607_mode_list,
+ .num_modes = ARRAY_SIZE(max11607_mode_list),
+ .default_mode = s0to3,
+ .info = &max1238_info,
+ .channels = max1036_channels,
+ .num_channels = ARRAY_SIZE(max1036_channels),
+ },
+ [max11602] = {
+ .bits = 8,
+ .int_vref_mv = 4096,
+ .mode_list = max11608_mode_list,
+ .num_modes = ARRAY_SIZE(max11608_mode_list),
+ .default_mode = s0to7,
+ .info = &max1238_info,
+ .channels = max11602_channels,
+ .num_channels = ARRAY_SIZE(max11602_channels),
+ },
+ [max11603] = {
+ .bits = 8,
+ .int_vref_mv = 2048,
+ .mode_list = max11608_mode_list,
+ .num_modes = ARRAY_SIZE(max11608_mode_list),
+ .default_mode = s0to7,
+ .info = &max1238_info,
+ .channels = max11602_channels,
+ .num_channels = ARRAY_SIZE(max11602_channels),
+ },
+ [max11604] = {
+ .bits = 8,
+ .int_vref_mv = 4098,
+ .mode_list = max1238_mode_list,
+ .num_modes = ARRAY_SIZE(max1238_mode_list),
+ .default_mode = s0to11,
+ .info = &max1238_info,
+ .channels = max1238_channels,
+ .num_channels = ARRAY_SIZE(max1238_channels),
+ },
+ [max11605] = {
+ .bits = 8,
+ .int_vref_mv = 2048,
+ .mode_list = max1238_mode_list,
+ .num_modes = ARRAY_SIZE(max1238_mode_list),
+ .default_mode = s0to11,
+ .info = &max1238_info,
+ .channels = max1238_channels,
+ .num_channels = ARRAY_SIZE(max1238_channels),
+ },
+ [max11606] = {
+ .bits = 10,
+ .int_vref_mv = 4096,
+ .mode_list = max11607_mode_list,
+ .num_modes = ARRAY_SIZE(max11607_mode_list),
+ .default_mode = s0to3,
+ .info = &max1238_info,
+ .channels = max1136_channels,
+ .num_channels = ARRAY_SIZE(max1136_channels),
+ },
+ [max11607] = {
+ .bits = 10,
+ .int_vref_mv = 2048,
+ .mode_list = max11607_mode_list,
+ .num_modes = ARRAY_SIZE(max11607_mode_list),
+ .default_mode = s0to3,
+ .info = &max1238_info,
+ .channels = max1136_channels,
+ .num_channels = ARRAY_SIZE(max1136_channels),
+ },
+ [max11608] = {
+ .bits = 10,
+ .int_vref_mv = 4096,
+ .mode_list = max11608_mode_list,
+ .num_modes = ARRAY_SIZE(max11608_mode_list),
+ .default_mode = s0to7,
+ .info = &max1238_info,
+ .channels = max11608_channels,
+ .num_channels = ARRAY_SIZE(max11608_channels),
+ },
+ [max11609] = {
+ .bits = 10,
+ .int_vref_mv = 2048,
+ .mode_list = max11608_mode_list,
+ .num_modes = ARRAY_SIZE(max11608_mode_list),
+ .default_mode = s0to7,
+ .info = &max1238_info,
+ .channels = max11608_channels,
+ .num_channels = ARRAY_SIZE(max11608_channels),
+ },
+ [max11610] = {
+ .bits = 10,
+ .int_vref_mv = 4098,
+ .mode_list = max1238_mode_list,
+ .num_modes = ARRAY_SIZE(max1238_mode_list),
+ .default_mode = s0to11,
+ .info = &max1238_info,
+ .channels = max1238_channels,
+ .num_channels = ARRAY_SIZE(max1238_channels),
+ },
+ [max11611] = {
+ .bits = 10,
+ .int_vref_mv = 2048,
+ .mode_list = max1238_mode_list,
+ .num_modes = ARRAY_SIZE(max1238_mode_list),
+ .default_mode = s0to11,
+ .info = &max1238_info,
+ .channels = max1238_channels,
+ .num_channels = ARRAY_SIZE(max1238_channels),
+ },
+ [max11612] = {
+ .bits = 12,
+ .int_vref_mv = 4096,
+ .mode_list = max11607_mode_list,
+ .num_modes = ARRAY_SIZE(max11607_mode_list),
+ .default_mode = s0to3,
+ .info = &max1238_info,
+ .channels = max1363_channels,
+ .num_channels = ARRAY_SIZE(max1363_channels),
+ },
+ [max11613] = {
+ .bits = 12,
+ .int_vref_mv = 2048,
+ .mode_list = max11607_mode_list,
+ .num_modes = ARRAY_SIZE(max11607_mode_list),
+ .default_mode = s0to3,
+ .info = &max1238_info,
+ .channels = max1363_channels,
+ .num_channels = ARRAY_SIZE(max1363_channels),
+ },
+ [max11614] = {
+ .bits = 12,
+ .int_vref_mv = 4096,
+ .mode_list = max11608_mode_list,
+ .num_modes = ARRAY_SIZE(max11608_mode_list),
+ .default_mode = s0to7,
+ .info = &max1238_info,
+ .channels = max11614_channels,
+ .num_channels = ARRAY_SIZE(max11614_channels),
+ },
+ [max11615] = {
+ .bits = 12,
+ .int_vref_mv = 2048,
+ .mode_list = max11608_mode_list,
+ .num_modes = ARRAY_SIZE(max11608_mode_list),
+ .default_mode = s0to7,
+ .info = &max1238_info,
+ .channels = max11614_channels,
+ .num_channels = ARRAY_SIZE(max11614_channels),
+ },
+ [max11616] = {
+ .bits = 12,
+ .int_vref_mv = 4098,
+ .mode_list = max1238_mode_list,
+ .num_modes = ARRAY_SIZE(max1238_mode_list),
+ .default_mode = s0to11,
+ .info = &max1238_info,
+ .channels = max1238_channels,
+ .num_channels = ARRAY_SIZE(max1238_channels),
+ },
+ [max11617] = {
+ .bits = 12,
+ .int_vref_mv = 2048,
+ .mode_list = max1238_mode_list,
+ .num_modes = ARRAY_SIZE(max1238_mode_list),
+ .default_mode = s0to11,
+ .info = &max1238_info,
+ .channels = max1238_channels,
+ .num_channels = ARRAY_SIZE(max1238_channels),
+ },
+ [max11644] = {
+ .bits = 12,
+ .int_vref_mv = 2048,
+ .mode_list = max11644_mode_list,
+ .num_modes = ARRAY_SIZE(max11644_mode_list),
+ .default_mode = s0to1,
+ .info = &max1238_info,
+ .channels = max11644_channels,
+ .num_channels = ARRAY_SIZE(max11644_channels),
+ },
+ [max11645] = {
+ .bits = 12,
+ .int_vref_mv = 4096,
+ .mode_list = max11644_mode_list,
+ .num_modes = ARRAY_SIZE(max11644_mode_list),
+ .default_mode = s0to1,
+ .info = &max1238_info,
+ .channels = max11644_channels,
+ .num_channels = ARRAY_SIZE(max11644_channels),
+ },
+ [max11646] = {
+ .bits = 10,
+ .int_vref_mv = 2048,
+ .mode_list = max11644_mode_list,
+ .num_modes = ARRAY_SIZE(max11644_mode_list),
+ .default_mode = s0to1,
+ .info = &max1238_info,
+ .channels = max11646_channels,
+ .num_channels = ARRAY_SIZE(max11646_channels),
+ },
+ [max11647] = {
+ .bits = 10,
+ .int_vref_mv = 4096,
+ .mode_list = max11644_mode_list,
+ .num_modes = ARRAY_SIZE(max11644_mode_list),
+ .default_mode = s0to1,
+ .info = &max1238_info,
+ .channels = max11646_channels,
+ .num_channels = ARRAY_SIZE(max11646_channels),
+ },
+};
+
+static int max1363_initial_setup(struct max1363_state *st)
+{
+ st->setupbyte = MAX1363_SETUP_AIN3_IS_AIN3_REF_IS_VDD
+ | MAX1363_SETUP_POWER_UP_INT_REF
+ | MAX1363_SETUP_INT_CLOCK
+ | MAX1363_SETUP_UNIPOLAR
+ | MAX1363_SETUP_NORESET;
+
+ /* Set scan mode writes the config anyway so wait until then*/
+ st->setupbyte = MAX1363_SETUP_BYTE(st->setupbyte);
+ st->current_mode = &max1363_mode_table[st->chip_info->default_mode];
+ st->configbyte = MAX1363_CONFIG_BYTE(st->configbyte);
+
+ return max1363_set_scan_mode(st);
+}
+
+static int __devinit max1363_alloc_scan_masks(struct iio_dev *indio_dev)
+{
+ struct max1363_state *st = iio_priv(indio_dev);
+ unsigned long *masks;
+ int i;
+
+ masks = kzalloc(BITS_TO_LONGS(MAX1363_MAX_CHANNELS)*sizeof(long)*
+ (st->chip_info->num_modes + 1), GFP_KERNEL);
+ if (!masks)
+ return -ENOMEM;
+
+ for (i = 0; i < st->chip_info->num_modes; i++)
+ bitmap_copy(masks + BITS_TO_LONGS(MAX1363_MAX_CHANNELS)*i,
+ max1363_mode_table[st->chip_info->mode_list[i]]
+ .modemask, MAX1363_MAX_CHANNELS);
+
+ indio_dev->available_scan_masks = masks;
+
+ return 0;
+}
+
+
+static irqreturn_t max1363_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct max1363_state *st = iio_priv(indio_dev);
+ s64 time_ns;
+ __u8 *rxbuf;
+ int b_sent;
+ size_t d_size;
+ unsigned long numvals = bitmap_weight(st->current_mode->modemask,
+ MAX1363_MAX_CHANNELS);
+
+ /* Ensure the timestamp is 8 byte aligned */
+ if (st->chip_info->bits != 8)
+ d_size = numvals*2;
+ else
+ d_size = numvals;
+ if (indio_dev->scan_timestamp) {
+ d_size += sizeof(s64);
+ if (d_size % sizeof(s64))
+ d_size += sizeof(s64) - (d_size % sizeof(s64));
+ }
+ /* 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)
+ goto done;
+
+ rxbuf = kmalloc(d_size, GFP_KERNEL);
+ if (rxbuf == NULL)
+ goto done;
+ if (st->chip_info->bits != 8)
+ b_sent = i2c_master_recv(st->client, rxbuf, numvals*2);
+ else
+ b_sent = i2c_master_recv(st->client, rxbuf, numvals);
+ if (b_sent < 0)
+ goto done_free;
+
+ time_ns = iio_get_time_ns();
+
+ if (indio_dev->scan_timestamp)
+ memcpy(rxbuf + d_size - sizeof(s64), &time_ns, sizeof(time_ns));
+ iio_push_to_buffers(indio_dev, rxbuf);
+
+done_free:
+ kfree(rxbuf);
+done:
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+static const struct iio_buffer_setup_ops max1363_buffered_setup_ops = {
+ .postenable = &iio_triggered_buffer_postenable,
+ .preenable = &iio_sw_buffer_preenable,
+ .predisable = &iio_triggered_buffer_predisable,
+};
+
+static int max1363_register_buffered_funcs_and_init(struct iio_dev *indio_dev)
+{
+ struct max1363_state *st = iio_priv(indio_dev);
+ int ret = 0;
+
+ indio_dev->buffer = iio_kfifo_allocate(indio_dev);
+ if (!indio_dev->buffer) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+ indio_dev->pollfunc = iio_alloc_pollfunc(NULL,
+ &max1363_trigger_handler,
+ IRQF_ONESHOT,
+ indio_dev,
+ "%s_consumer%d",
+ st->client->name,
+ indio_dev->id);
+ if (indio_dev->pollfunc == NULL) {
+ ret = -ENOMEM;
+ goto error_deallocate_sw_rb;
+ }
+ /* Buffer functions - here trigger setup related */
+ indio_dev->setup_ops = &max1363_buffered_setup_ops;
+
+ /* Flag that polled buffering is possible */
+ indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
+
+ return 0;
+
+error_deallocate_sw_rb:
+ iio_kfifo_free(indio_dev->buffer);
+error_ret:
+ return ret;
+}
+
+static void max1363_buffer_cleanup(struct iio_dev *indio_dev)
+{
+ /* ensure that the trigger has been detached */
+ iio_dealloc_pollfunc(indio_dev->pollfunc);
+ iio_kfifo_free(indio_dev->buffer);
+}
+
+static int __devinit max1363_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret;
+ struct max1363_state *st;
+ struct iio_dev *indio_dev;
+
+ indio_dev = iio_device_alloc(sizeof(struct max1363_state));
+ if (indio_dev == NULL) {
+ ret = -ENOMEM;
+ goto error_out;
+ }
+
+ ret = iio_map_array_register(indio_dev, client->dev.platform_data);
+ if (ret < 0)
+ goto error_free_device;
+
+ st = iio_priv(indio_dev);
+
+ st->reg = regulator_get(&client->dev, "vcc");
+ if (IS_ERR(st->reg)) {
+ ret = PTR_ERR(st->reg);
+ goto error_unregister_map;
+ }
+
+ ret = regulator_enable(st->reg);
+ if (ret)
+ goto error_put_reg;
+
+ /* this is only used for device removal purposes */
+ i2c_set_clientdata(client, indio_dev);
+
+ st->chip_info = &max1363_chip_info_tbl[id->driver_data];
+ st->client = client;
+
+ ret = max1363_alloc_scan_masks(indio_dev);
+ if (ret)
+ goto error_disable_reg;
+
+ /* Estabilish that the iio_dev is a child of the i2c device */
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->name = id->name;
+ indio_dev->channels = st->chip_info->channels;
+ indio_dev->num_channels = st->chip_info->num_channels;
+ indio_dev->info = st->chip_info->info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = st->chip_info->channels;
+ indio_dev->num_channels = st->chip_info->num_channels;
+ ret = max1363_initial_setup(st);
+ if (ret < 0)
+ goto error_free_available_scan_masks;
+
+ ret = max1363_register_buffered_funcs_and_init(indio_dev);
+ if (ret)
+ goto error_free_available_scan_masks;
+
+ ret = iio_buffer_register(indio_dev,
+ st->chip_info->channels,
+ st->chip_info->num_channels);
+ if (ret)
+ goto error_cleanup_buffer;
+
+ if (client->irq) {
+ ret = request_threaded_irq(st->client->irq,
+ NULL,
+ &max1363_event_handler,
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ "max1363_event",
+ indio_dev);
+
+ if (ret)
+ goto error_uninit_buffer;
+ }
+
+ ret = iio_device_register(indio_dev);
+ if (ret < 0)
+ goto error_free_irq;
+
+ return 0;
+error_free_irq:
+ free_irq(st->client->irq, indio_dev);
+error_uninit_buffer:
+ iio_buffer_unregister(indio_dev);
+error_cleanup_buffer:
+ max1363_buffer_cleanup(indio_dev);
+error_free_available_scan_masks:
+ kfree(indio_dev->available_scan_masks);
+error_unregister_map:
+ iio_map_array_unregister(indio_dev, client->dev.platform_data);
+error_disable_reg:
+ regulator_disable(st->reg);
+error_put_reg:
+ regulator_put(st->reg);
+error_free_device:
+ iio_device_free(indio_dev);
+error_out:
+ return ret;
+}
+
+static int __devexit max1363_remove(struct i2c_client *client)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ struct max1363_state *st = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+ if (client->irq)
+ free_irq(st->client->irq, indio_dev);
+ iio_buffer_unregister(indio_dev);
+ max1363_buffer_cleanup(indio_dev);
+ kfree(indio_dev->available_scan_masks);
+ if (!IS_ERR(st->reg)) {
+ regulator_disable(st->reg);
+ regulator_put(st->reg);
+ }
+ iio_map_array_unregister(indio_dev, client->dev.platform_data);
+ iio_device_free(indio_dev);
+
+ return 0;
+}
+
+static const struct i2c_device_id max1363_id[] = {
+ { "max1361", max1361 },
+ { "max1362", max1362 },
+ { "max1363", max1363 },
+ { "max1364", max1364 },
+ { "max1036", max1036 },
+ { "max1037", max1037 },
+ { "max1038", max1038 },
+ { "max1039", max1039 },
+ { "max1136", max1136 },
+ { "max1137", max1137 },
+ { "max1138", max1138 },
+ { "max1139", max1139 },
+ { "max1236", max1236 },
+ { "max1237", max1237 },
+ { "max1238", max1238 },
+ { "max1239", max1239 },
+ { "max11600", max11600 },
+ { "max11601", max11601 },
+ { "max11602", max11602 },
+ { "max11603", max11603 },
+ { "max11604", max11604 },
+ { "max11605", max11605 },
+ { "max11606", max11606 },
+ { "max11607", max11607 },
+ { "max11608", max11608 },
+ { "max11609", max11609 },
+ { "max11610", max11610 },
+ { "max11611", max11611 },
+ { "max11612", max11612 },
+ { "max11613", max11613 },
+ { "max11614", max11614 },
+ { "max11615", max11615 },
+ { "max11616", max11616 },
+ { "max11617", max11617 },
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, max1363_id);
+
+static struct i2c_driver max1363_driver = {
+ .driver = {
+ .name = "max1363",
+ },
+ .probe = max1363_probe,
+ .remove = __devexit_p(max1363_remove),
+ .id_table = max1363_id,
+};
+module_i2c_driver(max1363_driver);
+
+MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
+MODULE_DESCRIPTION("Maxim 1363 ADC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/ti-adc081c.c b/drivers/iio/adc/ti-adc081c.c
new file mode 100644
index 000000000000..f4a46dd8f43b
--- /dev/null
+++ b/drivers/iio/adc/ti-adc081c.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2012 Avionic Design GmbH
+ *
+ * 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.
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+
+#include <linux/iio/iio.h>
+#include <linux/regulator/consumer.h>
+
+struct adc081c {
+ struct i2c_client *i2c;
+ struct regulator *ref;
+};
+
+#define REG_CONV_RES 0x00
+
+static int adc081c_read_raw(struct iio_dev *iio,
+ struct iio_chan_spec const *channel, int *value,
+ int *shift, long mask)
+{
+ struct adc081c *adc = iio_priv(iio);
+ int err;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ err = i2c_smbus_read_word_swapped(adc->i2c, REG_CONV_RES);
+ if (err < 0)
+ return err;
+
+ *value = (err >> 4) & 0xff;
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_SCALE:
+ err = regulator_get_voltage(adc->ref);
+ if (err < 0)
+ return err;
+
+ *value = err / 1000;
+ *shift = 8;
+
+ return IIO_VAL_FRACTIONAL_LOG2;
+
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static const struct iio_chan_spec adc081c_channel = {
+ .type = IIO_VOLTAGE,
+ .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT |
+ IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+};
+
+static const struct iio_info adc081c_info = {
+ .read_raw = adc081c_read_raw,
+ .driver_module = THIS_MODULE,
+};
+
+static int adc081c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct iio_dev *iio;
+ struct adc081c *adc;
+ int err;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
+ return -ENODEV;
+
+ iio = iio_device_alloc(sizeof(*adc));
+ if (!iio)
+ return -ENOMEM;
+
+ adc = iio_priv(iio);
+ adc->i2c = client;
+
+ adc->ref = regulator_get(&client->dev, "vref");
+ if (IS_ERR(adc->ref)) {
+ err = PTR_ERR(adc->ref);
+ goto iio_free;
+ }
+
+ err = regulator_enable(adc->ref);
+ if (err < 0)
+ goto regulator_put;
+
+ iio->dev.parent = &client->dev;
+ iio->name = dev_name(&client->dev);
+ iio->modes = INDIO_DIRECT_MODE;
+ iio->info = &adc081c_info;
+
+ iio->channels = &adc081c_channel;
+ iio->num_channels = 1;
+
+ err = iio_device_register(iio);
+ if (err < 0)
+ goto regulator_disable;
+
+ i2c_set_clientdata(client, iio);
+
+ return 0;
+
+regulator_disable:
+ regulator_disable(adc->ref);
+regulator_put:
+ regulator_put(adc->ref);
+iio_free:
+ iio_device_free(iio);
+
+ return err;
+}
+
+static int adc081c_remove(struct i2c_client *client)
+{
+ struct iio_dev *iio = i2c_get_clientdata(client);
+ struct adc081c *adc = iio_priv(iio);
+
+ iio_device_unregister(iio);
+ regulator_disable(adc->ref);
+ regulator_put(adc->ref);
+ iio_device_free(iio);
+
+ return 0;
+}
+
+static const struct i2c_device_id adc081c_id[] = {
+ { "adc081c", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, adc081c_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id adc081c_of_match[] = {
+ { .compatible = "ti,adc081c" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, adc081c_of_match);
+#endif
+
+static struct i2c_driver adc081c_driver = {
+ .driver = {
+ .name = "adc081c",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(adc081c_of_match),
+ },
+ .probe = adc081c_probe,
+ .remove = adc081c_remove,
+ .id_table = adc081c_id,
+};
+module_i2c_driver(adc081c_driver);
+
+MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>");
+MODULE_DESCRIPTION("Texas Instruments ADC081C021/027 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/buffer_cb.c b/drivers/iio/buffer_cb.c
new file mode 100644
index 000000000000..4d40e24f3721
--- /dev/null
+++ b/drivers/iio/buffer_cb.c
@@ -0,0 +1,113 @@
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/consumer.h>
+
+struct iio_cb_buffer {
+ struct iio_buffer buffer;
+ int (*cb)(u8 *data, void *private);
+ void *private;
+ struct iio_channel *channels;
+};
+
+static int iio_buffer_cb_store_to(struct iio_buffer *buffer, u8 *data)
+{
+ struct iio_cb_buffer *cb_buff = container_of(buffer,
+ struct iio_cb_buffer,
+ buffer);
+
+ return cb_buff->cb(data, cb_buff->private);
+}
+
+static struct iio_buffer_access_funcs iio_cb_access = {
+ .store_to = &iio_buffer_cb_store_to,
+};
+
+struct iio_cb_buffer *iio_channel_get_all_cb(const char *name,
+ int (*cb)(u8 *data,
+ void *private),
+ void *private)
+{
+ int ret;
+ struct iio_cb_buffer *cb_buff;
+ struct iio_dev *indio_dev;
+ struct iio_channel *chan;
+
+ cb_buff = kzalloc(sizeof(*cb_buff), GFP_KERNEL);
+ if (cb_buff == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+
+ cb_buff->private = private;
+ cb_buff->cb = cb;
+ cb_buff->buffer.access = &iio_cb_access;
+ INIT_LIST_HEAD(&cb_buff->buffer.demux_list);
+
+ cb_buff->channels = iio_channel_get_all(name);
+ if (IS_ERR(cb_buff->channels)) {
+ ret = PTR_ERR(cb_buff->channels);
+ goto error_free_cb_buff;
+ }
+
+ indio_dev = cb_buff->channels[0].indio_dev;
+ cb_buff->buffer.scan_mask
+ = kcalloc(BITS_TO_LONGS(indio_dev->masklength), sizeof(long),
+ GFP_KERNEL);
+ if (cb_buff->buffer.scan_mask == NULL) {
+ ret = -ENOMEM;
+ goto error_release_channels;
+ }
+ chan = &cb_buff->channels[0];
+ while (chan->indio_dev) {
+ if (chan->indio_dev != indio_dev) {
+ ret = -EINVAL;
+ goto error_release_channels;
+ }
+ set_bit(chan->channel->scan_index,
+ cb_buff->buffer.scan_mask);
+ chan++;
+ }
+
+ return cb_buff;
+
+error_release_channels:
+ iio_channel_release_all(cb_buff->channels);
+error_free_cb_buff:
+ kfree(cb_buff);
+error_ret:
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(iio_channel_get_all_cb);
+
+int iio_channel_start_all_cb(struct iio_cb_buffer *cb_buff)
+{
+ return iio_update_buffers(cb_buff->channels[0].indio_dev,
+ &cb_buff->buffer,
+ NULL);
+}
+EXPORT_SYMBOL_GPL(iio_channel_start_all_cb);
+
+void iio_channel_stop_all_cb(struct iio_cb_buffer *cb_buff)
+{
+ iio_update_buffers(cb_buff->channels[0].indio_dev,
+ NULL,
+ &cb_buff->buffer);
+}
+EXPORT_SYMBOL_GPL(iio_channel_stop_all_cb);
+
+void iio_channel_release_all_cb(struct iio_cb_buffer *cb_buff)
+{
+ iio_channel_release_all(cb_buff->channels);
+ kfree(cb_buff);
+}
+EXPORT_SYMBOL_GPL(iio_channel_release_all_cb);
+
+struct iio_channel
+*iio_channel_cb_get_channels(const struct iio_cb_buffer *cb_buffer)
+{
+ return cb_buffer->channels;
+}
+EXPORT_SYMBOL_GPL(iio_channel_cb_get_channels);
diff --git a/drivers/iio/common/hid-sensors/Kconfig b/drivers/iio/common/hid-sensors/Kconfig
index 8e63d81d652a..ae10778da7aa 100644
--- a/drivers/iio/common/hid-sensors/Kconfig
+++ b/drivers/iio/common/hid-sensors/Kconfig
@@ -15,7 +15,7 @@ config HID_SENSOR_IIO_COMMON
attributes.
config HID_SENSOR_ENUM_BASE_QUIRKS
- tristate "ENUM base quirks for HID Sensor IIO drivers"
+ bool "ENUM base quirks for HID Sensor IIO drivers"
depends on HID_SENSOR_IIO_COMMON
help
Say yes here to build support for sensor hub FW using
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
index d4b790d18efb..d60198a6ca29 100644
--- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
+++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
@@ -36,10 +36,8 @@ static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
int state_val;
state_val = state ? 1 : 0;
-#if (defined CONFIG_HID_SENSOR_ENUM_BASE_QUIRKS) || \
- (defined CONFIG_HID_SENSOR_ENUM_BASE_QUIRKS_MODULE)
- ++state_val;
-#endif
+ if (IS_ENABLED(CONFIG_HID_SENSOR_ENUM_BASE_QUIRKS))
+ ++state_val;
st->data_ready = state;
sensor_hub_set_feature(st->hsdev, st->power_state.report_id,
st->power_state.index,
diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
index b1c0ee5294ca..f4a6f0838327 100644
--- a/drivers/iio/dac/Kconfig
+++ b/drivers/iio/dac/Kconfig
@@ -67,6 +67,16 @@ config AD5446
To compile this driver as a module, choose M here: the
module will be called ad5446.
+config AD5449
+ tristate "Analog Device AD5449 and similar DACs driver"
+ depends on SPI_MASTER
+ help
+ Say yes here to build support for Analog Devices AD5415, AD5426, AD5429,
+ AD5432, AD5439, AD5443, AD5449 Digital to Analog Converters.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ad5449.
+
config AD5504
tristate "Analog Devices AD5504/AD5501 DAC SPI driver"
depends on SPI
@@ -122,7 +132,7 @@ config AD5686
config MAX517
tristate "Maxim MAX517/518/519 DAC driver"
- depends on I2C && EXPERIMENTAL
+ depends on I2C
help
If you say yes here you get support for the Maxim chips MAX517,
MAX518 and MAX519 (I2C 8-Bit DACs with rail-to-rail outputs).
diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile
index c0d333b23ba3..5b528ebb3343 100644
--- a/drivers/iio/dac/Makefile
+++ b/drivers/iio/dac/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_AD5624R_SPI) += ad5624r_spi.o
obj-$(CONFIG_AD5064) += ad5064.o
obj-$(CONFIG_AD5504) += ad5504.o
obj-$(CONFIG_AD5446) += ad5446.o
+obj-$(CONFIG_AD5449) += ad5449.o
obj-$(CONFIG_AD5755) += ad5755.o
obj-$(CONFIG_AD5764) += ad5764.o
obj-$(CONFIG_AD5791) += ad5791.o
diff --git a/drivers/iio/dac/ad5449.c b/drivers/iio/dac/ad5449.c
new file mode 100644
index 000000000000..0ee6f8eeba8d
--- /dev/null
+++ b/drivers/iio/dac/ad5449.c
@@ -0,0 +1,376 @@
+/*
+ * AD5415, AD5426, AD5429, AD5432, AD5439, AD5443, AD5449 Digital to Analog
+ * Converter driver.
+ *
+ * Copyright 2012 Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/regulator/consumer.h>
+#include <asm/unaligned.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#include <linux/platform_data/ad5449.h>
+
+#define AD5449_MAX_CHANNELS 2
+#define AD5449_MAX_VREFS 2
+
+#define AD5449_CMD_NOOP 0x0
+#define AD5449_CMD_LOAD_AND_UPDATE(x) (0x1 + (x) * 3)
+#define AD5449_CMD_READ(x) (0x2 + (x) * 3)
+#define AD5449_CMD_LOAD(x) (0x3 + (x) * 3)
+#define AD5449_CMD_CTRL 13
+
+#define AD5449_CTRL_SDO_OFFSET 10
+#define AD5449_CTRL_DAISY_CHAIN BIT(9)
+#define AD5449_CTRL_HCLR_TO_MIDSCALE BIT(8)
+#define AD5449_CTRL_SAMPLE_RISING BIT(7)
+
+/**
+ * struct ad5449_chip_info - chip specific information
+ * @channels: Channel specification
+ * @num_channels: Number of channels
+ * @has_ctrl: Chip has a control register
+ */
+struct ad5449_chip_info {
+ const struct iio_chan_spec *channels;
+ unsigned int num_channels;
+ bool has_ctrl;
+};
+
+/**
+ * struct ad5449 - driver instance specific data
+ * @spi: the SPI device for this driver instance
+ * @chip_info: chip model specific constants, available modes etc
+ * @vref_reg: vref supply regulators
+ * @has_sdo: whether the SDO line is connected
+ * @dac_cache: Cache for the DAC values
+ * @data: spi transfer buffers
+ */
+struct ad5449 {
+ struct spi_device *spi;
+ const struct ad5449_chip_info *chip_info;
+ struct regulator_bulk_data vref_reg[AD5449_MAX_VREFS];
+
+ bool has_sdo;
+ uint16_t dac_cache[AD5449_MAX_CHANNELS];
+
+ /*
+ * DMA (thus cache coherency maintenance) requires the
+ * transfer buffers to live in their own cache lines.
+ */
+ __be16 data[2] ____cacheline_aligned;
+};
+
+enum ad5449_type {
+ ID_AD5426,
+ ID_AD5429,
+ ID_AD5432,
+ ID_AD5439,
+ ID_AD5443,
+ ID_AD5449,
+};
+
+static int ad5449_write(struct iio_dev *indio_dev, unsigned int addr,
+ unsigned int val)
+{
+ struct ad5449 *st = iio_priv(indio_dev);
+ int ret;
+
+ mutex_lock(&indio_dev->mlock);
+ st->data[0] = cpu_to_be16((addr << 12) | val);
+ ret = spi_write(st->spi, st->data, 2);
+ mutex_unlock(&indio_dev->mlock);
+
+ return ret;
+}
+
+static int ad5449_read(struct iio_dev *indio_dev, unsigned int addr,
+ unsigned int *val)
+{
+ struct ad5449 *st = iio_priv(indio_dev);
+ int ret;
+ struct spi_message msg;
+ struct spi_transfer t[] = {
+ {
+ .tx_buf = &st->data[0],
+ .len = 2,
+ .cs_change = 1,
+ }, {
+ .tx_buf = &st->data[1],
+ .rx_buf = &st->data[1],
+ .len = 2,
+ },
+ };
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&t[0], &msg);
+ spi_message_add_tail(&t[1], &msg);
+
+ mutex_lock(&indio_dev->mlock);
+ st->data[0] = cpu_to_be16(addr << 12);
+ st->data[1] = cpu_to_be16(AD5449_CMD_NOOP);
+
+ ret = spi_sync(st->spi, &msg);
+ if (ret < 0)
+ goto out_unlock;
+
+ *val = be16_to_cpu(st->data[1]);
+
+out_unlock:
+ mutex_unlock(&indio_dev->mlock);
+ return ret;
+}
+
+static int ad5449_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val, int *val2, long info)
+{
+ struct ad5449 *st = iio_priv(indio_dev);
+ struct regulator_bulk_data *reg;
+ int scale_uv;
+ int ret;
+
+ switch (info) {
+ case IIO_CHAN_INFO_RAW:
+ if (st->has_sdo) {
+ ret = ad5449_read(indio_dev,
+ AD5449_CMD_READ(chan->address), val);
+ if (ret)
+ return ret;
+ *val &= 0xfff;
+ } else {
+ *val = st->dac_cache[chan->address];
+ }
+
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ reg = &st->vref_reg[chan->channel];
+ scale_uv = regulator_get_voltage(reg->consumer);
+ if (scale_uv < 0)
+ return scale_uv;
+
+ *val = scale_uv / 1000;
+ *val2 = chan->scan_type.realbits;
+
+ return IIO_VAL_FRACTIONAL_LOG2;
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static int ad5449_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val, int val2, long info)
+{
+ struct ad5449 *st = iio_priv(indio_dev);
+ int ret;
+
+ switch (info) {
+ case IIO_CHAN_INFO_RAW:
+ if (val < 0 || val >= (1 << chan->scan_type.realbits))
+ return -EINVAL;
+
+ ret = ad5449_write(indio_dev,
+ AD5449_CMD_LOAD_AND_UPDATE(chan->address),
+ val << chan->scan_type.shift);
+ if (ret == 0)
+ st->dac_cache[chan->address] = val;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static const struct iio_info ad5449_info = {
+ .read_raw = ad5449_read_raw,
+ .write_raw = ad5449_write_raw,
+ .driver_module = THIS_MODULE,
+};
+
+#define AD5449_CHANNEL(chan, bits) { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .output = 1, \
+ .channel = (chan), \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
+ .address = (chan), \
+ .scan_type = IIO_ST('u', (bits), 16, 12 - (bits)), \
+}
+
+#define DECLARE_AD5449_CHANNELS(name, bits) \
+const struct iio_chan_spec name[] = { \
+ AD5449_CHANNEL(0, bits), \
+ AD5449_CHANNEL(1, bits), \
+}
+
+static DECLARE_AD5449_CHANNELS(ad5429_channels, 8);
+static DECLARE_AD5449_CHANNELS(ad5439_channels, 10);
+static DECLARE_AD5449_CHANNELS(ad5449_channels, 12);
+
+static const struct ad5449_chip_info ad5449_chip_info[] = {
+ [ID_AD5426] = {
+ .channels = ad5429_channels,
+ .num_channels = 1,
+ .has_ctrl = false,
+ },
+ [ID_AD5429] = {
+ .channels = ad5429_channels,
+ .num_channels = 2,
+ .has_ctrl = true,
+ },
+ [ID_AD5432] = {
+ .channels = ad5439_channels,
+ .num_channels = 1,
+ .has_ctrl = false,
+ },
+ [ID_AD5439] = {
+ .channels = ad5439_channels,
+ .num_channels = 2,
+ .has_ctrl = true,
+ },
+ [ID_AD5443] = {
+ .channels = ad5449_channels,
+ .num_channels = 1,
+ .has_ctrl = false,
+ },
+ [ID_AD5449] = {
+ .channels = ad5449_channels,
+ .num_channels = 2,
+ .has_ctrl = true,
+ },
+};
+
+static const char *ad5449_vref_name(struct ad5449 *st, int n)
+{
+ if (st->chip_info->num_channels == 1)
+ return "VREF";
+
+ if (n == 0)
+ return "VREFA";
+ else
+ return "VREFB";
+}
+
+static int __devinit ad5449_spi_probe(struct spi_device *spi)
+{
+ struct ad5449_platform_data *pdata = spi->dev.platform_data;
+ const struct spi_device_id *id = spi_get_device_id(spi);
+ struct iio_dev *indio_dev;
+ struct ad5449 *st;
+ unsigned int i;
+ int ret;
+
+ indio_dev = iio_device_alloc(sizeof(*st));
+ if (indio_dev == NULL)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+ spi_set_drvdata(spi, indio_dev);
+
+ st->chip_info = &ad5449_chip_info[id->driver_data];
+ st->spi = spi;
+
+ for (i = 0; i < st->chip_info->num_channels; ++i)
+ st->vref_reg[i].supply = ad5449_vref_name(st, i);
+
+ ret = regulator_bulk_get(&spi->dev, st->chip_info->num_channels,
+ st->vref_reg);
+ if (ret)
+ goto error_free;
+
+ ret = regulator_bulk_enable(st->chip_info->num_channels, st->vref_reg);
+ if (ret)
+ goto error_free_reg;
+
+ indio_dev->dev.parent = &spi->dev;
+ indio_dev->name = id->name;
+ indio_dev->info = &ad5449_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = st->chip_info->channels;
+ indio_dev->num_channels = st->chip_info->num_channels;
+
+ if (st->chip_info->has_ctrl) {
+ unsigned int ctrl = 0x00;
+ if (pdata) {
+ if (pdata->hardware_clear_to_midscale)
+ ctrl |= AD5449_CTRL_HCLR_TO_MIDSCALE;
+ ctrl |= pdata->sdo_mode << AD5449_CTRL_SDO_OFFSET;
+ st->has_sdo = pdata->sdo_mode != AD5449_SDO_DISABLED;
+ } else {
+ st->has_sdo = true;
+ }
+ ad5449_write(indio_dev, AD5449_CMD_CTRL, ctrl);
+ }
+
+ ret = iio_device_register(indio_dev);
+ if (ret)
+ goto error_disable_reg;
+
+ return 0;
+
+error_disable_reg:
+ regulator_bulk_disable(st->chip_info->num_channels, st->vref_reg);
+error_free_reg:
+ regulator_bulk_free(st->chip_info->num_channels, st->vref_reg);
+error_free:
+ iio_device_free(indio_dev);
+
+ return ret;
+}
+
+static int __devexit ad5449_spi_remove(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev = spi_get_drvdata(spi);
+ struct ad5449 *st = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+
+ regulator_bulk_disable(st->chip_info->num_channels, st->vref_reg);
+ regulator_bulk_free(st->chip_info->num_channels, st->vref_reg);
+
+ iio_device_free(indio_dev);
+
+ return 0;
+}
+
+static const struct spi_device_id ad5449_spi_ids[] = {
+ { "ad5415", ID_AD5449 },
+ { "ad5426", ID_AD5426 },
+ { "ad5429", ID_AD5429 },
+ { "ad5432", ID_AD5432 },
+ { "ad5439", ID_AD5439 },
+ { "ad5443", ID_AD5443 },
+ { "ad5449", ID_AD5449 },
+ {}
+};
+MODULE_DEVICE_TABLE(spi, ad5449_spi_ids);
+
+static struct spi_driver ad5449_spi_driver = {
+ .driver = {
+ .name = "ad5449",
+ .owner = THIS_MODULE,
+ },
+ .probe = ad5449_spi_probe,
+ .remove = __devexit_p(ad5449_spi_remove),
+ .id_table = ad5449_spi_ids,
+};
+module_spi_driver(ad5449_spi_driver);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("Analog Devices AD5449 and similar DACs");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c
index 6948d75e1036..bc92ff9309c2 100644
--- a/drivers/iio/dac/ad5686.c
+++ b/drivers/iio/dac/ad5686.c
@@ -188,7 +188,7 @@ static ssize_t ad5686_write_dac_powerdown(struct iio_dev *indio_dev,
if (ret)
return ret;
- if (readin == true)
+ if (readin)
st->pwr_down_mask |= (0x3 << (chan->channel * 2));
else
st->pwr_down_mask &= ~(0x3 << (chan->channel * 2));
diff --git a/drivers/iio/gyro/Kconfig b/drivers/iio/gyro/Kconfig
index 21e27e2fc68c..48ed1483ff27 100644
--- a/drivers/iio/gyro/Kconfig
+++ b/drivers/iio/gyro/Kconfig
@@ -3,6 +3,15 @@
#
menu "Digital gyroscope sensors"
+config ADIS16136
+ tristate "Analog devices ADIS16136 and similar gyroscopes driver"
+ depends on SPI_MASTER
+ select IIO_ADIS_LIB
+ select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
+ help
+ Say yes here to build support for the Analog Devices ADIS16133, ADIS16135,
+ ADIS16136 gyroscope devices.
+
config HID_SENSOR_GYRO_3D
depends on HID_SENSOR_HUB
select IIO_BUFFER
diff --git a/drivers/iio/gyro/Makefile b/drivers/iio/gyro/Makefile
index 8a895d9fcbce..702a058907e3 100644
--- a/drivers/iio/gyro/Makefile
+++ b/drivers/iio/gyro/Makefile
@@ -2,4 +2,5 @@
# Makefile for industrial I/O gyroscope sensor drivers
#
+obj-$(CONFIG_ADIS16136) += adis16136.o
obj-$(CONFIG_HID_SENSOR_GYRO_3D) += hid-sensor-gyro-3d.o
diff --git a/drivers/iio/gyro/adis16136.c b/drivers/iio/gyro/adis16136.c
new file mode 100644
index 000000000000..8cb0bcbfd609
--- /dev/null
+++ b/drivers/iio/gyro/adis16136.c
@@ -0,0 +1,580 @@
+/*
+ * ADIS16133/ADIS16135/ADIS16136 gyroscope driver
+ *
+ * Copyright 2012 Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/module.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/imu/adis.h>
+
+#include <linux/debugfs.h>
+
+#define ADIS16136_REG_FLASH_CNT 0x00
+#define ADIS16136_REG_TEMP_OUT 0x02
+#define ADIS16136_REG_GYRO_OUT2 0x04
+#define ADIS16136_REG_GYRO_OUT 0x06
+#define ADIS16136_REG_GYRO_OFF2 0x08
+#define ADIS16136_REG_GYRO_OFF 0x0A
+#define ADIS16136_REG_ALM_MAG1 0x10
+#define ADIS16136_REG_ALM_MAG2 0x12
+#define ADIS16136_REG_ALM_SAMPL1 0x14
+#define ADIS16136_REG_ALM_SAMPL2 0x16
+#define ADIS16136_REG_ALM_CTRL 0x18
+#define ADIS16136_REG_GPIO_CTRL 0x1A
+#define ADIS16136_REG_MSC_CTRL 0x1C
+#define ADIS16136_REG_SMPL_PRD 0x1E
+#define ADIS16136_REG_AVG_CNT 0x20
+#define ADIS16136_REG_DEC_RATE 0x22
+#define ADIS16136_REG_SLP_CTRL 0x24
+#define ADIS16136_REG_DIAG_STAT 0x26
+#define ADIS16136_REG_GLOB_CMD 0x28
+#define ADIS16136_REG_LOT1 0x32
+#define ADIS16136_REG_LOT2 0x34
+#define ADIS16136_REG_LOT3 0x36
+#define ADIS16136_REG_PROD_ID 0x38
+#define ADIS16136_REG_SERIAL_NUM 0x3A
+
+#define ADIS16136_DIAG_STAT_FLASH_UPDATE_FAIL 2
+#define ADIS16136_DIAG_STAT_SPI_FAIL 3
+#define ADIS16136_DIAG_STAT_SELF_TEST_FAIL 5
+#define ADIS16136_DIAG_STAT_FLASH_CHKSUM_FAIL 6
+
+#define ADIS16136_MSC_CTRL_MEMORY_TEST BIT(11)
+#define ADIS16136_MSC_CTRL_SELF_TEST BIT(10)
+
+struct adis16136_chip_info {
+ unsigned int precision;
+ unsigned int fullscale;
+};
+
+struct adis16136 {
+ const struct adis16136_chip_info *chip_info;
+
+ struct adis adis;
+};
+
+#ifdef CONFIG_DEBUG_FS
+
+static ssize_t adis16136_show_serial(struct file *file,
+ char __user *userbuf, size_t count, loff_t *ppos)
+{
+ struct adis16136 *adis16136 = file->private_data;
+ uint16_t lot1, lot2, lot3, serial;
+ char buf[20];
+ size_t len;
+ int ret;
+
+ ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_SERIAL_NUM,
+ &serial);
+ if (ret < 0)
+ return ret;
+
+ ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT1, &lot1);
+ if (ret < 0)
+ return ret;
+
+ ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT2, &lot2);
+ if (ret < 0)
+ return ret;
+
+ ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT3, &lot3);
+ if (ret < 0)
+ return ret;
+
+ len = snprintf(buf, sizeof(buf), "%.4x%.4x%.4x-%.4x\n", lot1, lot2,
+ lot3, serial);
+
+ return simple_read_from_buffer(userbuf, count, ppos, buf, len);
+}
+
+static const struct file_operations adis16136_serial_fops = {
+ .open = simple_open,
+ .read = adis16136_show_serial,
+ .llseek = default_llseek,
+ .owner = THIS_MODULE,
+};
+
+static int adis16136_show_product_id(void *arg, u64 *val)
+{
+ struct adis16136 *adis16136 = arg;
+ u16 prod_id;
+ int ret;
+
+ ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_PROD_ID,
+ &prod_id);
+ if (ret < 0)
+ return ret;
+
+ *val = prod_id;
+
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(adis16136_product_id_fops,
+ adis16136_show_product_id, NULL, "%llu\n");
+
+static int adis16136_show_flash_count(void *arg, u64 *val)
+{
+ struct adis16136 *adis16136 = arg;
+ uint16_t flash_count;
+ int ret;
+
+ ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_FLASH_CNT,
+ &flash_count);
+ if (ret < 0)
+ return ret;
+
+ *val = flash_count;
+
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(adis16136_flash_count_fops,
+ adis16136_show_flash_count, NULL, "%lld\n");
+
+static int adis16136_debugfs_init(struct iio_dev *indio_dev)
+{
+ struct adis16136 *adis16136 = iio_priv(indio_dev);
+
+ debugfs_create_file("serial_number", 0400, indio_dev->debugfs_dentry,
+ adis16136, &adis16136_serial_fops);
+ debugfs_create_file("product_id", 0400, indio_dev->debugfs_dentry,
+ adis16136, &adis16136_product_id_fops);
+ debugfs_create_file("flash_count", 0400, indio_dev->debugfs_dentry,
+ adis16136, &adis16136_flash_count_fops);
+
+ return 0;
+}
+
+#else
+
+static int adis16136_debugfs_init(struct iio_dev *indio_dev)
+{
+ return 0;
+}
+
+#endif
+
+static int adis16136_set_freq(struct adis16136 *adis16136, unsigned int freq)
+{
+ unsigned int t;
+
+ t = 32768 / freq;
+ if (t < 0xf)
+ t = 0xf;
+ else if (t > 0xffff)
+ t = 0xffff;
+ else
+ t--;
+
+ return adis_write_reg_16(&adis16136->adis, ADIS16136_REG_SMPL_PRD, t);
+}
+
+static int adis16136_get_freq(struct adis16136 *adis16136, unsigned int *freq)
+{
+ uint16_t t;
+ int ret;
+
+ ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_SMPL_PRD, &t);
+ if (ret < 0)
+ return ret;
+
+ *freq = 32768 / (t + 1);
+
+ return 0;
+}
+
+static ssize_t adis16136_write_frequency(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct adis16136 *adis16136 = iio_priv(indio_dev);
+ unsigned int val;
+ int ret;
+
+ ret = kstrtouint(buf, 10, &val);
+ if (ret)
+ return ret;
+
+ if (val == 0)
+ return -EINVAL;
+
+ ret = adis16136_set_freq(adis16136, val);
+
+ return ret ? ret : len;
+}
+
+static ssize_t adis16136_read_frequency(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct adis16136 *adis16136 = iio_priv(indio_dev);
+ unsigned int freq;
+ int ret;
+
+ ret = adis16136_get_freq(adis16136, &freq);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%d\n", freq);
+}
+
+static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
+ adis16136_read_frequency,
+ adis16136_write_frequency);
+
+static const unsigned adis16136_3db_divisors[] = {
+ [0] = 2, /* Special case */
+ [1] = 6,
+ [2] = 12,
+ [3] = 25,
+ [4] = 50,
+ [5] = 100,
+ [6] = 200,
+ [7] = 200, /* Not a valid setting */
+};
+
+static int adis16136_set_filter(struct iio_dev *indio_dev, int val)
+{
+ struct adis16136 *adis16136 = iio_priv(indio_dev);
+ unsigned int freq;
+ int i, ret;
+
+ ret = adis16136_get_freq(adis16136, &freq);
+ if (ret < 0)
+ return ret;
+
+ for (i = ARRAY_SIZE(adis16136_3db_divisors) - 1; i >= 1; i--) {
+ if (freq / adis16136_3db_divisors[i] >= val)
+ break;
+ }
+
+ return adis_write_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, i);
+}
+
+static int adis16136_get_filter(struct iio_dev *indio_dev, int *val)
+{
+ struct adis16136 *adis16136 = iio_priv(indio_dev);
+ unsigned int freq;
+ uint16_t val16;
+ int ret;
+
+ mutex_lock(&indio_dev->mlock);
+
+ ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, &val16);
+ if (ret < 0)
+ goto err_unlock;
+
+ ret = adis16136_get_freq(adis16136, &freq);
+ if (ret < 0)
+ goto err_unlock;
+
+ *val = freq / adis16136_3db_divisors[val16 & 0x07];
+
+err_unlock:
+ mutex_unlock(&indio_dev->mlock);
+
+ return ret ? ret : IIO_VAL_INT;
+}
+
+static int adis16136_read_raw(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, int *val, int *val2, long info)
+{
+ struct adis16136 *adis16136 = iio_priv(indio_dev);
+ uint32_t val32;
+ int ret;
+
+ switch (info) {
+ case IIO_CHAN_INFO_RAW:
+ return adis_single_conversion(indio_dev, chan, 0, val);
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->type) {
+ case IIO_ANGL_VEL:
+ *val = adis16136->chip_info->precision;
+ *val2 = (adis16136->chip_info->fullscale << 16);
+ return IIO_VAL_FRACTIONAL;
+ case IIO_TEMP:
+ *val = 10;
+ *val2 = 697000; /* 0.010697 degree Celsius */
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_CALIBBIAS:
+ ret = adis_read_reg_32(&adis16136->adis,
+ ADIS16136_REG_GYRO_OFF2, &val32);
+ if (ret < 0)
+ return ret;
+
+ *val = sign_extend32(val32, 31);
+
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+ return adis16136_get_filter(indio_dev, val);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int adis16136_write_raw(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, int val, int val2, long info)
+{
+ struct adis16136 *adis16136 = iio_priv(indio_dev);
+
+ switch (info) {
+ case IIO_CHAN_INFO_CALIBBIAS:
+ return adis_write_reg_32(&adis16136->adis,
+ ADIS16136_REG_GYRO_OFF2, val);
+ case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+ return adis16136_set_filter(indio_dev, val);
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+enum {
+ ADIS16136_SCAN_GYRO,
+ ADIS16136_SCAN_TEMP,
+};
+
+static const struct iio_chan_spec adis16136_channels[] = {
+ {
+ .type = IIO_ANGL_VEL,
+ .modified = 1,
+ .channel2 = IIO_MOD_X,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT |
+ IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SEPARATE_BIT,
+ .address = ADIS16136_REG_GYRO_OUT2,
+ .scan_index = ADIS16136_SCAN_GYRO,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 32,
+ .storagebits = 32,
+ .endianness = IIO_BE,
+ },
+ }, {
+ .type = IIO_TEMP,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .address = ADIS16136_REG_TEMP_OUT,
+ .scan_index = ADIS16136_SCAN_TEMP,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 16,
+ .storagebits = 16,
+ .endianness = IIO_BE,
+ },
+ },
+ IIO_CHAN_SOFT_TIMESTAMP(2),
+};
+
+static struct attribute *adis16136_attributes[] = {
+ &iio_dev_attr_sampling_frequency.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group adis16136_attribute_group = {
+ .attrs = adis16136_attributes,
+};
+
+static const struct iio_info adis16136_info = {
+ .driver_module = THIS_MODULE,
+ .attrs = &adis16136_attribute_group,
+ .read_raw = &adis16136_read_raw,
+ .write_raw = &adis16136_write_raw,
+ .update_scan_mode = adis_update_scan_mode,
+ .debugfs_reg_access = adis_debugfs_reg_access,
+};
+
+static int adis16136_stop_device(struct iio_dev *indio_dev)
+{
+ struct adis16136 *adis16136 = iio_priv(indio_dev);
+ int ret;
+
+ ret = adis_write_reg_16(&adis16136->adis, ADIS16136_REG_SLP_CTRL, 0xff);
+ if (ret)
+ dev_err(&indio_dev->dev,
+ "Could not power down device: %d\n", ret);
+
+ return ret;
+}
+
+static int adis16136_initial_setup(struct iio_dev *indio_dev)
+{
+ struct adis16136 *adis16136 = iio_priv(indio_dev);
+ unsigned int device_id;
+ uint16_t prod_id;
+ int ret;
+
+ ret = adis_initial_startup(&adis16136->adis);
+ if (ret)
+ return ret;
+
+ ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_PROD_ID,
+ &prod_id);
+ if (ret)
+ return ret;
+
+ sscanf(indio_dev->name, "adis%u\n", &device_id);
+
+ if (prod_id != device_id)
+ dev_warn(&indio_dev->dev, "Device ID(%u) and product ID(%u) do not match.",
+ device_id, prod_id);
+
+ return 0;
+}
+
+static const char * const adis16136_status_error_msgs[] = {
+ [ADIS16136_DIAG_STAT_FLASH_UPDATE_FAIL] = "Flash update failed",
+ [ADIS16136_DIAG_STAT_SPI_FAIL] = "SPI failure",
+ [ADIS16136_DIAG_STAT_SELF_TEST_FAIL] = "Self test error",
+ [ADIS16136_DIAG_STAT_FLASH_CHKSUM_FAIL] = "Flash checksum error",
+};
+
+static const struct adis_data adis16136_data = {
+ .diag_stat_reg = ADIS16136_REG_DIAG_STAT,
+ .glob_cmd_reg = ADIS16136_REG_GLOB_CMD,
+ .msc_ctrl_reg = ADIS16136_REG_MSC_CTRL,
+
+ .self_test_mask = ADIS16136_MSC_CTRL_SELF_TEST,
+ .startup_delay = 80,
+
+ .read_delay = 10,
+ .write_delay = 10,
+
+ .status_error_msgs = adis16136_status_error_msgs,
+ .status_error_mask = BIT(ADIS16136_DIAG_STAT_FLASH_UPDATE_FAIL) |
+ BIT(ADIS16136_DIAG_STAT_SPI_FAIL) |
+ BIT(ADIS16136_DIAG_STAT_SELF_TEST_FAIL) |
+ BIT(ADIS16136_DIAG_STAT_FLASH_CHKSUM_FAIL),
+};
+
+enum adis16136_id {
+ ID_ADIS16133,
+ ID_ADIS16135,
+ ID_ADIS16136,
+};
+
+static const struct adis16136_chip_info adis16136_chip_info[] = {
+ [ID_ADIS16133] = {
+ .precision = IIO_DEGREE_TO_RAD(1200),
+ .fullscale = 24000,
+ },
+ [ID_ADIS16135] = {
+ .precision = IIO_DEGREE_TO_RAD(300),
+ .fullscale = 24000,
+ },
+ [ID_ADIS16136] = {
+ .precision = IIO_DEGREE_TO_RAD(450),
+ .fullscale = 24623,
+ },
+};
+
+static int adis16136_probe(struct spi_device *spi)
+{
+ const struct spi_device_id *id = spi_get_device_id(spi);
+ struct adis16136 *adis16136;
+ struct iio_dev *indio_dev;
+ int ret;
+
+ indio_dev = iio_device_alloc(sizeof(*adis16136));
+ if (indio_dev == NULL)
+ return -ENOMEM;
+
+ spi_set_drvdata(spi, indio_dev);
+
+ adis16136 = iio_priv(indio_dev);
+
+ adis16136->chip_info = &adis16136_chip_info[id->driver_data];
+ indio_dev->dev.parent = &spi->dev;
+ indio_dev->name = spi_get_device_id(spi)->name;
+ indio_dev->channels = adis16136_channels;
+ indio_dev->num_channels = ARRAY_SIZE(adis16136_channels);
+ indio_dev->info = &adis16136_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = adis_init(&adis16136->adis, indio_dev, spi, &adis16136_data);
+ if (ret)
+ goto error_free_dev;
+
+ ret = adis_setup_buffer_and_trigger(&adis16136->adis, indio_dev, NULL);
+ if (ret)
+ goto error_free_dev;
+
+ ret = adis16136_initial_setup(indio_dev);
+ if (ret)
+ goto error_cleanup_buffer;
+
+ ret = iio_device_register(indio_dev);
+ if (ret)
+ goto error_stop_device;
+
+ adis16136_debugfs_init(indio_dev);
+
+ return 0;
+
+error_stop_device:
+ adis16136_stop_device(indio_dev);
+error_cleanup_buffer:
+ adis_cleanup_buffer_and_trigger(&adis16136->adis, indio_dev);
+error_free_dev:
+ iio_device_free(indio_dev);
+ return ret;
+}
+
+static int adis16136_remove(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev = spi_get_drvdata(spi);
+ struct adis16136 *adis16136 = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+ adis16136_stop_device(indio_dev);
+
+ adis_cleanup_buffer_and_trigger(&adis16136->adis, indio_dev);
+
+ iio_device_free(indio_dev);
+
+ return 0;
+}
+
+static const struct spi_device_id adis16136_ids[] = {
+ { "adis16133", ID_ADIS16133 },
+ { "adis16135", ID_ADIS16135 },
+ { "adis16136", ID_ADIS16136 },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, adis16136_ids);
+
+static struct spi_driver adis16136_driver = {
+ .driver = {
+ .name = "adis16136",
+ .owner = THIS_MODULE,
+ },
+ .id_table = adis16136_ids,
+ .probe = adis16136_probe,
+ .remove = adis16136_remove,
+};
+module_spi_driver(adis16136_driver);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("Analog Devices ADIS16133/ADIS16135/ADIS16136 gyroscope driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c
index 4c56ada51c39..4c8b158e40e1 100644
--- a/drivers/iio/gyro/hid-sensor-gyro-3d.c
+++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c
@@ -197,21 +197,8 @@ static const struct iio_info gyro_3d_info = {
/* Function to push data to buffer */
static void hid_sensor_push_data(struct iio_dev *indio_dev, u8 *data, int len)
{
- struct iio_buffer *buffer = indio_dev->buffer;
- int datum_sz;
-
dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n");
- if (!buffer) {
- dev_err(&indio_dev->dev, "Buffer == NULL\n");
- return;
- }
- datum_sz = buffer->access->get_bytes_per_datum(buffer);
- if (len > datum_sz) {
- dev_err(&indio_dev->dev, "Datum size mismatch %d:%d\n", len,
- datum_sz);
- return;
- }
- iio_push_to_buffer(buffer, (u8 *)data);
+ iio_push_to_buffers(indio_dev, (u8 *)data);
}
/* Callback handler to send event after all samples are received and captured */
@@ -319,10 +306,10 @@ static int __devinit hid_gyro_3d_probe(struct platform_device *pdev)
goto error_free_dev;
}
- channels = kmemdup(gyro_3d_channels,
- sizeof(gyro_3d_channels),
- GFP_KERNEL);
+ channels = kmemdup(gyro_3d_channels, sizeof(gyro_3d_channels),
+ GFP_KERNEL);
if (!channels) {
+ ret = -ENOMEM;
dev_err(&pdev->dev, "failed to duplicate channels\n");
goto error_free_dev;
}
diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig
new file mode 100644
index 000000000000..3d79a40e916b
--- /dev/null
+++ b/drivers/iio/imu/Kconfig
@@ -0,0 +1,27 @@
+#
+# IIO imu drivers configuration
+#
+menu "Inertial measurement units"
+
+config ADIS16480
+ tristate "Analog Devices ADIS16480 and similar IMU driver"
+ depends on SPI
+ select IIO_ADIS_LIB
+ select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
+ help
+ Say yes here to build support for Analog Devices ADIS16375, ADIS16480,
+ ADIS16485, ADIS16488 inertial sensors.
+
+endmenu
+
+config IIO_ADIS_LIB
+ tristate
+ help
+ A set of IO helper functions for the Analog Devices ADIS* device family.
+
+config IIO_ADIS_LIB_BUFFER
+ bool
+ select IIO_TRIGGERED_BUFFER
+ help
+ A set of buffer helper functions for the Analog Devices ADIS* device
+ family.
diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile
new file mode 100644
index 000000000000..cfe57638f6f9
--- /dev/null
+++ b/drivers/iio/imu/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for Inertial Measurement Units
+#
+
+obj-$(CONFIG_ADIS16480) += adis16480.o
+
+adis_lib-y += adis.o
+adis_lib-$(CONFIG_IIO_ADIS_LIB_BUFFER) += adis_trigger.o
+adis_lib-$(CONFIG_IIO_ADIS_LIB_BUFFER) += adis_buffer.o
+obj-$(CONFIG_IIO_ADIS_LIB) += adis_lib.o
diff --git a/drivers/iio/imu/adis.c b/drivers/iio/imu/adis.c
new file mode 100644
index 000000000000..911255d41c1a
--- /dev/null
+++ b/drivers/iio/imu/adis.c
@@ -0,0 +1,440 @@
+/*
+ * Common library for ADIS16XXX devices
+ *
+ * Copyright 2012 Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/module.h>
+#include <asm/unaligned.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/imu/adis.h>
+
+#define ADIS_MSC_CTRL_DATA_RDY_EN BIT(2)
+#define ADIS_MSC_CTRL_DATA_RDY_POL_HIGH BIT(1)
+#define ADIS_MSC_CTRL_DATA_RDY_DIO2 BIT(0)
+#define ADIS_GLOB_CMD_SW_RESET BIT(7)
+
+int adis_write_reg(struct adis *adis, unsigned int reg,
+ unsigned int value, unsigned int size)
+{
+ unsigned int page = reg / ADIS_PAGE_SIZE;
+ int ret, i;
+ struct spi_message msg;
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = adis->tx,
+ .bits_per_word = 8,
+ .len = 2,
+ .cs_change = 1,
+ .delay_usecs = adis->data->write_delay,
+ }, {
+ .tx_buf = adis->tx + 2,
+ .bits_per_word = 8,
+ .len = 2,
+ .cs_change = 1,
+ .delay_usecs = adis->data->write_delay,
+ }, {
+ .tx_buf = adis->tx + 4,
+ .bits_per_word = 8,
+ .len = 2,
+ .cs_change = 1,
+ .delay_usecs = adis->data->write_delay,
+ }, {
+ .tx_buf = adis->tx + 6,
+ .bits_per_word = 8,
+ .len = 2,
+ .delay_usecs = adis->data->write_delay,
+ }, {
+ .tx_buf = adis->tx + 8,
+ .bits_per_word = 8,
+ .len = 2,
+ .delay_usecs = adis->data->write_delay,
+ },
+ };
+
+ mutex_lock(&adis->txrx_lock);
+
+ spi_message_init(&msg);
+
+ if (adis->current_page != page) {
+ adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID);
+ adis->tx[1] = page;
+ spi_message_add_tail(&xfers[0], &msg);
+ }
+
+ switch (size) {
+ case 4:
+ adis->tx[8] = ADIS_WRITE_REG(reg + 3);
+ adis->tx[9] = (value >> 24) & 0xff;
+ adis->tx[6] = ADIS_WRITE_REG(reg + 2);
+ adis->tx[7] = (value >> 16) & 0xff;
+ case 2:
+ adis->tx[4] = ADIS_WRITE_REG(reg + 1);
+ adis->tx[5] = (value >> 8) & 0xff;
+ case 1:
+ adis->tx[2] = ADIS_WRITE_REG(reg);
+ adis->tx[3] = value & 0xff;
+ break;
+ default:
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ xfers[size].cs_change = 0;
+
+ for (i = 1; i <= size; i++)
+ spi_message_add_tail(&xfers[i], &msg);
+
+ ret = spi_sync(adis->spi, &msg);
+ if (ret) {
+ dev_err(&adis->spi->dev, "Failed to write register 0x%02X: %d\n",
+ reg, ret);
+ } else {
+ adis->current_page = page;
+ }
+
+out_unlock:
+ mutex_unlock(&adis->txrx_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(adis_write_reg);
+
+/**
+ * adis_read_reg() - read 2 bytes from a 16-bit register
+ * @adis: The adis device
+ * @reg: The address of the lower of the two registers
+ * @val: The value read back from the device
+ */
+int adis_read_reg(struct adis *adis, unsigned int reg,
+ unsigned int *val, unsigned int size)
+{
+ unsigned int page = reg / ADIS_PAGE_SIZE;
+ struct spi_message msg;
+ int ret;
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = adis->tx,
+ .bits_per_word = 8,
+ .len = 2,
+ .cs_change = 1,
+ .delay_usecs = adis->data->write_delay,
+ }, {
+ .tx_buf = adis->tx + 2,
+ .bits_per_word = 8,
+ .len = 2,
+ .cs_change = 1,
+ .delay_usecs = adis->data->read_delay,
+ }, {
+ .tx_buf = adis->tx + 4,
+ .rx_buf = adis->rx,
+ .bits_per_word = 8,
+ .len = 2,
+ .cs_change = 1,
+ .delay_usecs = adis->data->read_delay,
+ }, {
+ .rx_buf = adis->rx + 2,
+ .bits_per_word = 8,
+ .len = 2,
+ .delay_usecs = adis->data->read_delay,
+ },
+ };
+
+ mutex_lock(&adis->txrx_lock);
+ spi_message_init(&msg);
+
+ if (adis->current_page != page) {
+ adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID);
+ adis->tx[1] = page;
+ spi_message_add_tail(&xfers[0], &msg);
+ }
+
+ switch (size) {
+ case 4:
+ adis->tx[2] = ADIS_READ_REG(reg + 2);
+ adis->tx[3] = 0;
+ spi_message_add_tail(&xfers[1], &msg);
+ case 2:
+ adis->tx[4] = ADIS_READ_REG(reg);
+ adis->tx[5] = 0;
+ spi_message_add_tail(&xfers[2], &msg);
+ spi_message_add_tail(&xfers[3], &msg);
+ break;
+ default:
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ ret = spi_sync(adis->spi, &msg);
+ if (ret) {
+ dev_err(&adis->spi->dev, "Failed to read register 0x%02X: %d\n",
+ reg, ret);
+ goto out_unlock;
+ } else {
+ adis->current_page = page;
+ }
+
+ switch (size) {
+ case 4:
+ *val = get_unaligned_be32(adis->rx);
+ break;
+ case 2:
+ *val = get_unaligned_be16(adis->rx + 2);
+ break;
+ }
+
+out_unlock:
+ mutex_unlock(&adis->txrx_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(adis_read_reg);
+
+#ifdef CONFIG_DEBUG_FS
+
+int adis_debugfs_reg_access(struct iio_dev *indio_dev,
+ unsigned int reg, unsigned int writeval, unsigned int *readval)
+{
+ struct adis *adis = iio_device_get_drvdata(indio_dev);
+
+ if (readval) {
+ uint16_t val16;
+ int ret;
+
+ ret = adis_read_reg_16(adis, reg, &val16);
+ *readval = val16;
+
+ return ret;
+ } else {
+ return adis_write_reg_16(adis, reg, writeval);
+ }
+}
+EXPORT_SYMBOL(adis_debugfs_reg_access);
+
+#endif
+
+/**
+ * adis_enable_irq() - Enable or disable data ready IRQ
+ * @adis: The adis device
+ * @enable: Whether to enable the IRQ
+ *
+ * Returns 0 on success, negative error code otherwise
+ */
+int adis_enable_irq(struct adis *adis, bool enable)
+{
+ int ret = 0;
+ uint16_t msc;
+
+ if (adis->data->enable_irq)
+ return adis->data->enable_irq(adis, enable);
+
+ ret = adis_read_reg_16(adis, adis->data->msc_ctrl_reg, &msc);
+ if (ret)
+ goto error_ret;
+
+ msc |= ADIS_MSC_CTRL_DATA_RDY_POL_HIGH;
+ msc &= ~ADIS_MSC_CTRL_DATA_RDY_DIO2;
+ if (enable)
+ msc |= ADIS_MSC_CTRL_DATA_RDY_EN;
+ else
+ msc &= ~ADIS_MSC_CTRL_DATA_RDY_EN;
+
+ ret = adis_write_reg_16(adis, adis->data->msc_ctrl_reg, msc);
+
+error_ret:
+ return ret;
+}
+EXPORT_SYMBOL(adis_enable_irq);
+
+/**
+ * adis_check_status() - Check the device for error conditions
+ * @adis: The adis device
+ *
+ * Returns 0 on success, a negative error code otherwise
+ */
+int adis_check_status(struct adis *adis)
+{
+ uint16_t status;
+ int ret;
+ int i;
+
+ ret = adis_read_reg_16(adis, adis->data->diag_stat_reg, &status);
+ if (ret < 0)
+ return ret;
+
+ status &= adis->data->status_error_mask;
+
+ if (status == 0)
+ return 0;
+
+ for (i = 0; i < 16; ++i) {
+ if (status & BIT(i)) {
+ dev_err(&adis->spi->dev, "%s.\n",
+ adis->data->status_error_msgs[i]);
+ }
+ }
+
+ return -EIO;
+}
+EXPORT_SYMBOL_GPL(adis_check_status);
+
+/**
+ * adis_reset() - Reset the device
+ * @adis: The adis device
+ *
+ * Returns 0 on success, a negative error code otherwise
+ */
+int adis_reset(struct adis *adis)
+{
+ int ret;
+
+ ret = adis_write_reg_8(adis, adis->data->glob_cmd_reg,
+ ADIS_GLOB_CMD_SW_RESET);
+ if (ret)
+ dev_err(&adis->spi->dev, "Failed to reset device: %d\n", ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(adis_reset);
+
+static int adis_self_test(struct adis *adis)
+{
+ int ret;
+
+ ret = adis_write_reg_16(adis, adis->data->msc_ctrl_reg,
+ adis->data->self_test_mask);
+ if (ret) {
+ dev_err(&adis->spi->dev, "Failed to initiate self test: %d\n",
+ ret);
+ return ret;
+ }
+
+ msleep(adis->data->startup_delay);
+
+ return adis_check_status(adis);
+}
+
+/**
+ * adis_inital_startup() - Performs device self-test
+ * @adis: The adis device
+ *
+ * Returns 0 if the device is operational, a negative error code otherwise.
+ *
+ * This function should be called early on in the device initialization sequence
+ * to ensure that the device is in a sane and known state and that it is usable.
+ */
+int adis_initial_startup(struct adis *adis)
+{
+ int ret;
+
+ ret = adis_self_test(adis);
+ if (ret) {
+ dev_err(&adis->spi->dev, "Self-test failed, trying reset.\n");
+ adis_reset(adis);
+ msleep(adis->data->startup_delay);
+ ret = adis_self_test(adis);
+ if (ret) {
+ dev_err(&adis->spi->dev, "Second self-test failed, giving up.\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(adis_initial_startup);
+
+/**
+ * adis_single_conversion() - Performs a single sample conversion
+ * @indio_dev: The IIO device
+ * @chan: The IIO channel
+ * @error_mask: Mask for the error bit
+ * @val: Result of the conversion
+ *
+ * Returns IIO_VAL_INT on success, a negative error code otherwise.
+ *
+ * The function performs a single conversion on a given channel and post
+ * processes the value accordingly to the channel spec. If a error_mask is given
+ * the function will check if the mask is set in the returned raw value. If it
+ * is set the function will perform a self-check. If the device does not report
+ * a error bit in the channels raw value set error_mask to 0.
+ */
+int adis_single_conversion(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, unsigned int error_mask, int *val)
+{
+ struct adis *adis = iio_device_get_drvdata(indio_dev);
+ unsigned int uval;
+ int ret;
+
+ mutex_lock(&indio_dev->mlock);
+
+ ret = adis_read_reg(adis, chan->address, &uval,
+ chan->scan_type.storagebits / 8);
+ if (ret)
+ goto err_unlock;
+
+ if (uval & error_mask) {
+ ret = adis_check_status(adis);
+ if (ret)
+ goto err_unlock;
+ }
+
+ if (chan->scan_type.sign == 's')
+ *val = sign_extend32(uval, chan->scan_type.realbits - 1);
+ else
+ *val = uval & ((1 << chan->scan_type.realbits) - 1);
+
+ ret = IIO_VAL_INT;
+err_unlock:
+ mutex_unlock(&indio_dev->mlock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(adis_single_conversion);
+
+/**
+ * adis_init() - Initialize adis device structure
+ * @adis: The adis device
+ * @indio_dev: The iio device
+ * @spi: The spi device
+ * @data: Chip specific data
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ *
+ * This function must be called, before any other adis helper function may be
+ * called.
+ */
+int adis_init(struct adis *adis, struct iio_dev *indio_dev,
+ struct spi_device *spi, const struct adis_data *data)
+{
+ mutex_init(&adis->txrx_lock);
+ adis->spi = spi;
+ adis->data = data;
+ iio_device_set_drvdata(indio_dev, adis);
+
+ if (data->has_paging) {
+ /* Need to set the page before first read/write */
+ adis->current_page = -1;
+ } else {
+ /* Page will always be 0 */
+ adis->current_page = 0;
+ }
+
+ return adis_enable_irq(adis, false);
+}
+EXPORT_SYMBOL_GPL(adis_init);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("Common library code for ADIS16XXX devices");
diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c
new file mode 100644
index 000000000000..8c26a5f7cd5d
--- /dev/null
+++ b/drivers/iio/imu/adis16480.c
@@ -0,0 +1,924 @@
+/*
+ * ADIS16480 and similar IMUs driver
+ *
+ * Copyright 2012 Analog Devices Inc.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/module.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/imu/adis.h>
+
+#include <linux/debugfs.h>
+
+#define ADIS16480_PAGE_SIZE 0x80
+
+#define ADIS16480_REG(page, reg) ((page) * ADIS16480_PAGE_SIZE + (reg))
+
+#define ADIS16480_REG_PAGE_ID 0x00 /* Same address on each page */
+#define ADIS16480_REG_SEQ_CNT ADIS16480_REG(0x00, 0x06)
+#define ADIS16480_REG_SYS_E_FLA ADIS16480_REG(0x00, 0x08)
+#define ADIS16480_REG_DIAG_STS ADIS16480_REG(0x00, 0x0A)
+#define ADIS16480_REG_ALM_STS ADIS16480_REG(0x00, 0x0C)
+#define ADIS16480_REG_TEMP_OUT ADIS16480_REG(0x00, 0x0E)
+#define ADIS16480_REG_X_GYRO_OUT ADIS16480_REG(0x00, 0x10)
+#define ADIS16480_REG_Y_GYRO_OUT ADIS16480_REG(0x00, 0x14)
+#define ADIS16480_REG_Z_GYRO_OUT ADIS16480_REG(0x00, 0x18)
+#define ADIS16480_REG_X_ACCEL_OUT ADIS16480_REG(0x00, 0x1C)
+#define ADIS16480_REG_Y_ACCEL_OUT ADIS16480_REG(0x00, 0x20)
+#define ADIS16480_REG_Z_ACCEL_OUT ADIS16480_REG(0x00, 0x24)
+#define ADIS16480_REG_X_MAGN_OUT ADIS16480_REG(0x00, 0x28)
+#define ADIS16480_REG_Y_MAGN_OUT ADIS16480_REG(0x00, 0x2A)
+#define ADIS16480_REG_Z_MAGN_OUT ADIS16480_REG(0x00, 0x2C)
+#define ADIS16480_REG_BAROM_OUT ADIS16480_REG(0x00, 0x2E)
+#define ADIS16480_REG_X_DELTAANG_OUT ADIS16480_REG(0x00, 0x40)
+#define ADIS16480_REG_Y_DELTAANG_OUT ADIS16480_REG(0x00, 0x44)
+#define ADIS16480_REG_Z_DELTAANG_OUT ADIS16480_REG(0x00, 0x48)
+#define ADIS16480_REG_X_DELTAVEL_OUT ADIS16480_REG(0x00, 0x4C)
+#define ADIS16480_REG_Y_DELTAVEL_OUT ADIS16480_REG(0x00, 0x50)
+#define ADIS16480_REG_Z_DELTAVEL_OUT ADIS16480_REG(0x00, 0x54)
+#define ADIS16480_REG_PROD_ID ADIS16480_REG(0x00, 0x7E)
+
+#define ADIS16480_REG_X_GYRO_SCALE ADIS16480_REG(0x02, 0x04)
+#define ADIS16480_REG_Y_GYRO_SCALE ADIS16480_REG(0x02, 0x06)
+#define ADIS16480_REG_Z_GYRO_SCALE ADIS16480_REG(0x02, 0x08)
+#define ADIS16480_REG_X_ACCEL_SCALE ADIS16480_REG(0x02, 0x0A)
+#define ADIS16480_REG_Y_ACCEL_SCALE ADIS16480_REG(0x02, 0x0C)
+#define ADIS16480_REG_Z_ACCEL_SCALE ADIS16480_REG(0x02, 0x0E)
+#define ADIS16480_REG_X_GYRO_BIAS ADIS16480_REG(0x02, 0x10)
+#define ADIS16480_REG_Y_GYRO_BIAS ADIS16480_REG(0x02, 0x14)
+#define ADIS16480_REG_Z_GYRO_BIAS ADIS16480_REG(0x02, 0x18)
+#define ADIS16480_REG_X_ACCEL_BIAS ADIS16480_REG(0x02, 0x1C)
+#define ADIS16480_REG_Y_ACCEL_BIAS ADIS16480_REG(0x02, 0x20)
+#define ADIS16480_REG_Z_ACCEL_BIAS ADIS16480_REG(0x02, 0x24)
+#define ADIS16480_REG_X_HARD_IRON ADIS16480_REG(0x02, 0x28)
+#define ADIS16480_REG_Y_HARD_IRON ADIS16480_REG(0x02, 0x2A)
+#define ADIS16480_REG_Z_HARD_IRON ADIS16480_REG(0x02, 0x2C)
+#define ADIS16480_REG_BAROM_BIAS ADIS16480_REG(0x02, 0x40)
+#define ADIS16480_REG_FLASH_CNT ADIS16480_REG(0x02, 0x7C)
+
+#define ADIS16480_REG_GLOB_CMD ADIS16480_REG(0x03, 0x02)
+#define ADIS16480_REG_FNCTIO_CTRL ADIS16480_REG(0x03, 0x06)
+#define ADIS16480_REG_GPIO_CTRL ADIS16480_REG(0x03, 0x08)
+#define ADIS16480_REG_CONFIG ADIS16480_REG(0x03, 0x0A)
+#define ADIS16480_REG_DEC_RATE ADIS16480_REG(0x03, 0x0C)
+#define ADIS16480_REG_SLP_CNT ADIS16480_REG(0x03, 0x10)
+#define ADIS16480_REG_FILTER_BNK0 ADIS16480_REG(0x03, 0x16)
+#define ADIS16480_REG_FILTER_BNK1 ADIS16480_REG(0x03, 0x18)
+#define ADIS16480_REG_ALM_CNFG0 ADIS16480_REG(0x03, 0x20)
+#define ADIS16480_REG_ALM_CNFG1 ADIS16480_REG(0x03, 0x22)
+#define ADIS16480_REG_ALM_CNFG2 ADIS16480_REG(0x03, 0x24)
+#define ADIS16480_REG_XG_ALM_MAGN ADIS16480_REG(0x03, 0x28)
+#define ADIS16480_REG_YG_ALM_MAGN ADIS16480_REG(0x03, 0x2A)
+#define ADIS16480_REG_ZG_ALM_MAGN ADIS16480_REG(0x03, 0x2C)
+#define ADIS16480_REG_XA_ALM_MAGN ADIS16480_REG(0x03, 0x2E)
+#define ADIS16480_REG_YA_ALM_MAGN ADIS16480_REG(0x03, 0x30)
+#define ADIS16480_REG_ZA_ALM_MAGN ADIS16480_REG(0x03, 0x32)
+#define ADIS16480_REG_XM_ALM_MAGN ADIS16480_REG(0x03, 0x34)
+#define ADIS16480_REG_YM_ALM_MAGN ADIS16480_REG(0x03, 0x36)
+#define ADIS16480_REG_ZM_ALM_MAGN ADIS16480_REG(0x03, 0x38)
+#define ADIS16480_REG_BR_ALM_MAGN ADIS16480_REG(0x03, 0x3A)
+#define ADIS16480_REG_FIRM_REV ADIS16480_REG(0x03, 0x78)
+#define ADIS16480_REG_FIRM_DM ADIS16480_REG(0x03, 0x7A)
+#define ADIS16480_REG_FIRM_Y ADIS16480_REG(0x03, 0x7C)
+
+#define ADIS16480_REG_SERIAL_NUM ADIS16480_REG(0x04, 0x20)
+
+/* Each filter coefficent bank spans two pages */
+#define ADIS16480_FIR_COEF(page) (x < 60 ? ADIS16480_REG(page, (x) + 8) : \
+ ADIS16480_REG((page) + 1, (x) - 60 + 8))
+#define ADIS16480_FIR_COEF_A(x) ADIS16480_FIR_COEF(0x05, (x))
+#define ADIS16480_FIR_COEF_B(x) ADIS16480_FIR_COEF(0x07, (x))
+#define ADIS16480_FIR_COEF_C(x) ADIS16480_FIR_COEF(0x09, (x))
+#define ADIS16480_FIR_COEF_D(x) ADIS16480_FIR_COEF(0x0B, (x))
+
+struct adis16480_chip_info {
+ unsigned int num_channels;
+ const struct iio_chan_spec *channels;
+};
+
+struct adis16480 {
+ const struct adis16480_chip_info *chip_info;
+
+ struct adis adis;
+};
+
+#ifdef CONFIG_DEBUG_FS
+
+static ssize_t adis16480_show_firmware_revision(struct file *file,
+ char __user *userbuf, size_t count, loff_t *ppos)
+{
+ struct adis16480 *adis16480 = file->private_data;
+ char buf[7];
+ size_t len;
+ u16 rev;
+ int ret;
+
+ ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_FIRM_REV, &rev);
+ if (ret < 0)
+ return ret;
+
+ len = scnprintf(buf, sizeof(buf), "%x.%x\n", rev >> 8, rev & 0xff);
+
+ return simple_read_from_buffer(userbuf, count, ppos, buf, len);
+}
+
+static const struct file_operations adis16480_firmware_revision_fops = {
+ .open = simple_open,
+ .read = adis16480_show_firmware_revision,
+ .llseek = default_llseek,
+ .owner = THIS_MODULE,
+};
+
+static ssize_t adis16480_show_firmware_date(struct file *file,
+ char __user *userbuf, size_t count, loff_t *ppos)
+{
+ struct adis16480 *adis16480 = file->private_data;
+ u16 md, year;
+ char buf[12];
+ size_t len;
+ int ret;
+
+ ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_FIRM_Y, &year);
+ if (ret < 0)
+ return ret;
+
+ ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_FIRM_DM, &md);
+ if (ret < 0)
+ return ret;
+
+ len = snprintf(buf, sizeof(buf), "%.2x-%.2x-%.4x\n",
+ md >> 8, md & 0xff, year);
+
+ return simple_read_from_buffer(userbuf, count, ppos, buf, len);
+}
+
+static const struct file_operations adis16480_firmware_date_fops = {
+ .open = simple_open,
+ .read = adis16480_show_firmware_date,
+ .llseek = default_llseek,
+ .owner = THIS_MODULE,
+};
+
+static int adis16480_show_serial_number(void *arg, u64 *val)
+{
+ struct adis16480 *adis16480 = arg;
+ u16 serial;
+ int ret;
+
+ ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_SERIAL_NUM,
+ &serial);
+ if (ret < 0)
+ return ret;
+
+ *val = serial;
+
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(adis16480_serial_number_fops,
+ adis16480_show_serial_number, NULL, "0x%.4llx\n");
+
+static int adis16480_show_product_id(void *arg, u64 *val)
+{
+ struct adis16480 *adis16480 = arg;
+ u16 prod_id;
+ int ret;
+
+ ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_PROD_ID,
+ &prod_id);
+ if (ret < 0)
+ return ret;
+
+ *val = prod_id;
+
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(adis16480_product_id_fops,
+ adis16480_show_product_id, NULL, "%llu\n");
+
+static int adis16480_show_flash_count(void *arg, u64 *val)
+{
+ struct adis16480 *adis16480 = arg;
+ u32 flash_count;
+ int ret;
+
+ ret = adis_read_reg_32(&adis16480->adis, ADIS16480_REG_FLASH_CNT,
+ &flash_count);
+ if (ret < 0)
+ return ret;
+
+ *val = flash_count;
+
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(adis16480_flash_count_fops,
+ adis16480_show_flash_count, NULL, "%lld\n");
+
+static int adis16480_debugfs_init(struct iio_dev *indio_dev)
+{
+ struct adis16480 *adis16480 = iio_priv(indio_dev);
+
+ debugfs_create_file("firmware_revision", 0400,
+ indio_dev->debugfs_dentry, adis16480,
+ &adis16480_firmware_revision_fops);
+ debugfs_create_file("firmware_date", 0400, indio_dev->debugfs_dentry,
+ adis16480, &adis16480_firmware_date_fops);
+ debugfs_create_file("serial_number", 0400, indio_dev->debugfs_dentry,
+ adis16480, &adis16480_serial_number_fops);
+ debugfs_create_file("product_id", 0400, indio_dev->debugfs_dentry,
+ adis16480, &adis16480_product_id_fops);
+ debugfs_create_file("flash_count", 0400, indio_dev->debugfs_dentry,
+ adis16480, &adis16480_flash_count_fops);
+
+ return 0;
+}
+
+#else
+
+static int adis16480_debugfs_init(struct iio_dev *indio_dev)
+{
+ return 0;
+}
+
+#endif
+
+static int adis16480_set_freq(struct adis16480 *st, unsigned int freq)
+{
+ unsigned int t;
+
+ t = 2460000 / freq;
+ if (t > 2048)
+ t = 2048;
+
+ if (t != 0)
+ t--;
+
+ return adis_write_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, t);
+}
+
+static int adis16480_get_freq(struct adis16480 *st, unsigned int *freq)
+{
+ uint16_t t;
+ int ret;
+
+ ret = adis_read_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, &t);
+ if (ret < 0)
+ return ret;
+
+ *freq = 2460000 / (t + 1);
+
+ return 0;
+}
+
+static ssize_t adis16480_read_frequency(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct adis16480 *st = iio_priv(indio_dev);
+ unsigned int freq;
+ int ret;
+
+ ret = adis16480_get_freq(st, &freq);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%d.%.3d\n", freq / 1000, freq % 1000);
+}
+
+static ssize_t adis16480_write_frequency(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct adis16480 *st = iio_priv(indio_dev);
+ int freq_int, freq_fract;
+ long val;
+ int ret;
+
+ ret = iio_str_to_fixpoint(buf, 100, &freq_int, &freq_fract);
+ if (ret)
+ return ret;
+
+ val = freq_int * 1000 + freq_fract;
+
+ if (val <= 0)
+ return -EINVAL;
+
+ ret = adis16480_set_freq(st, val);
+
+ return ret ? ret : len;
+}
+
+static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
+ adis16480_read_frequency,
+ adis16480_write_frequency);
+
+enum {
+ ADIS16480_SCAN_GYRO_X,
+ ADIS16480_SCAN_GYRO_Y,
+ ADIS16480_SCAN_GYRO_Z,
+ ADIS16480_SCAN_ACCEL_X,
+ ADIS16480_SCAN_ACCEL_Y,
+ ADIS16480_SCAN_ACCEL_Z,
+ ADIS16480_SCAN_MAGN_X,
+ ADIS16480_SCAN_MAGN_Y,
+ ADIS16480_SCAN_MAGN_Z,
+ ADIS16480_SCAN_BARO,
+ ADIS16480_SCAN_TEMP,
+};
+
+static const unsigned int adis16480_calibbias_regs[] = {
+ [ADIS16480_SCAN_GYRO_X] = ADIS16480_REG_X_GYRO_BIAS,
+ [ADIS16480_SCAN_GYRO_Y] = ADIS16480_REG_Y_GYRO_BIAS,
+ [ADIS16480_SCAN_GYRO_Z] = ADIS16480_REG_Z_GYRO_BIAS,
+ [ADIS16480_SCAN_ACCEL_X] = ADIS16480_REG_X_ACCEL_BIAS,
+ [ADIS16480_SCAN_ACCEL_Y] = ADIS16480_REG_Y_ACCEL_BIAS,
+ [ADIS16480_SCAN_ACCEL_Z] = ADIS16480_REG_Z_ACCEL_BIAS,
+ [ADIS16480_SCAN_MAGN_X] = ADIS16480_REG_X_HARD_IRON,
+ [ADIS16480_SCAN_MAGN_Y] = ADIS16480_REG_Y_HARD_IRON,
+ [ADIS16480_SCAN_MAGN_Z] = ADIS16480_REG_Z_HARD_IRON,
+ [ADIS16480_SCAN_BARO] = ADIS16480_REG_BAROM_BIAS,
+};
+
+static const unsigned int adis16480_calibscale_regs[] = {
+ [ADIS16480_SCAN_GYRO_X] = ADIS16480_REG_X_GYRO_SCALE,
+ [ADIS16480_SCAN_GYRO_Y] = ADIS16480_REG_Y_GYRO_SCALE,
+ [ADIS16480_SCAN_GYRO_Z] = ADIS16480_REG_Z_GYRO_SCALE,
+ [ADIS16480_SCAN_ACCEL_X] = ADIS16480_REG_X_ACCEL_SCALE,
+ [ADIS16480_SCAN_ACCEL_Y] = ADIS16480_REG_Y_ACCEL_SCALE,
+ [ADIS16480_SCAN_ACCEL_Z] = ADIS16480_REG_Z_ACCEL_SCALE,
+};
+
+static int adis16480_set_calibbias(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, int bias)
+{
+ unsigned int reg = adis16480_calibbias_regs[chan->scan_index];
+ struct adis16480 *st = iio_priv(indio_dev);
+
+ switch (chan->type) {
+ case IIO_MAGN:
+ case IIO_PRESSURE:
+ if (bias < -0x8000 || bias >= 0x8000)
+ return -EINVAL;
+ return adis_write_reg_16(&st->adis, reg, bias);
+ case IIO_ANGL_VEL:
+ case IIO_ACCEL:
+ return adis_write_reg_32(&st->adis, reg, bias);
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static int adis16480_get_calibbias(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, int *bias)
+{
+ unsigned int reg = adis16480_calibbias_regs[chan->scan_index];
+ struct adis16480 *st = iio_priv(indio_dev);
+ uint16_t val16;
+ uint32_t val32;
+ int ret;
+
+ switch (chan->type) {
+ case IIO_MAGN:
+ case IIO_PRESSURE:
+ ret = adis_read_reg_16(&st->adis, reg, &val16);
+ *bias = sign_extend32(val16, 15);
+ break;
+ case IIO_ANGL_VEL:
+ case IIO_ACCEL:
+ ret = adis_read_reg_32(&st->adis, reg, &val32);
+ *bias = sign_extend32(val32, 31);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ if (ret < 0)
+ return ret;
+
+ return IIO_VAL_INT;
+}
+
+static int adis16480_set_calibscale(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, int scale)
+{
+ unsigned int reg = adis16480_calibscale_regs[chan->scan_index];
+ struct adis16480 *st = iio_priv(indio_dev);
+
+ if (scale < -0x8000 || scale >= 0x8000)
+ return -EINVAL;
+
+ return adis_write_reg_16(&st->adis, reg, scale);
+}
+
+static int adis16480_get_calibscale(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, int *scale)
+{
+ unsigned int reg = adis16480_calibscale_regs[chan->scan_index];
+ struct adis16480 *st = iio_priv(indio_dev);
+ uint16_t val16;
+ int ret;
+
+ ret = adis_read_reg_16(&st->adis, reg, &val16);
+ if (ret < 0)
+ return ret;
+
+ *scale = sign_extend32(val16, 15);
+ return IIO_VAL_INT;
+}
+
+static const unsigned int adis16480_def_filter_freqs[] = {
+ 310,
+ 55,
+ 275,
+ 63,
+};
+
+static const unsigned int ad16480_filter_data[][2] = {
+ [ADIS16480_SCAN_GYRO_X] = { ADIS16480_REG_FILTER_BNK0, 0 },
+ [ADIS16480_SCAN_GYRO_Y] = { ADIS16480_REG_FILTER_BNK0, 3 },
+ [ADIS16480_SCAN_GYRO_Z] = { ADIS16480_REG_FILTER_BNK0, 6 },
+ [ADIS16480_SCAN_ACCEL_X] = { ADIS16480_REG_FILTER_BNK0, 9 },
+ [ADIS16480_SCAN_ACCEL_Y] = { ADIS16480_REG_FILTER_BNK0, 12 },
+ [ADIS16480_SCAN_ACCEL_Z] = { ADIS16480_REG_FILTER_BNK1, 0 },
+ [ADIS16480_SCAN_MAGN_X] = { ADIS16480_REG_FILTER_BNK1, 3 },
+ [ADIS16480_SCAN_MAGN_Y] = { ADIS16480_REG_FILTER_BNK1, 6 },
+ [ADIS16480_SCAN_MAGN_Z] = { ADIS16480_REG_FILTER_BNK1, 9 },
+};
+
+static int adis16480_get_filter_freq(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, int *freq)
+{
+ struct adis16480 *st = iio_priv(indio_dev);
+ unsigned int enable_mask, offset, reg;
+ uint16_t val;
+ int ret;
+
+ reg = ad16480_filter_data[chan->scan_index][0];
+ offset = ad16480_filter_data[chan->scan_index][1];
+ enable_mask = BIT(offset + 2);
+
+ ret = adis_read_reg_16(&st->adis, reg, &val);
+ if (ret < 0)
+ return ret;
+
+ if (!(val & enable_mask))
+ *freq = 0;
+ else
+ *freq = adis16480_def_filter_freqs[(val >> offset) & 0x3];
+
+ return IIO_VAL_INT;
+}
+
+static int adis16480_set_filter_freq(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, unsigned int freq)
+{
+ struct adis16480 *st = iio_priv(indio_dev);
+ unsigned int enable_mask, offset, reg;
+ unsigned int diff, best_diff;
+ unsigned int i, best_freq;
+ uint16_t val;
+ int ret;
+
+ reg = ad16480_filter_data[chan->scan_index][0];
+ offset = ad16480_filter_data[chan->scan_index][1];
+ enable_mask = BIT(offset + 2);
+
+ ret = adis_read_reg_16(&st->adis, reg, &val);
+ if (ret < 0)
+ return ret;
+
+ if (freq == 0) {
+ val &= ~enable_mask;
+ } else {
+ best_freq = 0;
+ best_diff = 310;
+ for (i = 0; i < ARRAY_SIZE(adis16480_def_filter_freqs); i++) {
+ if (adis16480_def_filter_freqs[i] >= freq) {
+ diff = adis16480_def_filter_freqs[i] - freq;
+ if (diff < best_diff) {
+ best_diff = diff;
+ best_freq = i;
+ }
+ }
+ }
+
+ val &= ~(0x3 << offset);
+ val |= best_freq << offset;
+ val |= enable_mask;
+ }
+
+ return adis_write_reg_16(&st->adis, reg, val);
+}
+
+static int adis16480_read_raw(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, int *val, int *val2, long info)
+{
+ switch (info) {
+ case IIO_CHAN_INFO_RAW:
+ return adis_single_conversion(indio_dev, chan, 0, val);
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->type) {
+ case IIO_ANGL_VEL:
+ *val = 0;
+ *val2 = IIO_DEGREE_TO_RAD(20000); /* 0.02 degree/sec */
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_ACCEL:
+ *val = 0;
+ *val2 = IIO_G_TO_M_S_2(800); /* 0.8 mg */
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_MAGN:
+ *val = 0;
+ *val2 = 100; /* 0.0001 gauss */
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_TEMP:
+ *val = 5;
+ *val2 = 650000; /* 5.65 milli degree Celsius */
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_PRESSURE:
+ *val = 0;
+ *val2 = 4000; /* 40ubar = 0.004 kPa */
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_OFFSET:
+ /* Only the temperature channel has a offset */
+ *val = 4425; /* 25 degree Celsius = 0x0000 */
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_CALIBBIAS:
+ return adis16480_get_calibbias(indio_dev, chan, val);
+ case IIO_CHAN_INFO_CALIBSCALE:
+ return adis16480_get_calibscale(indio_dev, chan, val);
+ case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+ return adis16480_get_filter_freq(indio_dev, chan, val);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int adis16480_write_raw(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, int val, int val2, long info)
+{
+ switch (info) {
+ case IIO_CHAN_INFO_CALIBBIAS:
+ return adis16480_set_calibbias(indio_dev, chan, val);
+ case IIO_CHAN_INFO_CALIBSCALE:
+ return adis16480_set_calibscale(indio_dev, chan, val);
+ case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+ return adis16480_set_filter_freq(indio_dev, chan, val);
+ default:
+ return -EINVAL;
+ }
+}
+
+#define ADIS16480_MOD_CHANNEL(_type, _mod, _address, _si, _info, _bits) \
+ { \
+ .type = (_type), \
+ .modified = 1, \
+ .channel2 = (_mod), \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT | \
+ _info, \
+ .address = (_address), \
+ .scan_index = (_si), \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = (_bits), \
+ .storagebits = (_bits), \
+ .endianness = IIO_BE, \
+ }, \
+ }
+
+#define ADIS16480_GYRO_CHANNEL(_mod) \
+ ADIS16480_MOD_CHANNEL(IIO_ANGL_VEL, IIO_MOD_ ## _mod, \
+ ADIS16480_REG_ ## _mod ## _GYRO_OUT, ADIS16480_SCAN_GYRO_ ## _mod, \
+ IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SEPARATE_BIT | \
+ IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT, \
+ 32)
+
+#define ADIS16480_ACCEL_CHANNEL(_mod) \
+ ADIS16480_MOD_CHANNEL(IIO_ACCEL, IIO_MOD_ ## _mod, \
+ ADIS16480_REG_ ## _mod ## _ACCEL_OUT, ADIS16480_SCAN_ACCEL_ ## _mod, \
+ IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SEPARATE_BIT | \
+ IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT, \
+ 32)
+
+#define ADIS16480_MAGN_CHANNEL(_mod) \
+ ADIS16480_MOD_CHANNEL(IIO_MAGN, IIO_MOD_ ## _mod, \
+ ADIS16480_REG_ ## _mod ## _MAGN_OUT, ADIS16480_SCAN_MAGN_ ## _mod, \
+ IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SEPARATE_BIT, \
+ 16)
+
+#define ADIS16480_PRESSURE_CHANNEL() \
+ { \
+ .type = IIO_PRESSURE, \
+ .indexed = 1, \
+ .channel = 0, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
+ .address = ADIS16480_REG_BAROM_OUT, \
+ .scan_index = ADIS16480_SCAN_BARO, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = 32, \
+ .storagebits = 32, \
+ .endianness = IIO_BE, \
+ }, \
+ }
+
+#define ADIS16480_TEMP_CHANNEL() { \
+ .type = IIO_TEMP, \
+ .indexed = 1, \
+ .channel = 0, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT | \
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT, \
+ .address = ADIS16480_REG_TEMP_OUT, \
+ .scan_index = ADIS16480_SCAN_TEMP, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = 16, \
+ .storagebits = 16, \
+ .endianness = IIO_BE, \
+ }, \
+ }
+
+static const struct iio_chan_spec adis16480_channels[] = {
+ ADIS16480_GYRO_CHANNEL(X),
+ ADIS16480_GYRO_CHANNEL(Y),
+ ADIS16480_GYRO_CHANNEL(Z),
+ ADIS16480_ACCEL_CHANNEL(X),
+ ADIS16480_ACCEL_CHANNEL(Y),
+ ADIS16480_ACCEL_CHANNEL(Z),
+ ADIS16480_MAGN_CHANNEL(X),
+ ADIS16480_MAGN_CHANNEL(Y),
+ ADIS16480_MAGN_CHANNEL(Z),
+ ADIS16480_PRESSURE_CHANNEL(),
+ ADIS16480_TEMP_CHANNEL(),
+ IIO_CHAN_SOFT_TIMESTAMP(11)
+};
+
+static const struct iio_chan_spec adis16485_channels[] = {
+ ADIS16480_GYRO_CHANNEL(X),
+ ADIS16480_GYRO_CHANNEL(Y),
+ ADIS16480_GYRO_CHANNEL(Z),
+ ADIS16480_ACCEL_CHANNEL(X),
+ ADIS16480_ACCEL_CHANNEL(Y),
+ ADIS16480_ACCEL_CHANNEL(Z),
+ ADIS16480_TEMP_CHANNEL(),
+ IIO_CHAN_SOFT_TIMESTAMP(7)
+};
+
+enum adis16480_variant {
+ ADIS16375,
+ ADIS16480,
+ ADIS16485,
+ ADIS16488,
+};
+
+static const struct adis16480_chip_info adis16480_chip_info[] = {
+ [ADIS16375] = {
+ .channels = adis16485_channels,
+ .num_channels = ARRAY_SIZE(adis16485_channels),
+ },
+ [ADIS16480] = {
+ .channels = adis16480_channels,
+ .num_channels = ARRAY_SIZE(adis16480_channels),
+ },
+ [ADIS16485] = {
+ .channels = adis16485_channels,
+ .num_channels = ARRAY_SIZE(adis16485_channels),
+ },
+ [ADIS16488] = {
+ .channels = adis16480_channels,
+ .num_channels = ARRAY_SIZE(adis16480_channels),
+ },
+};
+
+static struct attribute *adis16480_attributes[] = {
+ &iio_dev_attr_sampling_frequency.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group adis16480_attribute_group = {
+ .attrs = adis16480_attributes,
+};
+
+static const struct iio_info adis16480_info = {
+ .attrs = &adis16480_attribute_group,
+ .read_raw = &adis16480_read_raw,
+ .write_raw = &adis16480_write_raw,
+ .update_scan_mode = adis_update_scan_mode,
+ .driver_module = THIS_MODULE,
+};
+
+static int adis16480_stop_device(struct iio_dev *indio_dev)
+{
+ struct adis16480 *st = iio_priv(indio_dev);
+ int ret;
+
+ ret = adis_write_reg_16(&st->adis, ADIS16480_REG_SLP_CNT, BIT(9));
+ if (ret)
+ dev_err(&indio_dev->dev,
+ "Could not power down device: %d\n", ret);
+
+ return ret;
+}
+
+static int adis16480_enable_irq(struct adis *adis, bool enable)
+{
+ return adis_write_reg_16(adis, ADIS16480_REG_FNCTIO_CTRL,
+ enable ? BIT(3) : 0);
+}
+
+static int adis16480_initial_setup(struct iio_dev *indio_dev)
+{
+ struct adis16480 *st = iio_priv(indio_dev);
+ uint16_t prod_id;
+ unsigned int device_id;
+ int ret;
+
+ adis_reset(&st->adis);
+ msleep(70);
+
+ ret = adis_write_reg_16(&st->adis, ADIS16480_REG_GLOB_CMD, BIT(1));
+ if (ret)
+ return ret;
+ msleep(30);
+
+ ret = adis_check_status(&st->adis);
+ if (ret)
+ return ret;
+
+ ret = adis_read_reg_16(&st->adis, ADIS16480_REG_PROD_ID, &prod_id);
+ if (ret)
+ return ret;
+
+ sscanf(indio_dev->name, "adis%u\n", &device_id);
+
+ if (prod_id != device_id)
+ dev_warn(&indio_dev->dev, "Device ID(%u) and product ID(%u) do not match.",
+ device_id, prod_id);
+
+ return 0;
+}
+
+#define ADIS16480_DIAG_STAT_XGYRO_FAIL 0
+#define ADIS16480_DIAG_STAT_YGYRO_FAIL 1
+#define ADIS16480_DIAG_STAT_ZGYRO_FAIL 2
+#define ADIS16480_DIAG_STAT_XACCL_FAIL 3
+#define ADIS16480_DIAG_STAT_YACCL_FAIL 4
+#define ADIS16480_DIAG_STAT_ZACCL_FAIL 5
+#define ADIS16480_DIAG_STAT_XMAGN_FAIL 8
+#define ADIS16480_DIAG_STAT_YMAGN_FAIL 9
+#define ADIS16480_DIAG_STAT_ZMAGN_FAIL 10
+#define ADIS16480_DIAG_STAT_BARO_FAIL 11
+
+static const char * const adis16480_status_error_msgs[] = {
+ [ADIS16480_DIAG_STAT_XGYRO_FAIL] = "X-axis gyroscope self-test failure",
+ [ADIS16480_DIAG_STAT_YGYRO_FAIL] = "Y-axis gyroscope self-test failure",
+ [ADIS16480_DIAG_STAT_ZGYRO_FAIL] = "Z-axis gyroscope self-test failure",
+ [ADIS16480_DIAG_STAT_XACCL_FAIL] = "X-axis accelerometer self-test failure",
+ [ADIS16480_DIAG_STAT_YACCL_FAIL] = "Y-axis accelerometer self-test failure",
+ [ADIS16480_DIAG_STAT_ZACCL_FAIL] = "Z-axis accelerometer self-test failure",
+ [ADIS16480_DIAG_STAT_XMAGN_FAIL] = "X-axis magnetometer self-test failure",
+ [ADIS16480_DIAG_STAT_YMAGN_FAIL] = "Y-axis magnetometer self-test failure",
+ [ADIS16480_DIAG_STAT_ZMAGN_FAIL] = "Z-axis magnetometer self-test failure",
+ [ADIS16480_DIAG_STAT_BARO_FAIL] = "Barometer self-test failure",
+};
+
+static const struct adis_data adis16480_data = {
+ .diag_stat_reg = ADIS16480_REG_DIAG_STS,
+ .glob_cmd_reg = ADIS16480_REG_GLOB_CMD,
+ .has_paging = true,
+
+ .read_delay = 5,
+ .write_delay = 5,
+
+ .status_error_msgs = adis16480_status_error_msgs,
+ .status_error_mask = BIT(ADIS16480_DIAG_STAT_XGYRO_FAIL) |
+ BIT(ADIS16480_DIAG_STAT_YGYRO_FAIL) |
+ BIT(ADIS16480_DIAG_STAT_ZGYRO_FAIL) |
+ BIT(ADIS16480_DIAG_STAT_XACCL_FAIL) |
+ BIT(ADIS16480_DIAG_STAT_YACCL_FAIL) |
+ BIT(ADIS16480_DIAG_STAT_ZACCL_FAIL) |
+ BIT(ADIS16480_DIAG_STAT_XMAGN_FAIL) |
+ BIT(ADIS16480_DIAG_STAT_YMAGN_FAIL) |
+ BIT(ADIS16480_DIAG_STAT_ZMAGN_FAIL) |
+ BIT(ADIS16480_DIAG_STAT_BARO_FAIL),
+
+ .enable_irq = adis16480_enable_irq,
+};
+
+static int adis16480_probe(struct spi_device *spi)
+{
+ const struct spi_device_id *id = spi_get_device_id(spi);
+ struct iio_dev *indio_dev;
+ struct adis16480 *st;
+ int ret;
+
+ indio_dev = iio_device_alloc(sizeof(*st));
+ if (indio_dev == NULL)
+ return -ENOMEM;
+
+ spi_set_drvdata(spi, indio_dev);
+
+ st = iio_priv(indio_dev);
+
+ st->chip_info = &adis16480_chip_info[id->driver_data];
+ indio_dev->dev.parent = &spi->dev;
+ indio_dev->name = spi_get_device_id(spi)->name;
+ indio_dev->channels = st->chip_info->channels;
+ indio_dev->num_channels = st->chip_info->num_channels;
+ indio_dev->info = &adis16480_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = adis_init(&st->adis, indio_dev, spi, &adis16480_data);
+ if (ret)
+ goto error_free_dev;
+
+ ret = adis_setup_buffer_and_trigger(&st->adis, indio_dev, NULL);
+ if (ret)
+ goto error_free_dev;
+
+ ret = adis16480_initial_setup(indio_dev);
+ if (ret)
+ goto error_cleanup_buffer;
+
+ ret = iio_device_register(indio_dev);
+ if (ret)
+ goto error_stop_device;
+
+ adis16480_debugfs_init(indio_dev);
+
+ return 0;
+
+error_stop_device:
+ adis16480_stop_device(indio_dev);
+error_cleanup_buffer:
+ adis_cleanup_buffer_and_trigger(&st->adis, indio_dev);
+error_free_dev:
+ iio_device_free(indio_dev);
+ return ret;
+}
+
+static int adis16480_remove(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev = spi_get_drvdata(spi);
+ struct adis16480 *st = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+ adis16480_stop_device(indio_dev);
+
+ adis_cleanup_buffer_and_trigger(&st->adis, indio_dev);
+
+ iio_device_free(indio_dev);
+
+ return 0;
+}
+
+static const struct spi_device_id adis16480_ids[] = {
+ { "adis16375", ADIS16375 },
+ { "adis16480", ADIS16480 },
+ { "adis16485", ADIS16485 },
+ { "adis16488", ADIS16488 },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, adis16480_ids);
+
+static struct spi_driver adis16480_driver = {
+ .driver = {
+ .name = "adis16480",
+ .owner = THIS_MODULE,
+ },
+ .id_table = adis16480_ids,
+ .probe = adis16480_probe,
+ .remove = adis16480_remove,
+};
+module_spi_driver(adis16480_driver);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("Analog Devices ADIS16480 IMU driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/imu/adis_buffer.c b/drivers/iio/imu/adis_buffer.c
new file mode 100644
index 000000000000..99d8e0b0dd34
--- /dev/null
+++ b/drivers/iio/imu/adis_buffer.c
@@ -0,0 +1,176 @@
+/*
+ * Common library for ADIS16XXX devices
+ *
+ * Copyright 2012 Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/export.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/imu/adis.h>
+
+int adis_update_scan_mode(struct iio_dev *indio_dev,
+ const unsigned long *scan_mask)
+{
+ struct adis *adis = iio_device_get_drvdata(indio_dev);
+ const struct iio_chan_spec *chan;
+ unsigned int scan_count;
+ unsigned int i, j;
+ __be16 *tx, *rx;
+
+ kfree(adis->xfer);
+ kfree(adis->buffer);
+
+ scan_count = indio_dev->scan_bytes / 2;
+
+ adis->xfer = kcalloc(scan_count + 1, sizeof(*adis->xfer), GFP_KERNEL);
+ if (!adis->xfer)
+ return -ENOMEM;
+
+ adis->buffer = kzalloc(indio_dev->scan_bytes * 2, GFP_KERNEL);
+ if (!adis->buffer)
+ return -ENOMEM;
+
+ rx = adis->buffer;
+ tx = rx + indio_dev->scan_bytes;
+
+ spi_message_init(&adis->msg);
+
+ for (j = 0; j <= scan_count; j++) {
+ adis->xfer[j].bits_per_word = 8;
+ if (j != scan_count)
+ adis->xfer[j].cs_change = 1;
+ adis->xfer[j].len = 2;
+ adis->xfer[j].delay_usecs = adis->data->read_delay;
+ if (j < scan_count)
+ adis->xfer[j].tx_buf = &tx[j];
+ if (j >= 1)
+ adis->xfer[j].rx_buf = &rx[j - 1];
+ spi_message_add_tail(&adis->xfer[j], &adis->msg);
+ }
+
+ chan = indio_dev->channels;
+ for (i = 0; i < indio_dev->num_channels; i++, chan++) {
+ if (!test_bit(chan->scan_index, scan_mask))
+ continue;
+ if (chan->scan_type.storagebits == 32)
+ *tx++ = cpu_to_be16((chan->address + 2) << 8);
+ *tx++ = cpu_to_be16(chan->address << 8);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(adis_update_scan_mode);
+
+static irqreturn_t adis_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct adis *adis = iio_device_get_drvdata(indio_dev);
+ int ret;
+
+ if (!adis->buffer)
+ return -ENOMEM;
+
+ if (adis->data->has_paging) {
+ mutex_lock(&adis->txrx_lock);
+ if (adis->current_page != 0) {
+ adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID);
+ adis->tx[1] = 0;
+ spi_write(adis->spi, adis->tx, 2);
+ }
+ }
+
+ ret = spi_sync(adis->spi, &adis->msg);
+ if (ret)
+ dev_err(&adis->spi->dev, "Failed to read data: %d", ret);
+
+
+ if (adis->data->has_paging) {
+ adis->current_page = 0;
+ mutex_unlock(&adis->txrx_lock);
+ }
+
+ /* Guaranteed to be aligned with 8 byte boundary */
+ if (indio_dev->scan_timestamp) {
+ void *b = adis->buffer + indio_dev->scan_bytes - sizeof(s64);
+ *(s64 *)b = pf->timestamp;
+ }
+
+ iio_push_to_buffers(indio_dev, adis->buffer);
+
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * adis_setup_buffer_and_trigger() - Sets up buffer and trigger for the adis device
+ * @adis: The adis device.
+ * @indio_dev: The IIO device.
+ * @trigger_handler: Optional trigger handler, may be NULL.
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ *
+ * This function sets up the buffer and trigger for a adis devices. If
+ * 'trigger_handler' is NULL the default trigger handler will be used. The
+ * default trigger handler will simply read the registers assigned to the
+ * currently active channels.
+ *
+ * adis_cleanup_buffer_and_trigger() should be called to free the resources
+ * allocated by this function.
+ */
+int adis_setup_buffer_and_trigger(struct adis *adis, struct iio_dev *indio_dev,
+ irqreturn_t (*trigger_handler)(int, void *))
+{
+ int ret;
+
+ if (!trigger_handler)
+ trigger_handler = adis_trigger_handler;
+
+ ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
+ trigger_handler, NULL);
+ if (ret)
+ return ret;
+
+ if (adis->spi->irq) {
+ ret = adis_probe_trigger(adis, indio_dev);
+ if (ret)
+ goto error_buffer_cleanup;
+ }
+ return 0;
+
+error_buffer_cleanup:
+ iio_triggered_buffer_cleanup(indio_dev);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(adis_setup_buffer_and_trigger);
+
+/**
+ * adis_cleanup_buffer_and_trigger() - Free buffer and trigger resources
+ * @adis: The adis device.
+ * @indio_dev: The IIO device.
+ *
+ * Frees resources allocated by adis_setup_buffer_and_trigger()
+ */
+void adis_cleanup_buffer_and_trigger(struct adis *adis,
+ struct iio_dev *indio_dev)
+{
+ if (adis->spi->irq)
+ adis_remove_trigger(adis);
+ kfree(adis->buffer);
+ kfree(adis->xfer);
+ iio_triggered_buffer_cleanup(indio_dev);
+}
+EXPORT_SYMBOL_GPL(adis_cleanup_buffer_and_trigger);
diff --git a/drivers/iio/imu/adis_trigger.c b/drivers/iio/imu/adis_trigger.c
new file mode 100644
index 000000000000..5a24c9cac343
--- /dev/null
+++ b/drivers/iio/imu/adis_trigger.c
@@ -0,0 +1,89 @@
+/*
+ * Common library for ADIS16XXX devices
+ *
+ * Copyright 2012 Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/export.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/imu/adis.h>
+
+static int adis_data_rdy_trigger_set_state(struct iio_trigger *trig,
+ bool state)
+{
+ struct adis *adis = trig->private_data;
+
+ return adis_enable_irq(adis, state);
+}
+
+static const struct iio_trigger_ops adis_trigger_ops = {
+ .owner = THIS_MODULE,
+ .set_trigger_state = &adis_data_rdy_trigger_set_state,
+};
+
+/**
+ * adis_probe_trigger() - Sets up trigger for a adis device
+ * @adis: The adis device
+ * @indio_dev: The IIO device
+ *
+ * Returns 0 on success or a negative error code
+ *
+ * adis_remove_trigger() should be used to free the trigger.
+ */
+int adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev)
+{
+ int ret;
+
+ adis->trig = iio_trigger_alloc("%s-dev%d", indio_dev->name,
+ indio_dev->id);
+ if (adis->trig == NULL)
+ return -ENOMEM;
+
+ ret = request_irq(adis->spi->irq,
+ &iio_trigger_generic_data_rdy_poll,
+ IRQF_TRIGGER_RISING,
+ indio_dev->name,
+ adis->trig);
+ if (ret)
+ goto error_free_trig;
+
+ adis->trig->dev.parent = &adis->spi->dev;
+ adis->trig->ops = &adis_trigger_ops;
+ adis->trig->private_data = adis;
+ ret = iio_trigger_register(adis->trig);
+
+ indio_dev->trig = adis->trig;
+ if (ret)
+ goto error_free_irq;
+
+ return 0;
+
+error_free_irq:
+ free_irq(adis->spi->irq, adis->trig);
+error_free_trig:
+ iio_trigger_free(adis->trig);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(adis_probe_trigger);
+
+/**
+ * adis_remove_trigger() - Remove trigger for a adis devices
+ * @adis: The adis device
+ *
+ * Removes the trigger previously registered with adis_probe_trigger().
+ */
+void adis_remove_trigger(struct adis *adis)
+{
+ iio_trigger_unregister(adis->trig);
+ free_irq(adis->spi->irq, adis->trig);
+ iio_trigger_free(adis->trig);
+}
+EXPORT_SYMBOL_GPL(adis_remove_trigger);
diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
index d4ad37455a67..aaadd32f9f0d 100644
--- a/drivers/iio/industrialio-buffer.c
+++ b/drivers/iio/industrialio-buffer.c
@@ -31,6 +31,18 @@ static const char * const iio_endian_prefix[] = {
[IIO_LE] = "le",
};
+static bool iio_buffer_is_active(struct iio_dev *indio_dev,
+ struct iio_buffer *buf)
+{
+ struct list_head *p;
+
+ list_for_each(p, &indio_dev->buffer_list)
+ if (p == &buf->buffer_list)
+ return true;
+
+ return false;
+}
+
/**
* iio_buffer_read_first_n_outer() - chrdev read for buffer access
*
@@ -134,7 +146,7 @@ static ssize_t iio_scan_el_store(struct device *dev,
if (ret < 0)
return ret;
mutex_lock(&indio_dev->mlock);
- if (iio_buffer_enabled(indio_dev)) {
+ if (iio_buffer_is_active(indio_dev, indio_dev->buffer)) {
ret = -EBUSY;
goto error_ret;
}
@@ -180,12 +192,11 @@ static ssize_t iio_scan_el_ts_store(struct device *dev,
return ret;
mutex_lock(&indio_dev->mlock);
- if (iio_buffer_enabled(indio_dev)) {
+ if (iio_buffer_is_active(indio_dev, indio_dev->buffer)) {
ret = -EBUSY;
goto error_ret;
}
indio_dev->buffer->scan_timestamp = state;
- indio_dev->scan_timestamp = state;
error_ret:
mutex_unlock(&indio_dev->mlock);
@@ -371,12 +382,12 @@ ssize_t iio_buffer_write_length(struct device *dev,
const char *buf,
size_t len)
{
- int ret;
- ulong val;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_buffer *buffer = indio_dev->buffer;
+ unsigned int val;
+ int ret;
- ret = strict_strtoul(buf, 10, &val);
+ ret = kstrtouint(buf, 10, &val);
if (ret)
return ret;
@@ -385,7 +396,7 @@ ssize_t iio_buffer_write_length(struct device *dev,
return len;
mutex_lock(&indio_dev->mlock);
- if (iio_buffer_enabled(indio_dev)) {
+ if (iio_buffer_is_active(indio_dev, indio_dev->buffer)) {
ret = -EBUSY;
} else {
if (buffer->access->set_length)
@@ -398,102 +409,14 @@ ssize_t iio_buffer_write_length(struct device *dev,
}
EXPORT_SYMBOL(iio_buffer_write_length);
-ssize_t iio_buffer_store_enable(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
-{
- int ret;
- bool requested_state, current_state;
- int previous_mode;
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct iio_buffer *buffer = indio_dev->buffer;
-
- mutex_lock(&indio_dev->mlock);
- previous_mode = indio_dev->currentmode;
- requested_state = !(buf[0] == '0');
- current_state = iio_buffer_enabled(indio_dev);
- if (current_state == requested_state) {
- printk(KERN_INFO "iio-buffer, current state requested again\n");
- goto done;
- }
- if (requested_state) {
- if (indio_dev->setup_ops->preenable) {
- ret = indio_dev->setup_ops->preenable(indio_dev);
- if (ret) {
- printk(KERN_ERR
- "Buffer not started: "
- "buffer preenable failed\n");
- goto error_ret;
- }
- }
- if (buffer->access->request_update) {
- ret = buffer->access->request_update(buffer);
- if (ret) {
- printk(KERN_INFO
- "Buffer not started: "
- "buffer parameter update failed\n");
- goto error_ret;
- }
- }
- /* Definitely possible for devices to support both of these. */
- if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) {
- if (!indio_dev->trig) {
- printk(KERN_INFO
- "Buffer not started: no trigger\n");
- ret = -EINVAL;
- goto error_ret;
- }
- indio_dev->currentmode = INDIO_BUFFER_TRIGGERED;
- } else if (indio_dev->modes & INDIO_BUFFER_HARDWARE)
- indio_dev->currentmode = INDIO_BUFFER_HARDWARE;
- else { /* should never be reached */
- ret = -EINVAL;
- goto error_ret;
- }
-
- if (indio_dev->setup_ops->postenable) {
- ret = indio_dev->setup_ops->postenable(indio_dev);
- if (ret) {
- printk(KERN_INFO
- "Buffer not started: "
- "postenable failed\n");
- indio_dev->currentmode = previous_mode;
- if (indio_dev->setup_ops->postdisable)
- indio_dev->setup_ops->
- postdisable(indio_dev);
- goto error_ret;
- }
- }
- } else {
- if (indio_dev->setup_ops->predisable) {
- ret = indio_dev->setup_ops->predisable(indio_dev);
- if (ret)
- goto error_ret;
- }
- indio_dev->currentmode = INDIO_DIRECT_MODE;
- if (indio_dev->setup_ops->postdisable) {
- ret = indio_dev->setup_ops->postdisable(indio_dev);
- if (ret)
- goto error_ret;
- }
- }
-done:
- mutex_unlock(&indio_dev->mlock);
- return len;
-
-error_ret:
- mutex_unlock(&indio_dev->mlock);
- return ret;
-}
-EXPORT_SYMBOL(iio_buffer_store_enable);
-
ssize_t iio_buffer_show_enable(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- return sprintf(buf, "%d\n", iio_buffer_enabled(indio_dev));
+ return sprintf(buf, "%d\n",
+ iio_buffer_is_active(indio_dev,
+ indio_dev->buffer));
}
EXPORT_SYMBOL(iio_buffer_show_enable);
@@ -537,35 +460,220 @@ static int iio_compute_scan_bytes(struct iio_dev *indio_dev, const long *mask,
return bytes;
}
-int iio_sw_buffer_preenable(struct iio_dev *indio_dev)
+int iio_update_buffers(struct iio_dev *indio_dev,
+ struct iio_buffer *insert_buffer,
+ struct iio_buffer *remove_buffer)
{
- struct iio_buffer *buffer = indio_dev->buffer;
- dev_dbg(&indio_dev->dev, "%s\n", __func__);
+ int ret;
+ int success = 0;
+ struct iio_buffer *buffer;
+ unsigned long *compound_mask;
+ const unsigned long *old_mask;
- /* How much space will the demuxed element take? */
- indio_dev->scan_bytes =
- iio_compute_scan_bytes(indio_dev, buffer->scan_mask,
- buffer->scan_timestamp);
- buffer->access->set_bytes_per_datum(buffer, indio_dev->scan_bytes);
+ /* Wind down existing buffers - iff there are any */
+ if (!list_empty(&indio_dev->buffer_list)) {
+ if (indio_dev->setup_ops->predisable) {
+ ret = indio_dev->setup_ops->predisable(indio_dev);
+ if (ret)
+ goto error_ret;
+ }
+ indio_dev->currentmode = INDIO_DIRECT_MODE;
+ if (indio_dev->setup_ops->postdisable) {
+ ret = indio_dev->setup_ops->postdisable(indio_dev);
+ if (ret)
+ goto error_ret;
+ }
+ }
+ /* Keep a copy of current setup to allow roll back */
+ old_mask = indio_dev->active_scan_mask;
+ if (!indio_dev->available_scan_masks)
+ indio_dev->active_scan_mask = NULL;
+
+ if (remove_buffer)
+ list_del(&remove_buffer->buffer_list);
+ if (insert_buffer)
+ list_add(&insert_buffer->buffer_list, &indio_dev->buffer_list);
+
+ /* If no buffers in list, we are done */
+ if (list_empty(&indio_dev->buffer_list)) {
+ indio_dev->currentmode = INDIO_DIRECT_MODE;
+ if (indio_dev->available_scan_masks == NULL)
+ kfree(old_mask);
+ return 0;
+ }
/* What scan mask do we actually have ?*/
- if (indio_dev->available_scan_masks)
+ compound_mask = kcalloc(BITS_TO_LONGS(indio_dev->masklength),
+ sizeof(long), GFP_KERNEL);
+ if (compound_mask == NULL) {
+ if (indio_dev->available_scan_masks == NULL)
+ kfree(old_mask);
+ return -ENOMEM;
+ }
+ indio_dev->scan_timestamp = 0;
+
+ list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list) {
+ bitmap_or(compound_mask, compound_mask, buffer->scan_mask,
+ indio_dev->masklength);
+ indio_dev->scan_timestamp |= buffer->scan_timestamp;
+ }
+ if (indio_dev->available_scan_masks) {
indio_dev->active_scan_mask =
iio_scan_mask_match(indio_dev->available_scan_masks,
indio_dev->masklength,
- buffer->scan_mask);
- else
- indio_dev->active_scan_mask = buffer->scan_mask;
-
- if (indio_dev->active_scan_mask == NULL)
- return -EINVAL;
+ compound_mask);
+ if (indio_dev->active_scan_mask == NULL) {
+ /*
+ * Roll back.
+ * Note can only occur when adding a buffer.
+ */
+ list_del(&insert_buffer->buffer_list);
+ indio_dev->active_scan_mask = old_mask;
+ success = -EINVAL;
+ }
+ } else {
+ indio_dev->active_scan_mask = compound_mask;
+ }
iio_update_demux(indio_dev);
- if (indio_dev->info->update_scan_mode)
- return indio_dev->info
+ /* Wind up again */
+ if (indio_dev->setup_ops->preenable) {
+ ret = indio_dev->setup_ops->preenable(indio_dev);
+ if (ret) {
+ printk(KERN_ERR
+ "Buffer not started:"
+ "buffer preenable failed\n");
+ goto error_remove_inserted;
+ }
+ }
+ indio_dev->scan_bytes =
+ iio_compute_scan_bytes(indio_dev,
+ indio_dev->active_scan_mask,
+ indio_dev->scan_timestamp);
+ list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list)
+ if (buffer->access->request_update) {
+ ret = buffer->access->request_update(buffer);
+ if (ret) {
+ printk(KERN_INFO
+ "Buffer not started:"
+ "buffer parameter update failed\n");
+ goto error_run_postdisable;
+ }
+ }
+ if (indio_dev->info->update_scan_mode) {
+ ret = indio_dev->info
->update_scan_mode(indio_dev,
indio_dev->active_scan_mask);
+ if (ret < 0) {
+ printk(KERN_INFO "update scan mode failed\n");
+ goto error_run_postdisable;
+ }
+ }
+ /* Definitely possible for devices to support both of these.*/
+ if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) {
+ if (!indio_dev->trig) {
+ printk(KERN_INFO "Buffer not started: no trigger\n");
+ ret = -EINVAL;
+ /* Can only occur on first buffer */
+ goto error_run_postdisable;
+ }
+ indio_dev->currentmode = INDIO_BUFFER_TRIGGERED;
+ } else if (indio_dev->modes & INDIO_BUFFER_HARDWARE) {
+ indio_dev->currentmode = INDIO_BUFFER_HARDWARE;
+ } else { /* should never be reached */
+ ret = -EINVAL;
+ goto error_run_postdisable;
+ }
+
+ if (indio_dev->setup_ops->postenable) {
+ ret = indio_dev->setup_ops->postenable(indio_dev);
+ if (ret) {
+ printk(KERN_INFO
+ "Buffer not started: postenable failed\n");
+ indio_dev->currentmode = INDIO_DIRECT_MODE;
+ if (indio_dev->setup_ops->postdisable)
+ indio_dev->setup_ops->postdisable(indio_dev);
+ goto error_disable_all_buffers;
+ }
+ }
+
+ if (indio_dev->available_scan_masks)
+ kfree(compound_mask);
+ else
+ kfree(old_mask);
+
+ return success;
+
+error_disable_all_buffers:
+ indio_dev->currentmode = INDIO_DIRECT_MODE;
+error_run_postdisable:
+ if (indio_dev->setup_ops->postdisable)
+ indio_dev->setup_ops->postdisable(indio_dev);
+error_remove_inserted:
+
+ if (insert_buffer)
+ list_del(&insert_buffer->buffer_list);
+ indio_dev->active_scan_mask = old_mask;
+ kfree(compound_mask);
+error_ret:
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(iio_update_buffers);
+
+ssize_t iio_buffer_store_enable(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ int ret;
+ bool requested_state;
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct iio_buffer *pbuf = indio_dev->buffer;
+ bool inlist;
+
+ ret = strtobool(buf, &requested_state);
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&indio_dev->mlock);
+
+ /* Find out if it is in the list */
+ inlist = iio_buffer_is_active(indio_dev, pbuf);
+ /* Already in desired state */
+ if (inlist == requested_state)
+ goto done;
+
+ if (requested_state)
+ ret = iio_update_buffers(indio_dev,
+ indio_dev->buffer, NULL);
+ else
+ ret = iio_update_buffers(indio_dev,
+ NULL, indio_dev->buffer);
+
+ if (ret < 0)
+ goto done;
+done:
+ mutex_unlock(&indio_dev->mlock);
+ return (ret < 0) ? ret : len;
+}
+EXPORT_SYMBOL(iio_buffer_store_enable);
+
+int iio_sw_buffer_preenable(struct iio_dev *indio_dev)
+{
+ struct iio_buffer *buffer;
+ unsigned bytes;
+ dev_dbg(&indio_dev->dev, "%s\n", __func__);
+
+ list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list)
+ if (buffer->access->set_bytes_per_datum) {
+ bytes = iio_compute_scan_bytes(indio_dev,
+ buffer->scan_mask,
+ buffer->scan_timestamp);
+
+ buffer->access->set_bytes_per_datum(buffer, bytes);
+ }
return 0;
}
EXPORT_SYMBOL(iio_sw_buffer_preenable);
@@ -599,7 +707,11 @@ static bool iio_validate_scan_mask(struct iio_dev *indio_dev,
* iio_scan_mask_set() - set particular bit in the scan mask
* @buffer: the buffer whose scan mask we are interested in
* @bit: the bit to be set.
- **/
+ *
+ * Note that at this point we have no way of knowing what other
+ * buffers might request, hence this code only verifies that the
+ * individual buffers request is plausible.
+ */
int iio_scan_mask_set(struct iio_dev *indio_dev,
struct iio_buffer *buffer, int bit)
{
@@ -682,13 +794,12 @@ static unsigned char *iio_demux(struct iio_buffer *buffer,
return buffer->demux_bounce;
}
-int iio_push_to_buffer(struct iio_buffer *buffer, unsigned char *data)
+static int iio_push_to_buffer(struct iio_buffer *buffer, unsigned char *data)
{
unsigned char *dataout = iio_demux(buffer, data);
return buffer->access->store_to(buffer, dataout);
}
-EXPORT_SYMBOL_GPL(iio_push_to_buffer);
static void iio_buffer_demux_free(struct iio_buffer *buffer)
{
@@ -699,10 +810,26 @@ static void iio_buffer_demux_free(struct iio_buffer *buffer)
}
}
-int iio_update_demux(struct iio_dev *indio_dev)
+
+int iio_push_to_buffers(struct iio_dev *indio_dev, unsigned char *data)
+{
+ int ret;
+ struct iio_buffer *buf;
+
+ list_for_each_entry(buf, &indio_dev->buffer_list, buffer_list) {
+ ret = iio_push_to_buffer(buf, data);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(iio_push_to_buffers);
+
+static int iio_buffer_update_demux(struct iio_dev *indio_dev,
+ struct iio_buffer *buffer)
{
const struct iio_chan_spec *ch;
- struct iio_buffer *buffer = indio_dev->buffer;
int ret, in_ind = -1, out_ind, length;
unsigned in_loc = 0, out_loc = 0;
struct iio_demux_table *p;
@@ -787,4 +914,23 @@ error_clear_mux_table:
return ret;
}
+
+int iio_update_demux(struct iio_dev *indio_dev)
+{
+ struct iio_buffer *buffer;
+ int ret;
+
+ list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list) {
+ ret = iio_buffer_update_demux(indio_dev, buffer);
+ if (ret < 0)
+ goto error_clear_mux_table;
+ }
+ return 0;
+
+error_clear_mux_table:
+ list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list)
+ iio_buffer_demux_free(buffer);
+
+ return ret;
+}
EXPORT_SYMBOL_GPL(iio_update_demux);
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index 6eb24dbc081e..8848f16c547b 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -65,6 +65,7 @@ static const char * const iio_chan_type_name_spec[] = {
[IIO_CAPACITANCE] = "capacitance",
[IIO_ALTVOLTAGE] = "altvoltage",
[IIO_CCT] = "cct",
+ [IIO_PRESSURE] = "pressure",
};
static const char * const iio_modifier_names[] = {
@@ -397,11 +398,74 @@ static ssize_t iio_read_channel_info(struct device *dev,
val2 = do_div(tmp, 1000000000LL);
val = tmp;
return sprintf(buf, "%d.%09u\n", val, val2);
+ case IIO_VAL_FRACTIONAL_LOG2:
+ tmp = (s64)val * 1000000000LL >> val2;
+ val2 = do_div(tmp, 1000000000LL);
+ val = tmp;
+ return sprintf(buf, "%d.%09u\n", val, val2);
default:
return 0;
}
}
+/**
+ * iio_str_to_fixpoint() - Parse a fixed-point number from a string
+ * @str: The string to parse
+ * @fract_mult: Multiplier for the first decimal place, should be a power of 10
+ * @integer: The integer part of the number
+ * @fract: The fractional part of the number
+ *
+ * Returns 0 on success, or a negative error code if the string could not be
+ * parsed.
+ */
+int iio_str_to_fixpoint(const char *str, int fract_mult,
+ int *integer, int *fract)
+{
+ int i = 0, f = 0;
+ bool integer_part = true, negative = false;
+
+ if (str[0] == '-') {
+ negative = true;
+ str++;
+ } else if (str[0] == '+') {
+ str++;
+ }
+
+ while (*str) {
+ if ('0' <= *str && *str <= '9') {
+ if (integer_part) {
+ i = i * 10 + *str - '0';
+ } else {
+ f += fract_mult * (*str - '0');
+ fract_mult /= 10;
+ }
+ } else if (*str == '\n') {
+ if (*(str + 1) == '\0')
+ break;
+ else
+ return -EINVAL;
+ } else if (*str == '.' && integer_part) {
+ integer_part = false;
+ } else {
+ return -EINVAL;
+ }
+ str++;
+ }
+
+ if (negative) {
+ if (i)
+ i = -i;
+ else
+ f = -f;
+ }
+
+ *integer = i;
+ *fract = f;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(iio_str_to_fixpoint);
+
static ssize_t iio_write_channel_info(struct device *dev,
struct device_attribute *attr,
const char *buf,
@@ -409,8 +473,8 @@ static ssize_t iio_write_channel_info(struct device *dev,
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
- int ret, integer = 0, fract = 0, fract_mult = 100000;
- bool integer_part = true, negative = false;
+ int ret, fract_mult = 100000;
+ int integer, fract;
/* Assumes decimal - precision based on number of digits */
if (!indio_dev->info->write_raw)
@@ -429,39 +493,9 @@ static ssize_t iio_write_channel_info(struct device *dev,
return -EINVAL;
}
- if (buf[0] == '-') {
- negative = true;
- buf++;
- }
-
- while (*buf) {
- if ('0' <= *buf && *buf <= '9') {
- if (integer_part)
- integer = integer*10 + *buf - '0';
- else {
- fract += fract_mult*(*buf - '0');
- if (fract_mult == 1)
- break;
- fract_mult /= 10;
- }
- } else if (*buf == '\n') {
- if (*(buf + 1) == '\0')
- break;
- else
- return -EINVAL;
- } else if (*buf == '.') {
- integer_part = false;
- } else {
- return -EINVAL;
- }
- buf++;
- }
- if (negative) {
- if (integer)
- integer = -integer;
- else
- fract = -fract;
- }
+ ret = iio_str_to_fixpoint(buf, fract_mult, &integer, &fract);
+ if (ret)
+ return ret;
ret = indio_dev->info->write_raw(indio_dev, this_attr->c,
integer, fract, this_attr->address);
@@ -851,6 +885,7 @@ struct iio_dev *iio_device_alloc(int sizeof_priv)
return NULL;
}
dev_set_name(&dev->dev, "iio:device%d", dev->id);
+ INIT_LIST_HEAD(&dev->buffer_list);
}
return dev;
diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c
index fa6543bf6731..261cae00557e 100644
--- a/drivers/iio/industrialio-event.c
+++ b/drivers/iio/industrialio-event.c
@@ -239,13 +239,13 @@ static ssize_t iio_ev_value_store(struct device *dev,
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
- unsigned long val;
+ int val;
int ret;
if (!indio_dev->info->write_event_value)
return -EINVAL;
- ret = strict_strtoul(buf, 10, &val);
+ ret = kstrtoint(buf, 10, &val);
if (ret)
return ret;
@@ -350,15 +350,10 @@ static inline int __iio_add_event_config_attrs(struct iio_dev *indio_dev)
ret = iio_device_add_event_sysfs(indio_dev,
&indio_dev->channels[j]);
if (ret < 0)
- goto error_clear_attrs;
+ return ret;
attrcount += ret;
}
return attrcount;
-
-error_clear_attrs:
- __iio_remove_event_config_attrs(indio_dev);
-
- return ret;
}
static bool iio_check_for_dynamic_events(struct iio_dev *indio_dev)
diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
index f2b78d4fe457..d55e98fb300e 100644
--- a/drivers/iio/inkern.c
+++ b/drivers/iio/inkern.c
@@ -78,7 +78,7 @@ int iio_map_array_unregister(struct iio_dev *indio_dev,
found_it = true;
break;
}
- if (found_it == false) {
+ if (!found_it) {
ret = -ENODEV;
goto error_ret;
}
@@ -203,6 +203,7 @@ struct iio_channel *iio_channel_get_all(const char *name)
if (name && strcmp(name, c->map->consumer_dev_name) != 0)
continue;
chans[mapind].indio_dev = c->indio_dev;
+ chans[mapind].data = c->map->consumer_data;
chans[mapind].channel =
iio_chan_spec_from_name(chans[mapind].indio_dev,
c->map->adc_channel_label);
@@ -314,6 +315,9 @@ static int iio_convert_raw_to_processed_unlocked(struct iio_channel *chan,
*processed = div_s64(raw64 * (s64)scale_val * scale,
scale_val2);
break;
+ case IIO_VAL_FRACTIONAL_LOG2:
+ *processed = (raw64 * (s64)scale_val * scale) >> scale_val2;
+ break;
default:
return -EINVAL;
}
diff --git a/drivers/iio/light/adjd_s311.c b/drivers/iio/light/adjd_s311.c
index 164b62b91a4b..36d210a06b28 100644
--- a/drivers/iio/light/adjd_s311.c
+++ b/drivers/iio/light/adjd_s311.c
@@ -164,7 +164,6 @@ static irqreturn_t adjd_s311_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct adjd_s311_data *data = iio_priv(indio_dev);
- struct iio_buffer *buffer = indio_dev->buffer;
s64 time_ns = iio_get_time_ns();
int len = 0;
int i, j = 0;
@@ -187,7 +186,7 @@ static irqreturn_t adjd_s311_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
*(s64 *)((u8 *)data->buffer + ALIGN(len, sizeof(s64)))
= time_ns;
- iio_push_to_buffer(buffer, (u8 *)data->buffer);
+ iio_push_to_buffers(indio_dev, (u8 *)data->buffer);
done:
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c
index 96e3691e42c4..23eeeef64e84 100644
--- a/drivers/iio/light/hid-sensor-als.c
+++ b/drivers/iio/light/hid-sensor-als.c
@@ -176,21 +176,8 @@ static const struct iio_info als_info = {
/* Function to push data to buffer */
static void hid_sensor_push_data(struct iio_dev *indio_dev, u8 *data, int len)
{
- struct iio_buffer *buffer = indio_dev->buffer;
- int datum_sz;
-
dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n");
- if (!buffer) {
- dev_err(&indio_dev->dev, "Buffer == NULL\n");
- return;
- }
- datum_sz = buffer->access->get_bytes_per_datum(buffer);
- if (len > datum_sz) {
- dev_err(&indio_dev->dev, "Datum size mismatch %d:%d\n", len,
- datum_sz);
- return;
- }
- iio_push_to_buffer(buffer, (u8 *)data);
+ iio_push_to_buffers(indio_dev, (u8 *)data);
}
/* Callback handler to send event after all samples are received and captured */
@@ -285,10 +272,9 @@ static int __devinit hid_als_probe(struct platform_device *pdev)
goto error_free_dev;
}
- channels = kmemdup(als_channels,
- sizeof(als_channels),
- GFP_KERNEL);
+ channels = kmemdup(als_channels, sizeof(als_channels), GFP_KERNEL);
if (!channels) {
+ ret = -ENOMEM;
dev_err(&pdev->dev, "failed to duplicate channels\n");
goto error_free_dev;
}
diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
index c4f0d274f577..8e75eb76ccd9 100644
--- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c
+++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
@@ -198,21 +198,8 @@ static const struct iio_info magn_3d_info = {
/* Function to push data to buffer */
static void hid_sensor_push_data(struct iio_dev *indio_dev, u8 *data, int len)
{
- struct iio_buffer *buffer = indio_dev->buffer;
- int datum_sz;
-
dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n");
- if (!buffer) {
- dev_err(&indio_dev->dev, "Buffer == NULL\n");
- return;
- }
- datum_sz = buffer->access->get_bytes_per_datum(buffer);
- if (len > datum_sz) {
- dev_err(&indio_dev->dev, "Datum size mismatch %d:%d\n", len,
- datum_sz);
- return;
- }
- iio_push_to_buffer(buffer, (u8 *)data);
+ iio_push_to_buffers(indio_dev, (u8 *)data);
}
/* Callback handler to send event after all samples are received and captured */
@@ -320,10 +307,10 @@ static int __devinit hid_magn_3d_probe(struct platform_device *pdev)
goto error_free_dev;
}
- channels = kmemdup(magn_3d_channels,
- sizeof(magn_3d_channels),
- GFP_KERNEL);
+ channels = kmemdup(magn_3d_channels, sizeof(magn_3d_channels),
+ GFP_KERNEL);
if (!channels) {
+ ret = -ENOMEM;
dev_err(&pdev->dev, "failed to duplicate channels\n");
goto error_free_dev;
}