summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.mailmap1
-rw-r--r--Documentation/devicetree/bindings/iio/adc/ti-adc12138.txt37
-rw-r--r--Documentation/devicetree/bindings/iio/proximity/sx9500.txt24
-rw-r--r--Documentation/driver-model/devres.txt4
-rw-r--r--MAINTAINERS4
-rw-r--r--drivers/iio/accel/mxc6255.c4
-rw-r--r--drivers/iio/adc/Kconfig36
-rw-r--r--drivers/iio/adc/Makefile3
-rw-r--r--drivers/iio/adc/ad7266.c4
-rw-r--r--drivers/iio/adc/at91_adc.c13
-rw-r--r--drivers/iio/adc/ina2xx-adc.c5
-rw-r--r--drivers/iio/adc/ltc2485.c148
-rw-r--r--drivers/iio/adc/stx104.c (renamed from drivers/iio/dac/stx104.c)153
-rw-r--r--drivers/iio/adc/ti-adc12138.c552
-rw-r--r--drivers/iio/adc/ti-ads1015.c2
-rw-r--r--drivers/iio/adc/ti-ads8688.c4
-rw-r--r--drivers/iio/buffer/industrialio-triggered-buffer.c42
-rw-r--r--drivers/iio/chemical/vz89x.c201
-rw-r--r--drivers/iio/common/hid-sensors/hid-sensor-trigger.c9
-rw-r--r--drivers/iio/common/st_sensors/st_sensors_buffer.c2
-rw-r--r--drivers/iio/common/st_sensors/st_sensors_core.c53
-rw-r--r--drivers/iio/common/st_sensors/st_sensors_trigger.c4
-rw-r--r--drivers/iio/dac/Kconfig20
-rw-r--r--drivers/iio/dac/Makefile2
-rw-r--r--drivers/iio/dac/ad5755.c2
-rw-r--r--drivers/iio/dac/ad8801.c239
-rw-r--r--drivers/iio/industrialio-core.c3
-rw-r--r--drivers/iio/industrialio-event.c8
-rw-r--r--drivers/iio/industrialio-trigger.c95
-rw-r--r--drivers/iio/magnetometer/ak8974.c7
-rw-r--r--drivers/iio/pressure/ms5611_core.c6
-rw-r--r--drivers/iio/proximity/sx9500.c7
-rw-r--r--drivers/iio/temperature/maxim_thermocouple.c6
-rw-r--r--drivers/staging/iio/accel/sca3000_core.c2
-rw-r--r--include/linux/iio/iio.h3
-rw-r--r--include/linux/iio/trigger.h26
-rw-r--r--include/linux/iio/triggered_buffer.h8
-rw-r--r--tools/iio/iio_utils.c11
38 files changed, 1610 insertions, 140 deletions
diff --git a/.mailmap b/.mailmap
index de22dae..377d16f 100644
--- a/.mailmap
+++ b/.mailmap
@@ -159,6 +159,7 @@ Valdis Kletnieks <Valdis.Kletnieks@vt.edu>
Viresh Kumar <vireshk@kernel.org> <viresh.kumar@st.com>
Viresh Kumar <vireshk@kernel.org> <viresh.linux@gmail.com>
Viresh Kumar <vireshk@kernel.org> <viresh.kumar2@arm.com>
+Vlad Dogaru <ddvlad@gmail.com> <vlad.dogaru@intel.com>
Vladimir Davydov <vdavydov.dev@gmail.com> <vdavydov@virtuozzo.com>
Vladimir Davydov <vdavydov.dev@gmail.com> <vdavydov@parallels.com>
Takashi YOSHII <takashi.yoshii.zj@renesas.com>
diff --git a/Documentation/devicetree/bindings/iio/adc/ti-adc12138.txt b/Documentation/devicetree/bindings/iio/adc/ti-adc12138.txt
new file mode 100644
index 0000000..049a1d3
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/ti-adc12138.txt
@@ -0,0 +1,37 @@
+* Texas Instruments' ADC12130/ADC12132/ADC12138
+
+Required properties:
+ - compatible: Should be one of
+ * "ti,adc12130"
+ * "ti,adc12132"
+ * "ti,adc12138"
+ - reg: SPI chip select number for the device
+ - interrupts: Should contain interrupt for EOC (end of conversion)
+ - clocks: phandle to conversion clock input
+ - spi-max-frequency: Definision as per
+ Documentation/devicetree/bindings/spi/spi-bus.txt
+ - vref-p-supply: The regulator supply for positive analog voltage reference
+
+Optional properties:
+ - vref-n-supply: The regulator supply for negative analog voltage reference
+ (Note that this must not go below GND or exceed vref-p)
+ If not specified, this is assumed to be analog ground.
+ - ti,acquisition-time: The number of conversion clock periods for the S/H's
+ acquisition time. Should be one of 6, 10, 18, 34. If not specified,
+ default value of 10 is used.
+ For high source impedances, this value can be increased to 18 or 34.
+ For less ADC accuracy and/or slower CCLK frequencies this value may be
+ decreased to 6. See section 6.0 INPUT SOURCE RESISTANCE in the
+ datasheet for details.
+
+Example:
+adc@0 {
+ compatible = "ti,adc12138";
+ reg = <0>;
+ interrupts = <28 IRQ_TYPE_EDGE_RISING>;
+ interrupt-parent = <&gpio1>;
+ clocks = <&cclk>;
+ vref-p-supply = <&ldo4_reg>;
+ spi-max-frequency = <5000000>;
+ ti,acquisition-time = <6>;
+};
diff --git a/Documentation/devicetree/bindings/iio/proximity/sx9500.txt b/Documentation/devicetree/bindings/iio/proximity/sx9500.txt
new file mode 100644
index 0000000..b301dd2
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/proximity/sx9500.txt
@@ -0,0 +1,24 @@
+Semtech's SX9500 capacitive proximity button device driver
+
+Required properties:
+ - compatible: must be "semtech,sx9500"
+ - reg: i2c address where to find the device
+ - interrupt-parent : should be the phandle for the interrupt controller
+ - interrupts : the sole interrupt generated by the device
+
+ Refer to interrupt-controller/interrupts.txt for generic
+ interrupt client node bindings.
+
+Optional properties:
+ - reset-gpios: Reference to the GPIO connected to the device's active
+ low reset pin.
+
+Example:
+
+sx9500@28 {
+ compatible = "semtech,sx9500";
+ reg = <0x28>;
+ interrupt-parent = <&gpio2>;
+ interrupts = <16 IRQ_TYPE_LEVEL_LOW>;
+ reset-gpios = <&gpio2 10 GPIO_ACTIVE_LOW>;
+};
diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt
index b0d775d..75bc5b8 100644
--- a/Documentation/driver-model/devres.txt
+++ b/Documentation/driver-model/devres.txt
@@ -266,8 +266,12 @@ IIO
devm_iio_device_unregister()
devm_iio_kfifo_allocate()
devm_iio_kfifo_free()
+ devm_iio_triggered_buffer_setup()
+ devm_iio_triggered_buffer_cleanup()
devm_iio_trigger_alloc()
devm_iio_trigger_free()
+ devm_iio_trigger_register()
+ devm_iio_trigger_unregister()
devm_iio_channel_get()
devm_iio_channel_release()
devm_iio_channel_get_all()
diff --git a/MAINTAINERS b/MAINTAINERS
index ad01604..1b65477 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -810,11 +810,11 @@ L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Maintained
F: sound/aoa/
-APEX EMBEDDED SYSTEMS STX104 DAC DRIVER
+APEX EMBEDDED SYSTEMS STX104 IIO DRIVER
M: William Breathitt Gray <vilhelm.gray@gmail.com>
L: linux-iio@vger.kernel.org
S: Maintained
-F: drivers/iio/dac/stx104.c
+F: drivers/iio/adc/stx104.c
APM DRIVER
M: Jiri Kosina <jikos@kernel.org>
diff --git a/drivers/iio/accel/mxc6255.c b/drivers/iio/accel/mxc6255.c
index 97ccde7..0abad69 100644
--- a/drivers/iio/accel/mxc6255.c
+++ b/drivers/iio/accel/mxc6255.c
@@ -154,7 +154,7 @@ static int mxc6255_probe(struct i2c_client *client,
return ret;
}
- if (chip_id != MXC6255_CHIP_ID) {
+ if ((chip_id & 0x1f) != MXC6255_CHIP_ID) {
dev_err(&client->dev, "Invalid chip id %x\n", chip_id);
return -ENODEV;
}
@@ -171,12 +171,14 @@ static int mxc6255_probe(struct i2c_client *client,
}
static const struct acpi_device_id mxc6255_acpi_match[] = {
+ {"MXC6225", 0},
{"MXC6255", 0},
{ }
};
MODULE_DEVICE_TABLE(acpi, mxc6255_acpi_match);
static const struct i2c_device_id mxc6255_id[] = {
+ {"mxc6225", 0},
{"mxc6255", 0},
{ }
};
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 586830e..7edcf32 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -264,6 +264,15 @@ config LPC18XX_ADC
To compile this driver as a module, choose M here: the module will be
called lpc18xx_adc.
+config LTC2485
+ tristate "Linear Technology LTC2485 ADC driver"
+ depends on I2C
+ help
+ Say yes here to build support for Linear Technology LTC2485 ADC.
+
+ To compile this driver as a module, choose M here: the module will be
+ called ltc2485.
+
config MAX1027
tristate "Maxim max1027 ADC driver"
depends on SPI
@@ -410,6 +419,21 @@ config ROCKCHIP_SARADC
To compile this driver as a module, choose M here: the
module will be called rockchip_saradc.
+config STX104
+ tristate "Apex Embedded Systems STX104 driver"
+ depends on X86 && ISA_BUS_API
+ select GPIOLIB
+ help
+ Say yes here to build support for the Apex Embedded Systems STX104
+ integrated analog PC/104 card.
+
+ This driver supports the 16 channels of single-ended (8 channels of
+ differential) analog inputs, 2 channels of analog output, 4 digital
+ inputs, and 4 digital outputs provided by the STX104.
+
+ The base port addresses for the devices may be configured via the base
+ array module parameter.
+
config TI_ADC081C
tristate "Texas Instruments ADC081C/ADC101C/ADC121C family"
depends on I2C
@@ -430,6 +454,18 @@ config TI_ADC0832
This driver can also be built as a module. If so, the module will be
called ti-adc0832.
+config TI_ADC12138
+ tristate "Texas Instruments ADC12130/ADC12132/ADC12138"
+ depends on SPI
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ help
+ If you say yes here you get support for Texas Instruments ADC12130,
+ ADC12132 and ADC12138 chips.
+
+ This driver can also be built as a module. If so, the module will be
+ called ti-adc12138.
+
config TI_ADC128S052
tristate "Texas Instruments ADC128S052/ADC122S021/ADC124S021"
depends on SPI
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 33254eb..7a40c04 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_IMX7D_ADC) += imx7d_adc.o
obj-$(CONFIG_INA2XX_ADC) += ina2xx-adc.o
obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o
+obj-$(CONFIG_LTC2485) += ltc2485.o
obj-$(CONFIG_MAX1027) += max1027.o
obj-$(CONFIG_MAX1363) += max1363.o
obj-$(CONFIG_MCP320X) += mcp320x.o
@@ -39,8 +40,10 @@ obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o
obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o
obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o
obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o
+obj-$(CONFIG_STX104) += stx104.o
obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o
obj-$(CONFIG_TI_ADC0832) += ti-adc0832.o
+obj-$(CONFIG_TI_ADC12138) += ti-adc12138.o
obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o
obj-$(CONFIG_TI_ADC161S626) += ti-adc161s626.o
obj-$(CONFIG_TI_ADS1015) += ti-ads1015.o
diff --git a/drivers/iio/adc/ad7266.c b/drivers/iio/adc/ad7266.c
index c0f6a98..b8d5cfd 100644
--- a/drivers/iio/adc/ad7266.c
+++ b/drivers/iio/adc/ad7266.c
@@ -481,7 +481,7 @@ error_free_gpios:
if (!st->fixed_addr)
gpio_free_array(st->gpios, ARRAY_SIZE(st->gpios));
error_disable_reg:
- if (!IS_ERR_OR_NULL(st->reg))
+ if (!IS_ERR(st->reg))
regulator_disable(st->reg);
return ret;
@@ -496,7 +496,7 @@ static int ad7266_remove(struct spi_device *spi)
iio_triggered_buffer_cleanup(indio_dev);
if (!st->fixed_addr)
gpio_free_array(st->gpios, ARRAY_SIZE(st->gpios));
- if (!IS_ERR_OR_NULL(st->reg))
+ if (!IS_ERR(st->reg))
regulator_disable(st->reg);
return 0;
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index 0438c68..bbdac07 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -113,6 +113,7 @@
#define AT91_ADC_TSMR_TSAV (3 << 4) /* Averages samples */
#define AT91_ADC_TSMR_TSAV_(x) ((x) << 4)
#define AT91_ADC_TSMR_SCTIM (0x0f << 16) /* Switch closure time */
+#define AT91_ADC_TSMR_SCTIM_(x) ((x) << 16)
#define AT91_ADC_TSMR_PENDBC (0x0f << 28) /* Pen Debounce time */
#define AT91_ADC_TSMR_PENDBC_(x) ((x) << 28)
#define AT91_ADC_TSMR_NOTSDMA (1 << 22) /* No Touchscreen DMA */
@@ -150,6 +151,7 @@
#define MAX_RLPOS_BITS 10
#define TOUCH_SAMPLE_PERIOD_US_RL 10000 /* 10ms, the SoC can't keep up with 2ms */
#define TOUCH_SHTIM 0xa
+#define TOUCH_SCTIM_US 10 /* 10us for the Touchscreen Switches Closure Time */
/**
* struct at91_adc_reg_desc - Various informations relative to registers
@@ -1001,7 +1003,9 @@ static void atmel_ts_close(struct input_dev *dev)
static int at91_ts_hw_init(struct at91_adc_state *st, u32 adc_clk_khz)
{
+ struct iio_dev *idev = iio_priv_to_dev(st);
u32 reg = 0;
+ u32 tssctim = 0;
int i = 0;
/* a Pen Detect Debounce Time is necessary for the ADC Touch to avoid
@@ -1034,11 +1038,20 @@ static int at91_ts_hw_init(struct at91_adc_state *st, u32 adc_clk_khz)
return 0;
}
+ /* Touchscreen Switches Closure time needed for allowing the value to
+ * stabilize.
+ * Switch Closure Time = (TSSCTIM * 4) ADCClock periods
+ */
+ tssctim = DIV_ROUND_UP(TOUCH_SCTIM_US * adc_clk_khz / 1000, 4);
+ dev_dbg(&idev->dev, "adc_clk at: %d KHz, tssctim at: %d\n",
+ adc_clk_khz, tssctim);
+
if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_4WIRE)
reg = AT91_ADC_TSMR_TSMODE_4WIRE_PRESS;
else
reg = AT91_ADC_TSMR_TSMODE_5WIRE;
+ reg |= AT91_ADC_TSMR_SCTIM_(tssctim) & AT91_ADC_TSMR_SCTIM;
reg |= AT91_ADC_TSMR_TSAV_(st->caps->ts_filter_average)
& AT91_ADC_TSMR_TSAV;
reg |= AT91_ADC_TSMR_PENDBC_(st->ts_pendbc) & AT91_ADC_TSMR_PENDBC;
diff --git a/drivers/iio/adc/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c
index 955f3fd..59b7d76 100644
--- a/drivers/iio/adc/ina2xx-adc.c
+++ b/drivers/iio/adc/ina2xx-adc.c
@@ -114,7 +114,6 @@ struct ina2xx_chip_info {
struct mutex state_lock;
unsigned int shunt_resistor;
int avg;
- s64 prev_ns; /* track buffer capture time, check for underruns */
int int_time_vbus; /* Bus voltage integration time uS */
int int_time_vshunt; /* Shunt voltage integration time uS */
bool allow_async_readout;
@@ -509,8 +508,6 @@ static int ina2xx_work_buffer(struct iio_dev *indio_dev)
iio_push_to_buffers_with_timestamp(indio_dev,
(unsigned int *)data, time_a);
- chip->prev_ns = time_a;
-
return (unsigned long)(time_b - time_a) / 1000;
};
@@ -554,8 +551,6 @@ static int ina2xx_buffer_enable(struct iio_dev *indio_dev)
dev_dbg(&indio_dev->dev, "Async readout mode: %d\n",
chip->allow_async_readout);
- chip->prev_ns = iio_get_time_ns(indio_dev);
-
chip->task = kthread_run(ina2xx_capture_thread, (void *)indio_dev,
"%s:%d-%uus", indio_dev->name, indio_dev->id,
sampling_us);
diff --git a/drivers/iio/adc/ltc2485.c b/drivers/iio/adc/ltc2485.c
new file mode 100644
index 0000000..eab91f12
--- /dev/null
+++ b/drivers/iio/adc/ltc2485.c
@@ -0,0 +1,148 @@
+/*
+ * ltc2485.c - Driver for Linear Technology LTC2485 ADC
+ *
+ * Copyright (C) 2016 Alison Schofield <amsfield22@gmail.com>
+ *
+ * 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.
+ *
+ * Datasheet: http://cds.linear.com/docs/en/datasheet/2485fd.pdf
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+/* Power-on configuration: rejects both 50/60Hz, operates at 1x speed */
+#define LTC2485_CONFIG_DEFAULT 0
+
+struct ltc2485_data {
+ struct i2c_client *client;
+ ktime_t time_prev; /* last conversion */
+};
+
+static void ltc2485_wait_conv(struct ltc2485_data *data)
+{
+ const unsigned int conv_time = 147; /* conversion time ms */
+ unsigned int time_elapsed;
+
+ /* delay if conversion time not passed since last read or write */
+ time_elapsed = ktime_ms_delta(ktime_get(), data->time_prev);
+
+ if (time_elapsed < conv_time)
+ msleep(conv_time - time_elapsed);
+}
+
+static int ltc2485_read(struct ltc2485_data *data, int *val)
+{
+ struct i2c_client *client = data->client;
+ __be32 buf = 0;
+ int ret;
+
+ ltc2485_wait_conv(data);
+
+ ret = i2c_master_recv(client, (char *)&buf, 4);
+ if (ret < 0) {
+ dev_err(&client->dev, "i2c_master_recv failed\n");
+ return ret;
+ }
+ data->time_prev = ktime_get();
+ *val = sign_extend32(be32_to_cpu(buf) >> 6, 24);
+
+ return ret;
+}
+
+static int ltc2485_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct ltc2485_data *data = iio_priv(indio_dev);
+ int ret;
+
+ if (mask == IIO_CHAN_INFO_RAW) {
+ ret = ltc2485_read(data, val);
+ if (ret < 0)
+ return ret;
+
+ return IIO_VAL_INT;
+
+ } else if (mask == IIO_CHAN_INFO_SCALE) {
+ *val = 5000; /* on board vref millivolts */
+ *val2 = 25; /* 25 (24 + sign) data bits */
+ return IIO_VAL_FRACTIONAL_LOG2;
+
+ } else {
+ return -EINVAL;
+ }
+}
+
+static const struct iio_chan_spec ltc2485_channel[] = {
+ {
+ .type = IIO_VOLTAGE,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE)
+ },
+};
+
+static const struct iio_info ltc2485_info = {
+ .read_raw = ltc2485_read_raw,
+ .driver_module = THIS_MODULE,
+};
+
+static int ltc2485_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct iio_dev *indio_dev;
+ struct ltc2485_data *data;
+ int ret;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
+ I2C_FUNC_SMBUS_WRITE_BYTE))
+ return -EOPNOTSUPP;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ data = iio_priv(indio_dev);
+ i2c_set_clientdata(client, indio_dev);
+ data->client = client;
+
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->name = id->name;
+ indio_dev->info = &ltc2485_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = ltc2485_channel;
+ indio_dev->num_channels = ARRAY_SIZE(ltc2485_channel);
+
+ ret = i2c_smbus_write_byte(data->client, LTC2485_CONFIG_DEFAULT);
+ if (ret < 0)
+ return ret;
+
+ data->time_prev = ktime_get();
+
+ return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static const struct i2c_device_id ltc2485_id[] = {
+ { "ltc2485", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ltc2485_id);
+
+static struct i2c_driver ltc2485_driver = {
+ .driver = {
+ .name = "ltc2485",
+ },
+ .probe = ltc2485_probe,
+ .id_table = ltc2485_id,
+};
+module_i2c_driver(ltc2485_driver);
+
+MODULE_AUTHOR("Alison Schofield <amsfield22@gmail.com>");
+MODULE_DESCRIPTION("Linear Technology LTC2485 ADC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/dac/stx104.c b/drivers/iio/adc/stx104.c
index bebbd00..7e36457 100644
--- a/drivers/iio/dac/stx104.c
+++ b/drivers/iio/adc/stx104.c
@@ -1,5 +1,5 @@
/*
- * DAC driver for the Apex Embedded Systems STX104
+ * IIO driver for the Apex Embedded Systems STX104
* Copyright (C) 2016 William Breathitt Gray
*
* This program is free software; you can redistribute it and/or modify
@@ -20,19 +20,30 @@
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/isa.h>
+#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/spinlock.h>
-#define STX104_NUM_CHAN 2
-
-#define STX104_CHAN(chan) { \
+#define STX104_OUT_CHAN(chan) { \
.type = IIO_VOLTAGE, \
.channel = chan, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.indexed = 1, \
.output = 1 \
}
+#define STX104_IN_CHAN(chan, diff) { \
+ .type = IIO_VOLTAGE, \
+ .channel = chan, \
+ .channel2 = chan, \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_HARDWAREGAIN) | \
+ BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .indexed = 1, \
+ .differential = diff \
+}
+
+#define STX104_NUM_OUT_CHAN 2
#define STX104_EXTENT 16
@@ -47,8 +58,8 @@ MODULE_PARM_DESC(base, "Apex Embedded Systems STX104 base addresses");
* @base: base port address of the IIO device
*/
struct stx104_iio {
- unsigned chan_out_states[STX104_NUM_CHAN];
- unsigned base;
+ unsigned int chan_out_states[STX104_NUM_OUT_CHAN];
+ unsigned int base;
};
/**
@@ -79,28 +90,95 @@ static int stx104_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val, int *val2, long mask)
{
struct stx104_iio *const priv = iio_priv(indio_dev);
+ unsigned int adc_config;
+ int adbu;
+ int gain;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_HARDWAREGAIN:
+ /* get gain configuration */
+ adc_config = inb(priv->base + 11);
+ gain = adc_config & 0x3;
+
+ *val = 1 << gain;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_RAW:
+ if (chan->output) {
+ *val = priv->chan_out_states[chan->channel];
+ return IIO_VAL_INT;
+ }
+
+ /* select ADC channel */
+ outb(chan->channel | (chan->channel << 4), priv->base + 2);
+
+ /* trigger ADC sample capture and wait for completion */
+ outb(0, priv->base);
+ while (inb(priv->base + 8) & BIT(7));
+
+ *val = inw(priv->base);
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_OFFSET:
+ /* get ADC bipolar/unipolar configuration */
+ adc_config = inb(priv->base + 11);
+ adbu = !(adc_config & BIT(2));
+
+ *val = -32768 * adbu;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ /* get ADC bipolar/unipolar and gain configuration */
+ adc_config = inb(priv->base + 11);
+ adbu = !(adc_config & BIT(2));
+ gain = adc_config & 0x3;
+
+ *val = 5;
+ *val2 = 15 - adbu + gain;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ }
- if (mask != IIO_CHAN_INFO_RAW)
- return -EINVAL;
-
- *val = priv->chan_out_states[chan->channel];
-
- return IIO_VAL_INT;
+ return -EINVAL;
}
static int stx104_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val, int val2, long mask)
{
struct stx104_iio *const priv = iio_priv(indio_dev);
- const unsigned chan_addr_offset = 2 * chan->channel;
- if (mask != IIO_CHAN_INFO_RAW)
+ switch (mask) {
+ case IIO_CHAN_INFO_HARDWAREGAIN:
+ /* Only four gain states (x1, x2, x4, x8) */
+ switch (val) {
+ case 1:
+ outb(0, priv->base + 11);
+ break;
+ case 2:
+ outb(1, priv->base + 11);
+ break;
+ case 4:
+ outb(2, priv->base + 11);
+ break;
+ case 8:
+ outb(3, priv->base + 11);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+ case IIO_CHAN_INFO_RAW:
+ if (chan->output) {
+ /* DAC can only accept up to a 16-bit value */
+ if ((unsigned int)val > 65535)
+ return -EINVAL;
+
+ priv->chan_out_states[chan->channel] = val;
+ outw(val, priv->base + 4 + 2 * chan->channel);
+
+ return 0;
+ }
return -EINVAL;
+ }
- priv->chan_out_states[chan->channel] = val;
- outw(val, priv->base + 4 + chan_addr_offset);
-
- return 0;
+ return -EINVAL;
}
static const struct iio_info stx104_info = {
@@ -109,9 +187,22 @@ static const struct iio_info stx104_info = {
.write_raw = stx104_write_raw
};
-static const struct iio_chan_spec stx104_channels[STX104_NUM_CHAN] = {
- STX104_CHAN(0),
- STX104_CHAN(1)
+/* single-ended input channels configuration */
+static const struct iio_chan_spec stx104_channels_sing[] = {
+ STX104_OUT_CHAN(0), STX104_OUT_CHAN(1),
+ STX104_IN_CHAN(0, 0), STX104_IN_CHAN(1, 0), STX104_IN_CHAN(2, 0),
+ STX104_IN_CHAN(3, 0), STX104_IN_CHAN(4, 0), STX104_IN_CHAN(5, 0),
+ STX104_IN_CHAN(6, 0), STX104_IN_CHAN(7, 0), STX104_IN_CHAN(8, 0),
+ STX104_IN_CHAN(9, 0), STX104_IN_CHAN(10, 0), STX104_IN_CHAN(11, 0),
+ STX104_IN_CHAN(12, 0), STX104_IN_CHAN(13, 0), STX104_IN_CHAN(14, 0),
+ STX104_IN_CHAN(15, 0)
+};
+/* differential input channels configuration */
+static const struct iio_chan_spec stx104_channels_diff[] = {
+ STX104_OUT_CHAN(0), STX104_OUT_CHAN(1),
+ STX104_IN_CHAN(0, 1), STX104_IN_CHAN(1, 1), STX104_IN_CHAN(2, 1),
+ STX104_IN_CHAN(3, 1), STX104_IN_CHAN(4, 1), STX104_IN_CHAN(5, 1),
+ STX104_IN_CHAN(6, 1), STX104_IN_CHAN(7, 1)
};
static int stx104_gpio_get_direction(struct gpio_chip *chip,
@@ -204,13 +295,27 @@ static int stx104_probe(struct device *dev, unsigned int id)
indio_dev->info = &stx104_info;
indio_dev->modes = INDIO_DIRECT_MODE;
- indio_dev->channels = stx104_channels;
- indio_dev->num_channels = STX104_NUM_CHAN;
+
+ /* determine if differential inputs */
+ if (inb(base[id] + 8) & BIT(5)) {
+ indio_dev->num_channels = ARRAY_SIZE(stx104_channels_diff);
+ indio_dev->channels = stx104_channels_diff;
+ } else {
+ indio_dev->num_channels = ARRAY_SIZE(stx104_channels_sing);
+ indio_dev->channels = stx104_channels_sing;
+ }
+
indio_dev->name = dev_name(dev);
priv = iio_priv(indio_dev);
priv->base = base[id];
+ /* configure device for software trigger operation */
+ outb(0, base[id] + 9);
+
+ /* initialize gain setting to x1 */
+ outb(0, base[id] + 11);
+
/* initialize DAC output to 0V */
outw(0, base[id] + 4);
outw(0, base[id] + 6);
@@ -271,5 +376,5 @@ static struct isa_driver stx104_driver = {
module_isa_driver(stx104_driver, num_stx104);
MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
-MODULE_DESCRIPTION("Apex Embedded Systems STX104 DAC driver");
+MODULE_DESCRIPTION("Apex Embedded Systems STX104 IIO driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/ti-adc12138.c b/drivers/iio/adc/ti-adc12138.c
new file mode 100644
index 0000000..072f03b
--- /dev/null
+++ b/drivers/iio/adc/ti-adc12138.c
@@ -0,0 +1,552 @@
+/*
+ * ADC12130/ADC12132/ADC12138 12-bit plus sign ADC driver
+ *
+ * Copyright (c) 2016 Akinobu Mita <akinobu.mita@gmail.com>
+ *
+ * This file is subject to the terms and conditions of version 2 of
+ * the GNU General Public License. See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ * Datasheet: http://www.ti.com/lit/ds/symlink/adc12138.pdf
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/clk.h>
+#include <linux/spi/spi.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/regulator/consumer.h>
+
+#define ADC12138_MODE_AUTO_CAL 0x08
+#define ADC12138_MODE_READ_STATUS 0x0c
+#define ADC12138_MODE_ACQUISITION_TIME_6 0x0e
+#define ADC12138_MODE_ACQUISITION_TIME_10 0x4e
+#define ADC12138_MODE_ACQUISITION_TIME_18 0x8e
+#define ADC12138_MODE_ACQUISITION_TIME_34 0xce
+
+#define ADC12138_STATUS_CAL BIT(6)
+
+enum {
+ adc12130,
+ adc12132,
+ adc12138,
+};
+
+struct adc12138 {
+ struct spi_device *spi;
+ unsigned int id;
+ /* conversion clock */
+ struct clk *cclk;
+ /* positive analog voltage reference */
+ struct regulator *vref_p;
+ /* negative analog voltage reference */
+ struct regulator *vref_n;
+ struct mutex lock;
+ struct completion complete;
+ /* The number of cclk periods for the S/H's acquisition time */
+ unsigned int acquisition_time;
+
+ u8 tx_buf[2] ____cacheline_aligned;
+ u8 rx_buf[2];
+};
+
+#define ADC12138_VOLTAGE_CHANNEL(chan) \
+ { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = chan, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \
+ | BIT(IIO_CHAN_INFO_OFFSET), \
+ .scan_index = chan, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = 13, \
+ .storagebits = 16, \
+ .shift = 3, \
+ .endianness = IIO_BE, \
+ }, \
+ }
+
+#define ADC12138_VOLTAGE_CHANNEL_DIFF(chan1, chan2, si) \
+ { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = (chan1), \
+ .channel2 = (chan2), \
+ .differential = 1, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \
+ | BIT(IIO_CHAN_INFO_OFFSET), \
+ .scan_index = si, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = 13, \
+ .storagebits = 16, \
+ .shift = 3, \
+ .endianness = IIO_BE, \
+ }, \
+ }
+
+static const struct iio_chan_spec adc12132_channels[] = {
+ ADC12138_VOLTAGE_CHANNEL(0),
+ ADC12138_VOLTAGE_CHANNEL(1),
+ ADC12138_VOLTAGE_CHANNEL_DIFF(0, 1, 2),
+ ADC12138_VOLTAGE_CHANNEL_DIFF(1, 0, 3),
+ IIO_CHAN_SOFT_TIMESTAMP(4),
+};
+
+static const struct iio_chan_spec adc12138_channels[] = {
+ ADC12138_VOLTAGE_CHANNEL(0),
+ ADC12138_VOLTAGE_CHANNEL(1),
+ ADC12138_VOLTAGE_CHANNEL(2),
+ ADC12138_VOLTAGE_CHANNEL(3),
+ ADC12138_VOLTAGE_CHANNEL(4),
+ ADC12138_VOLTAGE_CHANNEL(5),
+ ADC12138_VOLTAGE_CHANNEL(6),
+ ADC12138_VOLTAGE_CHANNEL(7),
+ ADC12138_VOLTAGE_CHANNEL_DIFF(0, 1, 8),
+ ADC12138_VOLTAGE_CHANNEL_DIFF(1, 0, 9),
+ ADC12138_VOLTAGE_CHANNEL_DIFF(2, 3, 10),
+ ADC12138_VOLTAGE_CHANNEL_DIFF(3, 2, 11),
+ ADC12138_VOLTAGE_CHANNEL_DIFF(4, 5, 12),
+ ADC12138_VOLTAGE_CHANNEL_DIFF(5, 4, 13),
+ ADC12138_VOLTAGE_CHANNEL_DIFF(6, 7, 14),
+ ADC12138_VOLTAGE_CHANNEL_DIFF(7, 6, 15),
+ IIO_CHAN_SOFT_TIMESTAMP(16),
+};
+
+static int adc12138_mode_programming(struct adc12138 *adc, u8 mode,
+ void *rx_buf, int len)
+{
+ struct spi_transfer xfer = {
+ .tx_buf = adc->tx_buf,
+ .rx_buf = adc->rx_buf,
+ .len = len,
+ };
+ int ret;
+
+ /* Skip unused bits for ADC12130 and ADC12132 */
+ if (adc->id != adc12138)
+ mode = (mode & 0xc0) | ((mode & 0x0f) << 2);
+
+ adc->tx_buf[0] = mode;
+
+ ret = spi_sync_transfer(adc->spi, &xfer, 1);
+ if (ret)
+ return ret;
+
+ memcpy(rx_buf, adc->rx_buf, len);
+
+ return 0;
+}
+
+static int adc12138_read_status(struct adc12138 *adc)
+{
+ u8 rx_buf[2];
+ int ret;
+
+ ret = adc12138_mode_programming(adc, ADC12138_MODE_READ_STATUS,
+ rx_buf, 2);
+ if (ret)
+ return ret;
+
+ return (rx_buf[0] << 1) | (rx_buf[1] >> 7);
+}
+
+static int __adc12138_start_conv(struct adc12138 *adc,
+ struct iio_chan_spec const *channel,
+ void *data, int len)
+
+{
+ const u8 ch_to_mux[] = { 0, 4, 1, 5, 2, 6, 3, 7 };
+ u8 mode = (ch_to_mux[channel->channel] << 4) |
+ (channel->differential ? 0 : 0x80);
+
+ return adc12138_mode_programming(adc, mode, data, len);
+}
+
+static int adc12138_start_conv(struct adc12138 *adc,
+ struct iio_chan_spec const *channel)
+{
+ u8 trash;
+
+ return __adc12138_start_conv(adc, channel, &trash, 1);
+}
+
+static int adc12138_start_and_read_conv(struct adc12138 *adc,
+ struct iio_chan_spec const *channel,
+ __be16 *data)
+{
+ return __adc12138_start_conv(adc, channel, data, 2);
+}
+
+static int adc12138_read_conv_data(struct adc12138 *adc, __be16 *value)
+{
+ /* Issue a read status instruction and read previous conversion data */
+ return adc12138_mode_programming(adc, ADC12138_MODE_READ_STATUS,
+ value, sizeof(*value));
+}
+
+static int adc12138_wait_eoc(struct adc12138 *adc, unsigned long timeout)
+{
+ if (!wait_for_completion_timeout(&adc->complete, timeout))
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int adc12138_adc_conversion(struct adc12138 *adc,
+ struct iio_chan_spec const *channel,
+ __be16 *value)
+{
+ int ret;
+
+ reinit_completion(&adc->complete);
+
+ ret = adc12138_start_conv(adc, channel);
+ if (ret)
+ return ret;
+
+ ret = adc12138_wait_eoc(adc, msecs_to_jiffies(100));
+ if (ret)
+ return ret;
+
+ return adc12138_read_conv_data(adc, value);
+}
+
+static int adc12138_read_raw(struct iio_dev *iio,
+ struct iio_chan_spec const *channel, int *value,
+ int *shift, long mask)
+{
+ struct adc12138 *adc = iio_priv(iio);
+ int ret;
+ __be16 data;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ mutex_lock(&adc->lock);
+ ret = adc12138_adc_conversion(adc, channel, &data);
+ mutex_unlock(&adc->lock);
+ if (ret)
+ return ret;
+
+ *value = sign_extend32(be16_to_cpu(data) >> 3, 12);
+
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ ret = regulator_get_voltage(adc->vref_p);
+ if (ret < 0)
+ return ret;
+ *value = ret;
+
+ if (!IS_ERR(adc->vref_n)) {
+ ret = regulator_get_voltage(adc->vref_n);
+ if (ret < 0)
+ return ret;
+ *value -= ret;
+ }
+
+ /* convert regulator output voltage to mV */
+ *value /= 1000;
+ *shift = channel->scan_type.realbits - 1;
+
+ return IIO_VAL_FRACTIONAL_LOG2;
+ case IIO_CHAN_INFO_OFFSET:
+ if (!IS_ERR(adc->vref_n)) {
+ *value = regulator_get_voltage(adc->vref_n);
+ if (*value < 0)
+ return *value;
+ } else {
+ *value = 0;
+ }
+
+ /* convert regulator output voltage to mV */
+ *value /= 1000;
+
+ return IIO_VAL_INT;
+ }
+
+ return -EINVAL;
+}
+
+static const struct iio_info adc12138_info = {
+ .read_raw = adc12138_read_raw,
+ .driver_module = THIS_MODULE,
+};
+
+static int adc12138_init(struct adc12138 *adc)
+{
+ int ret;
+ int status;
+ u8 mode;
+ u8 trash;
+
+ reinit_completion(&adc->complete);
+
+ ret = adc12138_mode_programming(adc, ADC12138_MODE_AUTO_CAL, &trash, 1);
+ if (ret)
+ return ret;
+
+ /* data output at this time has no significance */
+ status = adc12138_read_status(adc);
+ if (status < 0)
+ return status;
+
+ adc12138_wait_eoc(adc, msecs_to_jiffies(100));
+
+ status = adc12138_read_status(adc);
+ if (status & ADC12138_STATUS_CAL) {
+ dev_warn(&adc->spi->dev,
+ "Auto Cal sequence is still in progress: %#x\n",
+ status);
+ return -EIO;
+ }
+
+ switch (adc->acquisition_time) {
+ case 6:
+ mode = ADC12138_MODE_ACQUISITION_TIME_6;
+ break;
+ case 10:
+ mode = ADC12138_MODE_ACQUISITION_TIME_10;
+ break;
+ case 18:
+ mode = ADC12138_MODE_ACQUISITION_TIME_18;
+ break;
+ case 34:
+ mode = ADC12138_MODE_ACQUISITION_TIME_34;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return adc12138_mode_programming(adc, mode, &trash, 1);
+}
+
+static irqreturn_t adc12138_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct adc12138 *adc = iio_priv(indio_dev);
+ __be16 data[20] = { }; /* 16x 2 bytes ADC data + 8 bytes timestamp */
+ __be16 trash;
+ int ret;
+ int scan_index;
+ int i = 0;
+
+ mutex_lock(&adc->lock);
+
+ for_each_set_bit(scan_index, indio_dev->active_scan_mask,
+ indio_dev->masklength) {
+ const struct iio_chan_spec *scan_chan =
+ &indio_dev->channels[scan_index];
+
+ reinit_completion(&adc->complete);
+
+ ret = adc12138_start_and_read_conv(adc, scan_chan,
+ i ? &data[i - 1] : &trash);
+ if (ret) {
+ dev_warn(&adc->spi->dev,
+ "failed to start conversion\n");
+ goto out;
+ }
+
+ ret = adc12138_wait_eoc(adc, msecs_to_jiffies(100));
+ if (ret) {
+ dev_warn(&adc->spi->dev, "wait eoc timeout\n");
+ goto out;
+ }
+
+ i++;
+ }
+
+ if (i) {
+ ret = adc12138_read_conv_data(adc, &data[i - 1]);
+ if (ret) {
+ dev_warn(&adc->spi->dev,
+ "failed to get conversion data\n");
+ goto out;
+ }
+ }
+
+ iio_push_to_buffers_with_timestamp(indio_dev, data,
+ iio_get_time_ns(indio_dev));
+out:
+ mutex_unlock(&adc->lock);
+
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t adc12138_eoc_handler(int irq, void *p)
+{
+ struct iio_dev *indio_dev = p;
+ struct adc12138 *adc = iio_priv(indio_dev);
+
+ complete(&adc->complete);
+
+ return IRQ_HANDLED;
+}
+
+static int adc12138_probe(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev;
+ struct adc12138 *adc;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ adc = iio_priv(indio_dev);
+ adc->spi = spi;
+ adc->id = spi_get_device_id(spi)->driver_data;
+ mutex_init(&adc->lock);
+ init_completion(&adc->complete);
+
+ indio_dev->name = spi_get_device_id(spi)->name;
+ indio_dev->dev.parent = &spi->dev;
+ indio_dev->info = &adc12138_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ switch (adc->id) {
+ case adc12130:
+ case adc12132:
+ indio_dev->channels = adc12132_channels;
+ indio_dev->num_channels = ARRAY_SIZE(adc12132_channels);
+ break;
+ case adc12138:
+ indio_dev->channels = adc12138_channels;
+ indio_dev->num_channels = ARRAY_SIZE(adc12138_channels);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32(spi->dev.of_node, "ti,acquisition-time",
+ &adc->acquisition_time);
+ if (ret)
+ adc->acquisition_time = 10;
+
+ adc->cclk = devm_clk_get(&spi->dev, NULL);
+ if (IS_ERR(adc->cclk))
+ return PTR_ERR(adc->cclk);
+
+ adc->vref_p = devm_regulator_get(&spi->dev, "vref-p");
+ if (IS_ERR(adc->vref_p))
+ return PTR_ERR(adc->vref_p);
+
+ adc->vref_n = devm_regulator_get_optional(&spi->dev, "vref-n");
+ if (IS_ERR(adc->vref_n)) {
+ /*
+ * Assume vref_n is 0V if an optional regulator is not
+ * specified, otherwise return the error code.
+ */
+ ret = PTR_ERR(adc->vref_n);
+ if (ret != -ENODEV)
+ return ret;
+ }
+
+ ret = devm_request_irq(&spi->dev, spi->irq, adc12138_eoc_handler,
+ IRQF_TRIGGER_RISING, indio_dev->name, indio_dev);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(adc->cclk);
+ if (ret)
+ return ret;
+
+ ret = regulator_enable(adc->vref_p);
+ if (ret)
+ goto err_clk_disable;
+
+ if (!IS_ERR(adc->vref_n)) {
+ ret = regulator_enable(adc->vref_n);
+ if (ret)
+ goto err_vref_p_disable;
+ }
+
+ ret = adc12138_init(adc);
+ if (ret)
+ goto err_vref_n_disable;
+
+ spi_set_drvdata(spi, indio_dev);
+
+ ret = iio_triggered_buffer_setup(indio_dev, NULL,
+ adc12138_trigger_handler, NULL);
+ if (ret)
+ goto err_vref_n_disable;
+
+ ret = iio_device_register(indio_dev);
+ if (ret)
+ goto err_buffer_cleanup;
+
+ return 0;
+err_buffer_cleanup:
+ iio_triggered_buffer_cleanup(indio_dev);
+err_vref_n_disable:
+ if (!IS_ERR(adc->vref_n))
+ regulator_disable(adc->vref_n);
+err_vref_p_disable:
+ regulator_disable(adc->vref_p);
+err_clk_disable:
+ clk_disable_unprepare(adc->cclk);
+
+ return ret;
+}
+
+static int adc12138_remove(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev = spi_get_drvdata(spi);
+ struct adc12138 *adc = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+ iio_triggered_buffer_cleanup(indio_dev);
+ if (!IS_ERR(adc->vref_n))
+ regulator_disable(adc->vref_n);
+ regulator_disable(adc->vref_p);
+ clk_disable_unprepare(adc->cclk);
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+
+static const struct of_device_id adc12138_dt_ids[] = {
+ { .compatible = "ti,adc12130", },
+ { .compatible = "ti,adc12132", },
+ { .compatible = "ti,adc12138", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, adc12138_dt_ids);
+
+#endif
+
+static const struct spi_device_id adc12138_id[] = {
+ { "adc12130", adc12130 },
+ { "adc12132", adc12132 },
+ { "adc12138", adc12138 },
+ {}
+};
+MODULE_DEVICE_TABLE(spi, adc12138_id);
+
+static struct spi_driver adc12138_driver = {
+ .driver = {
+ .name = "adc12138",
+ .of_match_table = of_match_ptr(adc12138_dt_ids),
+ },
+ .probe = adc12138_probe,
+ .remove = adc12138_remove,
+ .id_table = adc12138_id,
+};
+module_spi_driver(adc12138_driver);
+
+MODULE_AUTHOR("Akinobu Mita <akinobu.mita@gmail.com>");
+MODULE_DESCRIPTION("ADC12130/ADC12132/ADC12138 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c
index 066abaf..cde6f13 100644
--- a/drivers/iio/adc/ti-ads1015.c
+++ b/drivers/iio/adc/ti-ads1015.c
@@ -522,6 +522,7 @@ static int ads1015_get_channels_config_of(struct i2c_client *client)
if (pga > 6) {
dev_err(&client->dev, "invalid gain on %s\n",
node->full_name);
+ of_node_put(node);
return -EINVAL;
}
}
@@ -532,6 +533,7 @@ static int ads1015_get_channels_config_of(struct i2c_client *client)
dev_err(&client->dev,
"invalid data_rate on %s\n",
node->full_name);
+ of_node_put(node);
return -EINVAL;
}
}
diff --git a/drivers/iio/adc/ti-ads8688.c b/drivers/iio/adc/ti-ads8688.c
index c400439..4a16349 100644
--- a/drivers/iio/adc/ti-ads8688.c
+++ b/drivers/iio/adc/ti-ads8688.c
@@ -438,7 +438,7 @@ static int ads8688_probe(struct spi_device *spi)
return 0;
error_out:
- if (!IS_ERR_OR_NULL(st->reg))
+ if (!IS_ERR(st->reg))
regulator_disable(st->reg);
return ret;
@@ -451,7 +451,7 @@ static int ads8688_remove(struct spi_device *spi)
iio_device_unregister(indio_dev);
- if (!IS_ERR_OR_NULL(st->reg))
+ if (!IS_ERR(st->reg))
regulator_disable(st->reg);
return 0;
diff --git a/drivers/iio/buffer/industrialio-triggered-buffer.c b/drivers/iio/buffer/industrialio-triggered-buffer.c
index 4b2858b..d3db1fc 100644
--- a/drivers/iio/buffer/industrialio-triggered-buffer.c
+++ b/drivers/iio/buffer/industrialio-triggered-buffer.c
@@ -98,6 +98,48 @@ void iio_triggered_buffer_cleanup(struct iio_dev *indio_dev)
}
EXPORT_SYMBOL(iio_triggered_buffer_cleanup);
+static void devm_iio_triggered_buffer_clean(struct device *dev, void *res)
+{
+ iio_triggered_buffer_cleanup(*(struct iio_dev **)res);
+}
+
+int devm_iio_triggered_buffer_setup(struct device *dev,
+ struct iio_dev *indio_dev,
+ irqreturn_t (*h)(int irq, void *p),
+ irqreturn_t (*thread)(int irq, void *p),
+ const struct iio_buffer_setup_ops *ops)
+{
+ struct iio_dev **ptr;
+ int ret;
+
+ ptr = devres_alloc(devm_iio_triggered_buffer_clean, sizeof(*ptr),
+ GFP_KERNEL);
+ if (!ptr)
+ return -ENOMEM;
+
+ *ptr = indio_dev;
+
+ ret = iio_triggered_buffer_setup(indio_dev, h, thread, ops);
+ if (!ret)
+ devres_add(dev, ptr);
+ else
+ devres_free(ptr);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(devm_iio_triggered_buffer_setup);
+
+void devm_iio_triggered_buffer_cleanup(struct device *dev,
+ struct iio_dev *indio_dev)
+{
+ int rc;
+
+ rc = devres_release(dev, devm_iio_triggered_buffer_clean,
+ devm_iio_device_match, indio_dev);
+ WARN_ON(rc);
+}
+EXPORT_SYMBOL_GPL(devm_iio_triggered_buffer_cleanup);
+
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("IIO helper functions for setting up triggered buffers");
MODULE_LICENSE("GPL");
diff --git a/drivers/iio/chemical/vz89x.c b/drivers/iio/chemical/vz89x.c
index 652649d..8e0e441 100644
--- a/drivers/iio/chemical/vz89x.c
+++ b/drivers/iio/chemical/vz89x.c
@@ -19,25 +19,55 @@
#include <linux/mutex.h>
#include <linux/init.h>
#include <linux/i2c.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#define VZ89X_REG_MEASUREMENT 0x09
-#define VZ89X_REG_MEASUREMENT_SIZE 6
+#define VZ89X_REG_MEASUREMENT_RD_SIZE 6
+#define VZ89X_REG_MEASUREMENT_WR_SIZE 3
#define VZ89X_VOC_CO2_IDX 0
#define VZ89X_VOC_SHORT_IDX 1
#define VZ89X_VOC_TVOC_IDX 2
#define VZ89X_VOC_RESISTANCE_IDX 3
+#define VZ89TE_REG_MEASUREMENT 0x0c
+#define VZ89TE_REG_MEASUREMENT_RD_SIZE 7
+#define VZ89TE_REG_MEASUREMENT_WR_SIZE 6
+
+#define VZ89TE_VOC_TVOC_IDX 0
+#define VZ89TE_VOC_CO2_IDX 1
+#define VZ89TE_VOC_RESISTANCE_IDX 2
+
+enum {
+ VZ89X,
+ VZ89TE,
+};
+
+struct vz89x_chip_data;
+
struct vz89x_data {
struct i2c_client *client;
+ const struct vz89x_chip_data *chip;
struct mutex lock;
int (*xfer)(struct vz89x_data *data, u8 cmd);
+ bool is_valid;
unsigned long last_update;
- u8 buffer[VZ89X_REG_MEASUREMENT_SIZE];
+ u8 buffer[VZ89TE_REG_MEASUREMENT_RD_SIZE];
+};
+
+struct vz89x_chip_data {
+ bool (*valid)(struct vz89x_data *data);
+ const struct iio_chan_spec *channels;
+ u8 num_channels;
+
+ u8 cmd;
+ u8 read_size;
+ u8 write_size;
};
static const struct iio_chan_spec vz89x_channels[] = {
@@ -70,6 +100,40 @@ static const struct iio_chan_spec vz89x_channels[] = {
.info_mask_separate =
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
.address = VZ89X_VOC_RESISTANCE_IDX,
+ .scan_index = -1,
+ .scan_type = {
+ .endianness = IIO_LE,
+ },
+ },
+};
+
+static const struct iio_chan_spec vz89te_channels[] = {
+ {
+ .type = IIO_CONCENTRATION,
+ .channel2 = IIO_MOD_VOC,
+ .modified = 1,
+ .info_mask_separate =
+ BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_RAW),
+ .address = VZ89TE_VOC_TVOC_IDX,
+ },
+
+ {
+ .type = IIO_CONCENTRATION,
+ .channel2 = IIO_MOD_CO2,
+ .modified = 1,
+ .info_mask_separate =
+ BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_RAW),
+ .address = VZ89TE_VOC_CO2_IDX,
+ },
+ {
+ .type = IIO_RESISTANCE,
+ .info_mask_separate =
+ BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
+ .address = VZ89TE_VOC_RESISTANCE_IDX,
+ .scan_index = -1,
+ .scan_type = {
+ .endianness = IIO_BE,
+ },
},
};
@@ -93,29 +157,45 @@ static const struct attribute_group vz89x_attrs_group = {
* always zero, and by also confirming the VOC_short isn't zero.
*/
-static int vz89x_measurement_is_valid(struct vz89x_data *data)
+static bool vz89x_measurement_is_valid(struct vz89x_data *data)
{
if (data->buffer[VZ89X_VOC_SHORT_IDX] == 0)
- return 1;
+ return true;
- return !!(data->buffer[VZ89X_REG_MEASUREMENT_SIZE - 1] > 0);
+ return !!(data->buffer[data->chip->read_size - 1] > 0);
+}
+
+/* VZ89TE device has a modified CRC-8 two complement check */
+static bool vz89te_measurement_is_valid(struct vz89x_data *data)
+{
+ u8 crc = 0;
+ int i, sum = 0;
+
+ for (i = 0; i < (data->chip->read_size - 1); i++) {
+ sum = crc + data->buffer[i];
+ crc = sum;
+ crc += sum / 256;
+ }
+
+ return !((0xff - crc) == data->buffer[data->chip->read_size - 1]);
}
static int vz89x_i2c_xfer(struct vz89x_data *data, u8 cmd)
{
+ const struct vz89x_chip_data *chip = data->chip;
struct i2c_client *client = data->client;
struct i2c_msg msg[2];
int ret;
- u8 buf[3] = { cmd, 0, 0};
+ u8 buf[6] = { cmd, 0, 0, 0, 0, 0xf3 };
msg[0].addr = client->addr;
msg[0].flags = client->flags;
- msg[0].len = 3;
+ msg[0].len = chip->write_size;
msg[0].buf = (char *) &buf;
msg[1].addr = client->addr;
msg[1].flags = client->flags | I2C_M_RD;
- msg[1].len = VZ89X_REG_MEASUREMENT_SIZE;
+ msg[1].len = chip->read_size;
msg[1].buf = (char *) &data->buffer;
ret = i2c_transfer(client->adapter, msg, 2);
@@ -133,7 +213,7 @@ static int vz89x_smbus_xfer(struct vz89x_data *data, u8 cmd)
if (ret < 0)
return ret;
- for (i = 0; i < VZ89X_REG_MEASUREMENT_SIZE; i++) {
+ for (i = 0; i < data->chip->read_size; i++) {
ret = i2c_smbus_read_byte(client);
if (ret < 0)
return ret;
@@ -145,30 +225,47 @@ static int vz89x_smbus_xfer(struct vz89x_data *data, u8 cmd)
static int vz89x_get_measurement(struct vz89x_data *data)
{
+ const struct vz89x_chip_data *chip = data->chip;
int ret;
/* sensor can only be polled once a second max per datasheet */
if (!time_after(jiffies, data->last_update + HZ))
- return 0;
+ return data->is_valid ? 0 : -EAGAIN;
+
+ data->is_valid = false;
+ data->last_update = jiffies;
- ret = data->xfer(data, VZ89X_REG_MEASUREMENT);
+ ret = data->xfer(data, chip->cmd);
if (ret < 0)
return ret;
- ret = vz89x_measurement_is_valid(data);
+ ret = chip->valid(data);
if (ret)
return -EAGAIN;
- data->last_update = jiffies;
+ data->is_valid = true;
return 0;
}
-static int vz89x_get_resistance_reading(struct vz89x_data *data)
+static int vz89x_get_resistance_reading(struct vz89x_data *data,
+ struct iio_chan_spec const *chan,
+ int *val)
{
- u8 *buf = &data->buffer[VZ89X_VOC_RESISTANCE_IDX];
+ u8 *tmp = (u8 *) &data->buffer[chan->address];
- return buf[0] | (buf[1] << 8);
+ switch (chan->scan_type.endianness) {
+ case IIO_LE:
+ *val = le32_to_cpup((__le32 *) tmp) & GENMASK(23, 0);
+ break;
+ case IIO_BE:
+ *val = be32_to_cpup((__be32 *) tmp) >> 8;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
}
static int vz89x_read_raw(struct iio_dev *indio_dev,
@@ -187,15 +284,15 @@ static int vz89x_read_raw(struct iio_dev *indio_dev,
if (ret)
return ret;
- switch (chan->address) {
- case VZ89X_VOC_CO2_IDX:
- case VZ89X_VOC_SHORT_IDX:
- case VZ89X_VOC_TVOC_IDX:
+ switch (chan->type) {
+ case IIO_CONCENTRATION:
*val = data->buffer[chan->address];
return IIO_VAL_INT;
- case VZ89X_VOC_RESISTANCE_IDX:
- *val = vz89x_get_resistance_reading(data);
- return IIO_VAL_INT;
+ case IIO_RESISTANCE:
+ ret = vz89x_get_resistance_reading(data, chan, val);
+ if (!ret)
+ return IIO_VAL_INT;
+ break;
default:
return -EINVAL;
}
@@ -210,12 +307,12 @@ static int vz89x_read_raw(struct iio_dev *indio_dev,
}
break;
case IIO_CHAN_INFO_OFFSET:
- switch (chan->address) {
- case VZ89X_VOC_CO2_IDX:
+ switch (chan->channel2) {
+ case IIO_MOD_CO2:
*val = 44;
*val2 = 250000;
return IIO_VAL_INT_PLUS_MICRO;
- case VZ89X_VOC_TVOC_IDX:
+ case IIO_MOD_VOC:
*val = -13;
return IIO_VAL_INT;
default:
@@ -232,11 +329,43 @@ static const struct iio_info vz89x_info = {
.driver_module = THIS_MODULE,
};
+static const struct vz89x_chip_data vz89x_chips[] = {
+ {
+ .valid = vz89x_measurement_is_valid,
+
+ .cmd = VZ89X_REG_MEASUREMENT,
+ .read_size = VZ89X_REG_MEASUREMENT_RD_SIZE,
+ .write_size = VZ89X_REG_MEASUREMENT_WR_SIZE,
+
+ .channels = vz89x_channels,
+ .num_channels = ARRAY_SIZE(vz89x_channels),
+ },
+ {
+ .valid = vz89te_measurement_is_valid,
+
+ .cmd = VZ89TE_REG_MEASUREMENT,
+ .read_size = VZ89TE_REG_MEASUREMENT_RD_SIZE,
+ .write_size = VZ89TE_REG_MEASUREMENT_WR_SIZE,
+
+ .channels = vz89te_channels,
+ .num_channels = ARRAY_SIZE(vz89te_channels),
+ },
+};
+
+static const struct of_device_id vz89x_dt_ids[] = {
+ { .compatible = "sgx,vz89x", .data = (void *) VZ89X },
+ { .compatible = "sgx,vz89te", .data = (void *) VZ89TE },
+ { }
+};
+MODULE_DEVICE_TABLE(of, vz89x_dt_ids);
+
static int vz89x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct iio_dev *indio_dev;
struct vz89x_data *data;
+ const struct of_device_id *of_id;
+ int chip_id;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
@@ -251,8 +380,15 @@ static int vz89x_probe(struct i2c_client *client,
else
return -EOPNOTSUPP;
+ of_id = of_match_device(vz89x_dt_ids, &client->dev);
+ if (!of_id)
+ chip_id = id->driver_data;
+ else
+ chip_id = (unsigned long)of_id->data;
+
i2c_set_clientdata(client, indio_dev);
data->client = client;
+ data->chip = &vz89x_chips[chip_id];
data->last_update = jiffies - HZ;
mutex_init(&data->lock);
@@ -261,24 +397,19 @@ static int vz89x_probe(struct i2c_client *client,
indio_dev->name = dev_name(&client->dev);
indio_dev->modes = INDIO_DIRECT_MODE;
- indio_dev->channels = vz89x_channels;
- indio_dev->num_channels = ARRAY_SIZE(vz89x_channels);
+ indio_dev->channels = data->chip->channels;
+ indio_dev->num_channels = data->chip->num_channels;
return devm_iio_device_register(&client->dev, indio_dev);
}
static const struct i2c_device_id vz89x_id[] = {
- { "vz89x", 0 },
+ { "vz89x", VZ89X },
+ { "vz89te", VZ89TE },
{ }
};
MODULE_DEVICE_TABLE(i2c, vz89x_id);
-static const struct of_device_id vz89x_dt_ids[] = {
- { .compatible = "sgx,vz89x" },
- { }
-};
-MODULE_DEVICE_TABLE(of, vz89x_dt_ids);
-
static struct i2c_driver vz89x_driver = {
.driver = {
.name = "vz89x",
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
index 5264ed6..a3cce3a 100644
--- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
+++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
@@ -199,8 +199,7 @@ error_ret:
}
EXPORT_SYMBOL(hid_sensor_setup_trigger);
-#ifdef CONFIG_PM
-static int hid_sensor_suspend(struct device *dev)
+static int __maybe_unused hid_sensor_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
@@ -209,7 +208,7 @@ static int hid_sensor_suspend(struct device *dev)
return _hid_sensor_power_state(attrb, false);
}
-static int hid_sensor_resume(struct device *dev)
+static int __maybe_unused hid_sensor_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
@@ -218,7 +217,7 @@ static int hid_sensor_resume(struct device *dev)
return 0;
}
-static int hid_sensor_runtime_resume(struct device *dev)
+static int __maybe_unused hid_sensor_runtime_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
@@ -226,8 +225,6 @@ static int hid_sensor_runtime_resume(struct device *dev)
return _hid_sensor_power_state(attrb, true);
}
-#endif
-
const struct dev_pm_ops hid_sensor_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(hid_sensor_suspend, hid_sensor_resume)
SET_RUNTIME_PM_OPS(hid_sensor_suspend,
diff --git a/drivers/iio/common/st_sensors/st_sensors_buffer.c b/drivers/iio/common/st_sensors/st_sensors_buffer.c
index d06e728..fe7775b 100644
--- a/drivers/iio/common/st_sensors/st_sensors_buffer.c
+++ b/drivers/iio/common/st_sensors/st_sensors_buffer.c
@@ -63,7 +63,7 @@ irqreturn_t st_sensors_trigger_handler(int irq, void *p)
* the hardware trigger) and the hw_timestamp may get updated.
* By storing it in a local variable first, we are safe.
*/
- if (sdata->hw_irq_trigger)
+ if (iio_trigger_using_own(indio_dev))
timestamp = sdata->hw_timestamp;
else
timestamp = iio_get_time_ns(indio_dev);
diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c
index 2d5282e..285a64a 100644
--- a/drivers/iio/common/st_sensors/st_sensors_core.c
+++ b/drivers/iio/common/st_sensors/st_sensors_core.c
@@ -234,39 +234,35 @@ int st_sensors_power_enable(struct iio_dev *indio_dev)
int err;
/* Regulators not mandatory, but if requested we should enable them. */
- pdata->vdd = devm_regulator_get_optional(indio_dev->dev.parent, "vdd");
- if (!IS_ERR(pdata->vdd)) {
- err = regulator_enable(pdata->vdd);
- if (err != 0) {
- dev_warn(&indio_dev->dev,
- "Failed to enable specified Vdd supply\n");
- return err;
- }
- } else {
- err = PTR_ERR(pdata->vdd);
- if (err != -ENODEV)
- return err;
+ pdata->vdd = devm_regulator_get(indio_dev->dev.parent, "vdd");
+ if (IS_ERR(pdata->vdd)) {
+ dev_err(&indio_dev->dev, "unable to get Vdd supply\n");
+ return PTR_ERR(pdata->vdd);
+ }
+ err = regulator_enable(pdata->vdd);
+ if (err != 0) {
+ dev_warn(&indio_dev->dev,
+ "Failed to enable specified Vdd supply\n");
+ return err;
}
- pdata->vdd_io = devm_regulator_get_optional(indio_dev->dev.parent, "vddio");
- if (!IS_ERR(pdata->vdd_io)) {
- err = regulator_enable(pdata->vdd_io);
- if (err != 0) {
- dev_warn(&indio_dev->dev,
- "Failed to enable specified Vdd_IO supply\n");
- goto st_sensors_disable_vdd;
- }
- } else {
+ pdata->vdd_io = devm_regulator_get(indio_dev->dev.parent, "vddio");
+ if (IS_ERR(pdata->vdd_io)) {
+ dev_err(&indio_dev->dev, "unable to get Vdd_IO supply\n");
err = PTR_ERR(pdata->vdd_io);
- if (err != -ENODEV)
- goto st_sensors_disable_vdd;
+ goto st_sensors_disable_vdd;
+ }
+ err = regulator_enable(pdata->vdd_io);
+ if (err != 0) {
+ dev_warn(&indio_dev->dev,
+ "Failed to enable specified Vdd_IO supply\n");
+ goto st_sensors_disable_vdd;
}
return 0;
st_sensors_disable_vdd:
- if (!IS_ERR_OR_NULL(pdata->vdd))
- regulator_disable(pdata->vdd);
+ regulator_disable(pdata->vdd);
return err;
}
EXPORT_SYMBOL(st_sensors_power_enable);
@@ -275,11 +271,8 @@ void st_sensors_power_disable(struct iio_dev *indio_dev)
{
struct st_sensor_data *pdata = iio_priv(indio_dev);
- if (!IS_ERR_OR_NULL(pdata->vdd))
- regulator_disable(pdata->vdd);
-
- if (!IS_ERR_OR_NULL(pdata->vdd_io))
- regulator_disable(pdata->vdd_io);
+ regulator_disable(pdata->vdd);
+ regulator_disable(pdata->vdd_io);
}
EXPORT_SYMBOL(st_sensors_power_disable);
diff --git a/drivers/iio/common/st_sensors/st_sensors_trigger.c b/drivers/iio/common/st_sensors/st_sensors_trigger.c
index e66f12e..fa73e67 100644
--- a/drivers/iio/common/st_sensors/st_sensors_trigger.c
+++ b/drivers/iio/common/st_sensors/st_sensors_trigger.c
@@ -66,7 +66,7 @@ static int st_sensors_new_samples_available(struct iio_dev *indio_dev,
* @irq: irq number
* @p: private handler data
*/
-irqreturn_t st_sensors_irq_handler(int irq, void *p)
+static irqreturn_t st_sensors_irq_handler(int irq, void *p)
{
struct iio_trigger *trig = p;
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
@@ -82,7 +82,7 @@ irqreturn_t st_sensors_irq_handler(int irq, void *p)
* @irq: irq number
* @p: private handler data
*/
-irqreturn_t st_sensors_irq_thread(int irq, void *p)
+static irqreturn_t st_sensors_irq_thread(int irq, void *p)
{
struct iio_trigger *trig = p;
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
index b9f0442..120b244 100644
--- a/drivers/iio/dac/Kconfig
+++ b/drivers/iio/dac/Kconfig
@@ -190,6 +190,16 @@ config CIO_DAC
base port addresses for the devices may be configured via the base
array module parameter.
+config AD8801
+ tristate "Analog Devices AD8801/AD8803 DAC driver"
+ depends on SPI_MASTER
+ help
+ Say yes here to build support for Analog Devices AD8801, AD8803 Digital to
+ Analog Converters (DAC).
+
+ To compile this driver as a module choose M here: the module will be called
+ ad8801.
+
config LPC18XX_DAC
tristate "NXP LPC18xx DAC driver"
depends on ARCH_LPC18XX || COMPILE_TEST
@@ -254,16 +264,6 @@ config MCP4922
To compile this driver as a module, choose M here: the module
will be called mcp4922.
-config STX104
- tristate "Apex Embedded Systems STX104 DAC driver"
- depends on X86 && ISA_BUS_API
- select GPIOLIB
- help
- Say yes here to build support for the 2-channel DAC and GPIO on the
- Apex Embedded Systems STX104 integrated analog PC/104 card. The base
- port addresses for the devices may be configured via the base array
- module parameter.
-
config VF610_DAC
tristate "Vybrid vf610 DAC driver"
depends on OF
diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile
index b1a1206..27642bb 100644
--- a/drivers/iio/dac/Makefile
+++ b/drivers/iio/dac/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_AD5764) += ad5764.o
obj-$(CONFIG_AD5791) += ad5791.o
obj-$(CONFIG_AD5686) += ad5686.o
obj-$(CONFIG_AD7303) += ad7303.o
+obj-$(CONFIG_AD8801) += ad8801.o
obj-$(CONFIG_CIO_DAC) += cio-dac.o
obj-$(CONFIG_LPC18XX_DAC) += lpc18xx_dac.o
obj-$(CONFIG_M62332) += m62332.o
@@ -27,5 +28,4 @@ obj-$(CONFIG_MAX517) += max517.o
obj-$(CONFIG_MAX5821) += max5821.o
obj-$(CONFIG_MCP4725) += mcp4725.o
obj-$(CONFIG_MCP4922) += mcp4922.o
-obj-$(CONFIG_STX104) += stx104.o
obj-$(CONFIG_VF610_DAC) += vf610_dac.o
diff --git a/drivers/iio/dac/ad5755.c b/drivers/iio/dac/ad5755.c
index 0fde593..5f79682 100644
--- a/drivers/iio/dac/ad5755.c
+++ b/drivers/iio/dac/ad5755.c
@@ -655,7 +655,7 @@ static struct ad5755_platform_data *ad5755_parse_dt(struct device *dev)
devnr = 0;
for_each_child_of_node(np, pp) {
- if (devnr > AD5755_NUM_CHANNELS) {
+ if (devnr >= AD5755_NUM_CHANNELS) {
dev_err(dev,
"There is to many channels defined in DT\n");
goto error_out;
diff --git a/drivers/iio/dac/ad8801.c b/drivers/iio/dac/ad8801.c
new file mode 100644
index 0000000..f06faa1
--- /dev/null
+++ b/drivers/iio/dac/ad8801.c
@@ -0,0 +1,239 @@
+/*
+ * IIO DAC driver for Analog Devices AD8801 DAC
+ *
+ * Copyright (C) 2016 Gwenhael Goavec-Merou
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ */
+
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+#include <linux/sysfs.h>
+
+#define AD8801_CFG_ADDR_OFFSET 8
+
+enum ad8801_device_ids {
+ ID_AD8801,
+ ID_AD8803,
+};
+
+struct ad8801_state {
+ struct spi_device *spi;
+ unsigned char dac_cache[8]; /* Value write on each channel */
+ unsigned int vrefh_mv;
+ unsigned int vrefl_mv;
+ struct regulator *vrefh_reg;
+ struct regulator *vrefl_reg;
+
+ __be16 data ____cacheline_aligned;
+};
+
+static int ad8801_spi_write(struct ad8801_state *state,
+ u8 channel, unsigned char value)
+{
+ state->data = cpu_to_be16((channel << AD8801_CFG_ADDR_OFFSET) | value);
+ return spi_write(state->spi, &state->data, sizeof(state->data));
+}
+
+static int ad8801_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val, int val2, long mask)
+{
+ struct ad8801_state *state = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ if (val >= 256 || val < 0)
+ return -EINVAL;
+
+ ret = ad8801_spi_write(state, chan->channel, val);
+ if (ret == 0)
+ state->dac_cache[chan->channel] = val;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int ad8801_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val, int *val2, long info)
+{
+ struct ad8801_state *state = iio_priv(indio_dev);
+
+ switch (info) {
+ case IIO_CHAN_INFO_RAW:
+ *val = state->dac_cache[chan->channel];
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ *val = state->vrefh_mv - state->vrefl_mv;
+ *val2 = 8;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ case IIO_CHAN_INFO_OFFSET:
+ *val = state->vrefl_mv;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+
+ return -EINVAL;
+}
+
+static const struct iio_info ad8801_info = {
+ .read_raw = ad8801_read_raw,
+ .write_raw = ad8801_write_raw,
+ .driver_module = THIS_MODULE,
+};
+
+#define AD8801_CHANNEL(chan) { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .output = 1, \
+ .channel = chan, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_OFFSET), \
+}
+
+static const struct iio_chan_spec ad8801_channels[] = {
+ AD8801_CHANNEL(0),
+ AD8801_CHANNEL(1),
+ AD8801_CHANNEL(2),
+ AD8801_CHANNEL(3),
+ AD8801_CHANNEL(4),
+ AD8801_CHANNEL(5),
+ AD8801_CHANNEL(6),
+ AD8801_CHANNEL(7),
+};
+
+static int ad8801_probe(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev;
+ struct ad8801_state *state;
+ const struct spi_device_id *id;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*state));
+ if (indio_dev == NULL)
+ return -ENOMEM;
+
+ state = iio_priv(indio_dev);
+ state->spi = spi;
+ id = spi_get_device_id(spi);
+
+ state->vrefh_reg = devm_regulator_get(&spi->dev, "vrefh");
+ if (IS_ERR(state->vrefh_reg)) {
+ dev_err(&spi->dev, "Vrefh regulator not specified\n");
+ return PTR_ERR(state->vrefh_reg);
+ }
+
+ ret = regulator_enable(state->vrefh_reg);
+ if (ret) {
+ dev_err(&spi->dev, "Failed to enable vrefh regulator: %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = regulator_get_voltage(state->vrefh_reg);
+ if (ret < 0) {
+ dev_err(&spi->dev, "Failed to read vrefh regulator: %d\n",
+ ret);
+ goto error_disable_vrefh_reg;
+ }
+ state->vrefh_mv = ret / 1000;
+
+ if (id->driver_data == ID_AD8803) {
+ state->vrefl_reg = devm_regulator_get(&spi->dev, "vrefl");
+ if (IS_ERR(state->vrefl_reg)) {
+ dev_err(&spi->dev, "Vrefl regulator not specified\n");
+ ret = PTR_ERR(state->vrefl_reg);
+ goto error_disable_vrefh_reg;
+ }
+
+ ret = regulator_enable(state->vrefl_reg);
+ if (ret) {
+ dev_err(&spi->dev, "Failed to enable vrefl regulator: %d\n",
+ ret);
+ goto error_disable_vrefh_reg;
+ }
+
+ ret = regulator_get_voltage(state->vrefl_reg);
+ if (ret < 0) {
+ dev_err(&spi->dev, "Failed to read vrefl regulator: %d\n",
+ ret);
+ goto error_disable_vrefl_reg;
+ }
+ state->vrefl_mv = ret / 1000;
+ } else {
+ state->vrefl_mv = 0;
+ state->vrefl_reg = NULL;
+ }
+
+ spi_set_drvdata(spi, indio_dev);
+ indio_dev->dev.parent = &spi->dev;
+ indio_dev->info = &ad8801_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = ad8801_channels;
+ indio_dev->num_channels = ARRAY_SIZE(ad8801_channels);
+ indio_dev->name = id->name;
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ dev_err(&spi->dev, "Failed to register iio device: %d\n",
+ ret);
+ goto error_disable_vrefl_reg;
+ }
+
+ return 0;
+
+error_disable_vrefl_reg:
+ if (state->vrefl_reg)
+ regulator_disable(state->vrefl_reg);
+error_disable_vrefh_reg:
+ regulator_disable(state->vrefh_reg);
+ return ret;
+}
+
+static int ad8801_remove(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev = spi_get_drvdata(spi);
+ struct ad8801_state *state = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+ if (state->vrefl_reg)
+ regulator_disable(state->vrefl_reg);
+ regulator_disable(state->vrefh_reg);
+
+ return 0;
+}
+
+static const struct spi_device_id ad8801_ids[] = {
+ {"ad8801", ID_AD8801},
+ {"ad8803", ID_AD8803},
+ {}
+};
+MODULE_DEVICE_TABLE(spi, ad8801_ids);
+
+static struct spi_driver ad8801_driver = {
+ .driver = {
+ .name = "ad8801",
+ },
+ .probe = ad8801_probe,
+ .remove = ad8801_remove,
+ .id_table = ad8801_ids,
+};
+module_spi_driver(ad8801_driver);
+
+MODULE_AUTHOR("Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>");
+MODULE_DESCRIPTION("Analog Devices AD8801/AD8803 DAC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index d2b8899..fc340ed 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -1308,7 +1308,7 @@ static void devm_iio_device_release(struct device *dev, void *res)
iio_device_free(*(struct iio_dev **)res);
}
-static int devm_iio_device_match(struct device *dev, void *res, void *data)
+int devm_iio_device_match(struct device *dev, void *res, void *data)
{
struct iio_dev **r = res;
if (!r || !*r) {
@@ -1317,6 +1317,7 @@ static int devm_iio_device_match(struct device *dev, void *res, void *data)
}
return *r == data;
}
+EXPORT_SYMBOL_GPL(devm_iio_device_match);
/**
* devm_iio_device_alloc - Resource-managed iio_device_alloc()
diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c
index 0ebfc92..90fac8e 100644
--- a/drivers/iio/industrialio-event.c
+++ b/drivers/iio/industrialio-event.c
@@ -57,6 +57,11 @@ bool iio_event_enabled(const struct iio_event_interface *ev_int)
*
* Note: The caller must make sure that this function is not running
* concurrently for the same indio_dev more than once.
+ *
+ * This function may be safely used as soon as a valid reference to iio_dev has
+ * been obtained via iio_device_alloc(), but any events that are submitted
+ * before iio_device_register() has successfully completed will be silently
+ * discarded.
**/
int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp)
{
@@ -64,6 +69,9 @@ int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp)
struct iio_event_data ev;
int copied;
+ if (!ev_int)
+ return 0;
+
/* Does anyone care? */
if (iio_event_enabled(ev_int)) {
diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c
index 7ad82fd..e1e1048 100644
--- a/drivers/iio/industrialio-trigger.c
+++ b/drivers/iio/industrialio-trigger.c
@@ -119,6 +119,22 @@ void iio_trigger_unregister(struct iio_trigger *trig_info)
}
EXPORT_SYMBOL(iio_trigger_unregister);
+int iio_trigger_set_immutable(struct iio_dev *indio_dev, struct iio_trigger *trig)
+{
+ if (!indio_dev || !trig)
+ return -EINVAL;
+
+ mutex_lock(&indio_dev->mlock);
+ WARN_ON(indio_dev->trig_readonly);
+
+ indio_dev->trig = iio_trigger_get(trig);
+ indio_dev->trig_readonly = true;
+ mutex_unlock(&indio_dev->mlock);
+
+ return 0;
+}
+EXPORT_SYMBOL(iio_trigger_set_immutable);
+
/* Search for trigger by name, assuming iio_trigger_list_lock held */
static struct iio_trigger *__iio_trigger_find_by_name(const char *name)
{
@@ -255,6 +271,14 @@ static int iio_trigger_attach_poll_func(struct iio_trigger *trig,
goto out_free_irq;
}
+ /*
+ * Check if we just registered to our own trigger: we determine that
+ * this is the case if the IIO device and the trigger device share the
+ * same parent device.
+ */
+ if (pf->indio_dev->dev.parent == trig->dev.parent)
+ trig->attached_own_device = true;
+
return ret;
out_free_irq:
@@ -279,6 +303,8 @@ static int iio_trigger_detach_poll_func(struct iio_trigger *trig,
if (ret)
return ret;
}
+ if (pf->indio_dev->dev.parent == trig->dev.parent)
+ trig->attached_own_device = false;
iio_trigger_put_irq(trig, pf->irq);
free_irq(pf->irq, pf);
module_put(pf->indio_dev->info->driver_module);
@@ -384,6 +410,10 @@ static ssize_t iio_trigger_write_current(struct device *dev,
mutex_unlock(&indio_dev->mlock);
return -EBUSY;
}
+ if (indio_dev->trig_readonly) {
+ mutex_unlock(&indio_dev->mlock);
+ return -EPERM;
+ }
mutex_unlock(&indio_dev->mlock);
trig = iio_trigger_find_by_name(buf, len);
@@ -622,6 +652,71 @@ void devm_iio_trigger_free(struct device *dev, struct iio_trigger *iio_trig)
}
EXPORT_SYMBOL_GPL(devm_iio_trigger_free);
+static void devm_iio_trigger_unreg(struct device *dev, void *res)
+{
+ iio_trigger_unregister(*(struct iio_trigger **)res);
+}
+
+/**
+ * devm_iio_trigger_register - Resource-managed iio_trigger_register()
+ * @dev: device this trigger was allocated for
+ * @trig_info: trigger to register
+ *
+ * Managed iio_trigger_register(). The IIO trigger registered with this
+ * function is automatically unregistered on driver detach. This function
+ * calls iio_trigger_register() internally. Refer to that function for more
+ * information.
+ *
+ * If an iio_trigger registered with this function needs to be unregistered
+ * separately, devm_iio_trigger_unregister() must be used.
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int devm_iio_trigger_register(struct device *dev, struct iio_trigger *trig_info)
+{
+ struct iio_trigger **ptr;
+ int ret;
+
+ ptr = devres_alloc(devm_iio_trigger_unreg, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return -ENOMEM;
+
+ *ptr = trig_info;
+ ret = iio_trigger_register(trig_info);
+ if (!ret)
+ devres_add(dev, ptr);
+ else
+ devres_free(ptr);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(devm_iio_trigger_register);
+
+/**
+ * devm_iio_trigger_unregister - Resource-managed iio_trigger_unregister()
+ * @dev: device this iio_trigger belongs to
+ * @trig_info: the trigger associated with the device
+ *
+ * Unregister trigger registered with devm_iio_trigger_register().
+ */
+void devm_iio_trigger_unregister(struct device *dev,
+ struct iio_trigger *trig_info)
+{
+ int rc;
+
+ rc = devres_release(dev, devm_iio_trigger_unreg, devm_iio_trigger_match,
+ trig_info);
+ WARN_ON(rc);
+}
+EXPORT_SYMBOL_GPL(devm_iio_trigger_unregister);
+
+bool iio_trigger_using_own(struct iio_dev *indio_dev)
+{
+ return indio_dev->trig->attached_own_device;
+}
+EXPORT_SYMBOL(iio_trigger_using_own);
+
void iio_device_register_trigger_consumer(struct iio_dev *indio_dev)
{
indio_dev->groups[indio_dev->groupcounter++] =
diff --git a/drivers/iio/magnetometer/ak8974.c b/drivers/iio/magnetometer/ak8974.c
index e70e4e2..2173531 100644
--- a/drivers/iio/magnetometer/ak8974.c
+++ b/drivers/iio/magnetometer/ak8974.c
@@ -783,8 +783,7 @@ static int __exit ak8974_remove(struct i2c_client *i2c)
return 0;
}
-#ifdef CONFIG_PM
-static int ak8974_runtime_suspend(struct device *dev)
+static int __maybe_unused ak8974_runtime_suspend(struct device *dev)
{
struct ak8974 *ak8974 =
iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
@@ -795,7 +794,7 @@ static int ak8974_runtime_suspend(struct device *dev)
return 0;
}
-static int ak8974_runtime_resume(struct device *dev)
+static int __maybe_unused ak8974_runtime_resume(struct device *dev)
{
struct ak8974 *ak8974 =
iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
@@ -822,7 +821,6 @@ out_regulator_disable:
return ret;
}
-#endif /* CONFIG_PM */
static const struct dev_pm_ops ak8974_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
@@ -847,7 +845,6 @@ MODULE_DEVICE_TABLE(of, ak8974_of_match);
static struct i2c_driver ak8974_driver = {
.driver = {
.name = "ak8974",
- .owner = THIS_MODULE,
.pm = &ak8974_dev_pm_ops,
.of_match_table = of_match_ptr(ak8974_of_match),
},
diff --git a/drivers/iio/pressure/ms5611_core.c b/drivers/iio/pressure/ms5611_core.c
index feb41f8..a74ed1f 100644
--- a/drivers/iio/pressure/ms5611_core.c
+++ b/drivers/iio/pressure/ms5611_core.c
@@ -416,8 +416,7 @@ static int ms5611_init(struct iio_dev *indio_dev)
return 0;
err_regulator_disable:
- if (!IS_ERR_OR_NULL(st->vdd))
- regulator_disable(st->vdd);
+ regulator_disable(st->vdd);
return ret;
}
@@ -425,8 +424,7 @@ static void ms5611_fini(const struct iio_dev *indio_dev)
{
const struct ms5611_state *st = iio_priv(indio_dev);
- if (!IS_ERR_OR_NULL(st->vdd))
- regulator_disable(st->vdd);
+ regulator_disable(st->vdd);
}
int ms5611_probe(struct iio_dev *indio_dev, struct device *dev,
diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c
index 6f84f53..1f06282 100644
--- a/drivers/iio/proximity/sx9500.c
+++ b/drivers/iio/proximity/sx9500.c
@@ -1025,6 +1025,12 @@ static const struct acpi_device_id sx9500_acpi_match[] = {
};
MODULE_DEVICE_TABLE(acpi, sx9500_acpi_match);
+static const struct of_device_id sx9500_of_match[] = {
+ { .compatible = "semtech,sx9500", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, sx9500_of_match);
+
static const struct i2c_device_id sx9500_id[] = {
{"sx9500", 0},
{ },
@@ -1035,6 +1041,7 @@ static struct i2c_driver sx9500_driver = {
.driver = {
.name = SX9500_DRIVER_NAME,
.acpi_match_table = ACPI_PTR(sx9500_acpi_match),
+ .of_match_table = of_match_ptr(sx9500_of_match),
.pm = &sx9500_pm_ops,
},
.probe = sx9500_probe,
diff --git a/drivers/iio/temperature/maxim_thermocouple.c b/drivers/iio/temperature/maxim_thermocouple.c
index 030827e..39dd202 100644
--- a/drivers/iio/temperature/maxim_thermocouple.c
+++ b/drivers/iio/temperature/maxim_thermocouple.c
@@ -32,7 +32,7 @@ enum {
MAX31855,
};
-const struct iio_chan_spec max6675_channels[] = {
+static const struct iio_chan_spec max6675_channels[] = {
{ /* thermocouple temperature */
.type = IIO_TEMP,
.info_mask_separate =
@@ -49,7 +49,7 @@ const struct iio_chan_spec max6675_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(1),
};
-const struct iio_chan_spec max31855_channels[] = {
+static const struct iio_chan_spec max31855_channels[] = {
{ /* thermocouple temperature */
.type = IIO_TEMP,
.address = 2,
@@ -95,7 +95,7 @@ struct maxim_thermocouple_chip {
u32 status_bit;
};
-const struct maxim_thermocouple_chip maxim_thermocouple_chips[] = {
+static const struct maxim_thermocouple_chip maxim_thermocouple_chips[] = {
[MAX6675] = {
.channels = max6675_channels,
.num_channels = ARRAY_SIZE(max6675_channels),
diff --git a/drivers/staging/iio/accel/sca3000_core.c b/drivers/staging/iio/accel/sca3000_core.c
index b5625f5..61f3241 100644
--- a/drivers/staging/iio/accel/sca3000_core.c
+++ b/drivers/staging/iio/accel/sca3000_core.c
@@ -412,7 +412,7 @@ static const struct iio_event_spec sca3000_event = {
}, \
.event_spec = &sca3000_event, \
.num_event_specs = 1, \
- }
+ }
static const struct iio_chan_spec sca3000_channels[] = {
SCA3000_CHAN(0, IIO_MOD_X),
diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
index 854e2da..b4a0679 100644
--- a/include/linux/iio/iio.h
+++ b/include/linux/iio/iio.h
@@ -483,6 +483,7 @@ struct iio_buffer_setup_ops {
* @scan_timestamp: [INTERN] set if any buffers have requested timestamp
* @scan_index_timestamp:[INTERN] cache of the index to the timestamp
* @trig: [INTERN] current device trigger (buffer modes)
+ * @trig_readonly [INTERN] mark the current trigger immutable
* @pollfunc: [DRIVER] function run on trigger being received
* @pollfunc_event: [DRIVER] function run on events trigger being received
* @channels: [DRIVER] channel specification structure table
@@ -523,6 +524,7 @@ struct iio_dev {
bool scan_timestamp;
unsigned scan_index_timestamp;
struct iio_trigger *trig;
+ bool trig_readonly;
struct iio_poll_func *pollfunc;
struct iio_poll_func *pollfunc_event;
@@ -642,6 +644,7 @@ static inline struct iio_dev *iio_priv_to_dev(void *priv)
}
void iio_device_free(struct iio_dev *indio_dev);
+int devm_iio_device_match(struct device *dev, void *res, void *data);
struct iio_dev *devm_iio_device_alloc(struct device *dev, int sizeof_priv);
void devm_iio_device_free(struct device *dev, struct iio_dev *indio_dev);
struct iio_trigger *devm_iio_trigger_alloc(struct device *dev,
diff --git a/include/linux/iio/trigger.h b/include/linux/iio/trigger.h
index 1c9e028..4f1154f 100644
--- a/include/linux/iio/trigger.h
+++ b/include/linux/iio/trigger.h
@@ -56,6 +56,9 @@ struct iio_trigger_ops {
* @subirqs: [INTERN] information about the 'child' irqs.
* @pool: [INTERN] bitmap of irqs currently in use.
* @pool_lock: [INTERN] protection of the irq pool.
+ * @attached_own_device:[INTERN] if we are using our own device as trigger,
+ * i.e. if we registered a poll function to the same
+ * device as the one providing the trigger.
**/
struct iio_trigger {
const struct iio_trigger_ops *ops;
@@ -73,6 +76,7 @@ struct iio_trigger {
struct iio_subirq subirqs[CONFIG_IIO_CONSUMERS_PER_TRIGGER];
unsigned long pool[BITS_TO_LONGS(CONFIG_IIO_CONSUMERS_PER_TRIGGER)];
struct mutex pool_lock;
+ bool attached_own_device;
};
@@ -125,12 +129,27 @@ static inline void *iio_trigger_get_drvdata(struct iio_trigger *trig)
**/
int iio_trigger_register(struct iio_trigger *trig_info);
+int devm_iio_trigger_register(struct device *dev,
+ struct iio_trigger *trig_info);
+
/**
* iio_trigger_unregister() - unregister a trigger from the core
* @trig_info: trigger to be unregistered
**/
void iio_trigger_unregister(struct iio_trigger *trig_info);
+void devm_iio_trigger_unregister(struct device *dev,
+ struct iio_trigger *trig_info);
+
+/**
+ * iio_trigger_set_immutable() - set an immutable trigger on destination
+ *
+ * @indio_dev - IIO device structure containing the device
+ * @trig - trigger to assign to device
+ *
+ **/
+int iio_trigger_set_immutable(struct iio_dev *indio_dev, struct iio_trigger *trig);
+
/**
* iio_trigger_poll() - called on a trigger occurring
* @trig: trigger which occurred
@@ -145,6 +164,13 @@ irqreturn_t iio_trigger_generic_data_rdy_poll(int irq, void *private);
__printf(1, 2) struct iio_trigger *iio_trigger_alloc(const char *fmt, ...);
void iio_trigger_free(struct iio_trigger *trig);
+/**
+ * iio_trigger_using_own() - tells us if we use our own HW trigger ourselves
+ * @indio_dev: device to check
+ */
+bool iio_trigger_using_own(struct iio_dev *indio_dev);
+
+
#else
struct iio_trigger;
struct iio_trigger_ops;
diff --git a/include/linux/iio/triggered_buffer.h b/include/linux/iio/triggered_buffer.h
index f72f70d..3014561 100644
--- a/include/linux/iio/triggered_buffer.h
+++ b/include/linux/iio/triggered_buffer.h
@@ -12,4 +12,12 @@ int iio_triggered_buffer_setup(struct iio_dev *indio_dev,
const struct iio_buffer_setup_ops *setup_ops);
void iio_triggered_buffer_cleanup(struct iio_dev *indio_dev);
+int devm_iio_triggered_buffer_setup(struct device *dev,
+ struct iio_dev *indio_dev,
+ irqreturn_t (*h)(int irq, void *p),
+ irqreturn_t (*thread)(int irq, void *p),
+ const struct iio_buffer_setup_ops *ops);
+void devm_iio_triggered_buffer_cleanup(struct device *dev,
+ struct iio_dev *indio_dev);
+
#endif
diff --git a/tools/iio/iio_utils.c b/tools/iio/iio_utils.c
index 5eb6793..7a6d61c 100644
--- a/tools/iio/iio_utils.c
+++ b/tools/iio/iio_utils.c
@@ -121,10 +121,6 @@ int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used,
ret = -ENOENT;
while (ent = readdir(dp), ent)
- /*
- * Do we allow devices to override a generic name with
- * a specific one?
- */
if ((strcmp(builtname, ent->d_name) == 0) ||
(strcmp(builtname_generic, ent->d_name) == 0)) {
ret = asprintf(&filename,
@@ -178,6 +174,13 @@ int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used,
sysfsfp = 0;
free(filename);
filename = 0;
+
+ /*
+ * Avoid having a more generic entry overwriting
+ * the settings.
+ */
+ if (strcmp(builtname, ent->d_name) == 0)
+ break;
}
error_close_sysfsfp:
OpenPOWER on IntegriCloud