summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/sysfs-bus-iio9
-rw-r--r--Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt1
-rw-r--r--Documentation/devicetree/bindings/iio/adc/mcp320x.txt2
-rw-r--r--Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt6
-rw-r--r--Documentation/devicetree/bindings/iio/afe/current-sense-amplifier.txt26
-rw-r--r--Documentation/devicetree/bindings/iio/afe/current-sense-shunt.txt41
-rw-r--r--Documentation/devicetree/bindings/iio/afe/voltage-divider.txt53
-rw-r--r--Documentation/devicetree/bindings/iio/dac/ti,dac5571.txt24
-rw-r--r--Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt12
-rw-r--r--Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt1
-rw-r--r--MAINTAINERS17
-rw-r--r--drivers/iio/Kconfig1
-rw-r--r--drivers/iio/Makefile1
-rw-r--r--drivers/iio/accel/Kconfig24
-rw-r--r--drivers/iio/accel/Makefile2
-rw-r--r--drivers/iio/accel/adis16201.c321
-rw-r--r--drivers/iio/accel/adis16209.c (renamed from drivers/staging/iio/accel/adis16209.c)52
-rw-r--r--drivers/iio/accel/bmc150-accel-core.c23
-rw-r--r--drivers/iio/accel/sca3000.c13
-rw-r--r--drivers/iio/accel/st_accel_i2c.c1
-rw-r--r--drivers/iio/adc/ad7791.c87
-rw-r--r--drivers/iio/adc/meson_saradc.c83
-rw-r--r--drivers/iio/adc/stm32-adc-core.c66
-rw-r--r--drivers/iio/adc/stm32-adc.c47
-rw-r--r--drivers/iio/adc/stm32-dfsdm-adc.c13
-rw-r--r--drivers/iio/adc/stm32-dfsdm-core.c5
-rw-r--r--drivers/iio/adc/stx104.c11
-rw-r--r--drivers/iio/afe/Kconfig19
-rw-r--r--drivers/iio/afe/Makefile6
-rw-r--r--drivers/iio/afe/iio-rescale.c359
-rw-r--r--drivers/iio/chemical/atlas-ph-sensor.c14
-rw-r--r--drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c3
-rw-r--r--drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c9
-rw-r--r--drivers/iio/common/hid-sensors/hid-sensor-trigger.c9
-rw-r--r--drivers/iio/dac/Kconfig33
-rw-r--r--drivers/iio/dac/Makefile3
-rw-r--r--drivers/iio/dac/ad5686-spi.c93
-rw-r--r--drivers/iio/dac/ad5686.c311
-rw-r--r--drivers/iio/dac/ad5686.h121
-rw-r--r--drivers/iio/dac/ad5696-i2c.c97
-rw-r--r--drivers/iio/dac/ti-dac5571.c439
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_core.c275
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c86
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h22
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c43
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c12
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c52
-rw-r--r--drivers/iio/imu/st_lsm6dsx/Kconfig3
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h2
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c10
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c7
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c5
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c5
-rw-r--r--drivers/iio/light/cros_ec_light_prox.c3
-rw-r--r--drivers/iio/potentiometer/mcp4018.c41
-rw-r--r--drivers/iio/potentiometer/mcp4531.c145
-rw-r--r--drivers/iio/pressure/cros_ec_baro.c3
-rw-r--r--drivers/staging/iio/accel/Kconfig24
-rw-r--r--drivers/staging/iio/accel/Makefile2
-rw-r--r--drivers/staging/iio/accel/adis16201.c385
-rw-r--r--drivers/staging/iio/adc/ad7606_par.c6
-rw-r--r--drivers/staging/iio/adc/ad7780.c2
-rw-r--r--drivers/staging/iio/cdc/ad7746.c44
-rw-r--r--drivers/staging/iio/light/tsl2x7x.c935
-rw-r--r--drivers/staging/iio/light/tsl2x7x.h91
-rw-r--r--drivers/staging/iio/meter/ade7854-i2c.c238
-rw-r--r--drivers/staging/iio/meter/ade7854-spi.c268
-rw-r--r--drivers/staging/iio/meter/ade7854.c40
-rw-r--r--drivers/staging/iio/meter/ade7854.h16
-rw-r--r--drivers/staging/iio/resolver/ad2s1200.c35
-rw-r--r--include/linux/iio/adc/ad_sigma_delta.h24
-rw-r--r--include/linux/iio/common/cros_ec_sensors_core.h (renamed from drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.h)3
-rw-r--r--include/linux/iio/iio.h24
73 files changed, 3170 insertions, 2139 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
index 6a5f34b4d5b9..731146c3b138 100644
--- a/Documentation/ABI/testing/sysfs-bus-iio
+++ b/Documentation/ABI/testing/sysfs-bus-iio
@@ -190,6 +190,13 @@ Description:
but should match other such assignments on device).
Units after application of scale and offset are m/s^2.
+What: /sys/bus/iio/devices/iio:deviceX/in_angl_raw
+KernelVersion: 4.17
+Contact: linux-iio@vger.kernel.org
+Description:
+ Angle of rotation. Units after application of scale and offset
+ are radians.
+
What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_x_raw
What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_y_raw
What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_z_raw
@@ -297,6 +304,7 @@ What: /sys/bus/iio/devices/iio:deviceX/in_pressure_offset
What: /sys/bus/iio/devices/iio:deviceX/in_humidityrelative_offset
What: /sys/bus/iio/devices/iio:deviceX/in_magn_offset
What: /sys/bus/iio/devices/iio:deviceX/in_rot_offset
+What: /sys/bus/iio/devices/iio:deviceX/in_angl_offset
KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org
Description:
@@ -350,6 +358,7 @@ What: /sys/bus/iio/devices/iio:deviceX/in_humidityrelative_scale
What: /sys/bus/iio/devices/iio:deviceX/in_velocity_sqrt(x^2+y^2+z^2)_scale
What: /sys/bus/iio/devices/iio:deviceX/in_illuminance_scale
What: /sys/bus/iio/devices/iio:deviceX/in_countY_scale
+What: /sys/bus/iio/devices/iio:deviceX/in_angl_scale
KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org
Description:
diff --git a/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt b/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt
index 1e6ee3deb4fa..d1acd5ea2737 100644
--- a/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt
+++ b/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt
@@ -7,6 +7,7 @@ Required properties:
- "amlogic,meson-gxbb-saradc" for GXBB
- "amlogic,meson-gxl-saradc" for GXL
- "amlogic,meson-gxm-saradc" for GXM
+ - "amlogic,meson-axg-saradc" for AXG
along with the generic "amlogic,meson-saradc"
- reg: the physical base address and length of the registers
- interrupts: the interrupt indicating end of sampling
diff --git a/Documentation/devicetree/bindings/iio/adc/mcp320x.txt b/Documentation/devicetree/bindings/iio/adc/mcp320x.txt
index 7d64753df949..56373d643f76 100644
--- a/Documentation/devicetree/bindings/iio/adc/mcp320x.txt
+++ b/Documentation/devicetree/bindings/iio/adc/mcp320x.txt
@@ -49,7 +49,7 @@ Required properties:
Examples:
spi_controller {
mcp3x0x@0 {
- compatible = "mcp3002";
+ compatible = "microchip,mcp3002";
reg = <0>;
spi-max-frequency = <1000000>;
vref-supply = <&vref_reg>;
diff --git a/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt b/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt
index e8bb8243e92c..f1ead43a1a95 100644
--- a/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt
+++ b/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt
@@ -24,8 +24,11 @@ Required properties:
- compatible: Should be one of:
"st,stm32f4-adc-core"
"st,stm32h7-adc-core"
+ "st,stm32mp1-adc-core"
- reg: Offset and length of the ADC block register set.
-- interrupts: Must contain the interrupt for ADC block.
+- interrupts: One or more interrupts for ADC block. Some parts like stm32f4
+ and stm32h7 share a common ADC interrupt line. stm32mp1 has two separate
+ interrupt lines, one for each ADC within ADC block.
- clocks: Core can use up to two clocks, depending on part used:
- "adc" clock: for the analog circuitry, common to all ADCs.
It's required on stm32f4.
@@ -53,6 +56,7 @@ Required properties:
- compatible: Should be one of:
"st,stm32f4-adc"
"st,stm32h7-adc"
+ "st,stm32mp1-adc"
- reg: Offset of ADC instance in ADC block (e.g. may be 0x0, 0x100, 0x200).
- clocks: Input clock private to this ADC instance. It's required only on
stm32f4, that has per instance clock input for registers access.
diff --git a/Documentation/devicetree/bindings/iio/afe/current-sense-amplifier.txt b/Documentation/devicetree/bindings/iio/afe/current-sense-amplifier.txt
new file mode 100644
index 000000000000..0ddbaebba8ce
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/afe/current-sense-amplifier.txt
@@ -0,0 +1,26 @@
+Current Sense Amplifier
+=======================
+
+When an io-channel measures the output voltage from a current sense
+amplifier, the interesting mesaurement is almost always the current
+through the sense resistor, not the voltage output. This binding
+describes such a current sense circuit.
+
+Required properties:
+- compatible : "current-sense-amplifier"
+- io-channels : Channel node of a voltage io-channel.
+- sense-resistor-micro-ohms : The sense resistance in microohms.
+
+Optional properties:
+- sense-gain-mult: Amplifier gain multiplier. The default is <1>.
+- sense-gain-div: Amplifier gain divider. The default is <1>.
+
+Example:
+
+sysi {
+ compatible = "current-sense-amplifier";
+ io-channels = <&tiadc 0>;
+
+ sense-resistor-micro-ohms = <20000>;
+ sense-gain-mul = <50>;
+};
diff --git a/Documentation/devicetree/bindings/iio/afe/current-sense-shunt.txt b/Documentation/devicetree/bindings/iio/afe/current-sense-shunt.txt
new file mode 100644
index 000000000000..8e7b3e408a52
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/afe/current-sense-shunt.txt
@@ -0,0 +1,41 @@
+Current Sense Shunt
+===================
+
+When an io-channel measures the voltage over a current sense shunt,
+the interesting mesaurement is almost always the current through the
+shunt, not the voltage over it. This binding describes such a current
+sense circuit.
+
+Required properties:
+- compatible : "current-sense-shunt"
+- io-channels : Channel node of a voltage io-channel.
+- shunt-resistor-micro-ohms : The shunt resistance in microohms.
+
+Example:
+The system current is measured by measuring the voltage over a
+3.3 ohms shunt resistor.
+
+sysi {
+ compatible = "current-sense-shunt";
+ io-channels = <&tiadc 0>;
+
+ /* Divide the voltage by 3300000/1000000 (or 3.3) for the current. */
+ shunt-resistor-micro-ohms = <3300000>;
+};
+
+&i2c {
+ tiadc: adc@48 {
+ compatible = "ti,ads1015";
+ reg = <0x48>;
+ #io-channel-cells = <1>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ channel@0 { /* IN0,IN1 differential */
+ reg = <0>;
+ ti,gain = <1>;
+ ti,datarate = <4>;
+ };
+ };
+};
diff --git a/Documentation/devicetree/bindings/iio/afe/voltage-divider.txt b/Documentation/devicetree/bindings/iio/afe/voltage-divider.txt
new file mode 100644
index 000000000000..b452a8406107
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/afe/voltage-divider.txt
@@ -0,0 +1,53 @@
+Voltage divider
+===============
+
+When an io-channel measures the midpoint of a voltage divider, the
+interesting voltage is often the voltage over the full resistance
+of the divider. This binding describes the voltage divider in such
+a curcuit.
+
+ Vin ----.
+ |
+ .-----.
+ | R |
+ '-----'
+ |
+ +---- Vout
+ |
+ .-----.
+ | Rout|
+ '-----'
+ |
+ GND
+
+Required properties:
+- compatible : "voltage-divider"
+- io-channels : Channel node of a voltage io-channel measuring Vout.
+- output-ohms : Resistance Rout over which the output voltage is measured.
+ See full-ohms.
+- full-ohms : Resistance R + Rout for the full divider. The io-channel
+ is scaled by the Rout / (R + Rout) quotient.
+
+Example:
+The system voltage is circa 12V, but divided down with a 22/222
+voltage divider (R = 200 Ohms, Rout = 22 Ohms) and fed to an ADC.
+
+sysv {
+ compatible = "voltage-divider";
+ io-channels = <&maxadc 1>;
+
+ /* Scale the system voltage by 22/222 to fit the ADC range. */
+ output-ohms = <22>;
+ full-ohms = <222>; /* 200 + 22 */
+};
+
+&spi {
+ maxadc: adc@0 {
+ compatible = "maxim,max1027";
+ reg = <0>;
+ #io-channel-cells = <1>;
+ interrupt-parent = <&gpio5>;
+ interrupts = <15 IRQ_TYPE_EDGE_RISING>;
+ spi-max-frequency = <1000000>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/iio/dac/ti,dac5571.txt b/Documentation/devicetree/bindings/iio/dac/ti,dac5571.txt
new file mode 100644
index 000000000000..03af6b9a4d07
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/dac/ti,dac5571.txt
@@ -0,0 +1,24 @@
+* Texas Instruments DAC5571 Family
+
+Required properties:
+ - compatible: Should contain
+ "ti,dac5571"
+ "ti,dac6571"
+ "ti,dac7571"
+ "ti,dac5574"
+ "ti,dac6574"
+ "ti,dac7574"
+ "ti,dac5573"
+ "ti,dac6573"
+ "ti,dac7573"
+ - reg: Should contain the DAC I2C address
+
+Optional properties:
+ - vref-supply: The regulator supply for DAC reference voltage
+
+Example:
+dac@0 {
+ compatible = "ti,dac5571";
+ reg = <0x4C>;
+ vref-supply = <&vdd_supply>;
+};
diff --git a/Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt b/Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt
index 2b4514592f83..5f4777e8cc9e 100644
--- a/Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt
+++ b/Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt
@@ -8,10 +8,16 @@ Required properties:
"invensense,mpu6500"
"invensense,mpu9150"
"invensense,mpu9250"
+ "invensense,mpu9255"
"invensense,icm20608"
- reg : the I2C address of the sensor
- interrupt-parent : should be the phandle for the interrupt controller
- - interrupts : interrupt mapping for GPIO IRQ
+ - interrupts: interrupt mapping for IRQ. It should be configured with flags
+ IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_EDGE_RISING, IRQ_TYPE_LEVEL_LOW or
+ IRQ_TYPE_EDGE_FALLING.
+
+ Refer to interrupt-controller/interrupts.txt for generic interrupt client node
+ bindings.
Optional properties:
- mount-matrix: an optional 3x3 mounting rotation matrix
@@ -24,7 +30,7 @@ Example:
compatible = "invensense,mpu6050";
reg = <0x68>;
interrupt-parent = <&gpio1>;
- interrupts = <18 1>;
+ interrupts = <18 IRQ_TYPE_EDGE_RISING>;
mount-matrix = "-0.984807753012208", /* x0 */
"0", /* y0 */
"-0.173648177666930", /* z0 */
@@ -41,7 +47,7 @@ Example:
compatible = "invensense,mpu9250";
reg = <0x68>;
interrupt-parent = <&gpio3>;
- interrupts = <21 1>;
+ interrupts = <21 IRQ_TYPE_LEVEL_HIGH>;
i2c-gate {
#address-cells = <1>;
#size-cells = <0>;
diff --git a/Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt b/Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt
index 1ff1af799c76..ef8a8566c63f 100644
--- a/Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt
+++ b/Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt
@@ -6,6 +6,7 @@ Required properties:
"st,lsm6ds3h"
"st,lsm6dsl"
"st,lsm6dsm"
+ "st,ism330dlc"
- reg: i2c address of the sensor / spi cs line
Optional properties:
diff --git a/MAINTAINERS b/MAINTAINERS
index afc87293d786..4b65225d443a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -794,6 +794,14 @@ M: Michael Hanselmann <linux-kernel@hansmi.ch>
S: Supported
F: drivers/macintosh/ams/
+ANALOG DEVICES INC AD5686 DRIVER
+M: Stefan Popa <stefan.popa@analog.com>
+L: linux-pm@vger.kernel.org
+W: http://ez.analog.com/community/linux-device-drivers
+S: Supported
+F: drivers/iio/dac/ad5686*
+F: drivers/iio/dac/ad5696*
+
ANALOG DEVICES INC AD9389B DRIVER
M: Hans Verkuil <hans.verkuil@cisco.com>
L: linux-media@vger.kernel.org
@@ -6914,6 +6922,15 @@ F: drivers/staging/iio/
F: include/linux/iio/
F: tools/iio/
+IIO UNIT CONVERTER
+M: Peter Rosin <peda@axentia.se>
+L: linux-iio@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/iio/afe/current-sense-amplifier.txt
+F: Documentation/devicetree/bindings/iio/afe/current-sense-shunt.txt
+F: Documentation/devicetree/bindings/iio/afe/voltage-divider.txt
+F: drivers/iio/afe/iio-rescale.c
+
IKANOS/ADI EAGLE ADSL USB DRIVER
M: Matthieu Castet <castet.matthieu@free.fr>
M: Stanislaw Gruszka <stf_xl@wp.pl>
diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
index b3c8c6ef0dff..d69e85a8bdc3 100644
--- a/drivers/iio/Kconfig
+++ b/drivers/iio/Kconfig
@@ -70,6 +70,7 @@ config IIO_TRIGGERED_EVENT
source "drivers/iio/accel/Kconfig"
source "drivers/iio/adc/Kconfig"
+source "drivers/iio/afe/Kconfig"
source "drivers/iio/amplifiers/Kconfig"
source "drivers/iio/chemical/Kconfig"
source "drivers/iio/common/Kconfig"
diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
index b16b2e9ddc40..d8cba9c229c0 100644
--- a/drivers/iio/Makefile
+++ b/drivers/iio/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_IIO_TRIGGERED_EVENT) += industrialio-triggered-event.o
obj-y += accel/
obj-y += adc/
+obj-y += afe/
obj-y += amplifiers/
obj-y += buffer/
obj-y += chemical/
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index c6d9517d7611..62ae7e5abcfa 100644
--- a/drivers/iio/accel/Kconfig
+++ b/drivers/iio/accel/Kconfig
@@ -5,6 +5,30 @@
menu "Accelerometers"
+config ADIS16201
+ tristate "Analog Devices ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer"
+ depends on SPI
+ select IIO_ADIS_LIB
+ select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
+ help
+ Say Y here to build support for Analog Devices adis16201 dual-axis
+ digital inclinometer and accelerometer.
+
+ To compile this driver as a module, say M here: the module will
+ be called adis16201.
+
+config ADIS16209
+ tristate "Analog Devices ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer"
+ depends on SPI
+ select IIO_ADIS_LIB
+ select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
+ help
+ Say Y here to build support for Analog Devices adis16209 dual-axis digital inclinometer
+ and accelerometer.
+
+ To compile this driver as a module, say M here: the module will be
+ called adis16209.
+
config ADXL345
tristate
diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile
index 368aedb6377a..636d4d1b2990 100644
--- a/drivers/iio/accel/Makefile
+++ b/drivers/iio/accel/Makefile
@@ -4,6 +4,8 @@
#
# When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_ADIS16201) += adis16201.o
+obj-$(CONFIG_ADIS16209) += adis16209.o
obj-$(CONFIG_ADXL345) += adxl345_core.o
obj-$(CONFIG_ADXL345_I2C) += adxl345_i2c.o
obj-$(CONFIG_ADXL345_SPI) += adxl345_spi.o
diff --git a/drivers/iio/accel/adis16201.c b/drivers/iio/accel/adis16201.c
new file mode 100644
index 000000000000..4c1d482ea73a
--- /dev/null
+++ b/drivers/iio/accel/adis16201.c
@@ -0,0 +1,321 @@
+/*
+ * ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/sysfs.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/imu/adis.h>
+
+#define ADIS16201_STARTUP_DELAY_MS 220
+#define ADIS16201_FLASH_CNT 0x00
+
+/* Data Output Register Information */
+#define ADIS16201_SUPPLY_OUT_REG 0x02
+#define ADIS16201_XACCL_OUT_REG 0x04
+#define ADIS16201_YACCL_OUT_REG 0x06
+#define ADIS16201_AUX_ADC_REG 0x08
+#define ADIS16201_TEMP_OUT_REG 0x0A
+#define ADIS16201_XINCL_OUT_REG 0x0C
+#define ADIS16201_YINCL_OUT_REG 0x0E
+
+/* Calibration Register Definition */
+#define ADIS16201_XACCL_OFFS_REG 0x10
+#define ADIS16201_YACCL_OFFS_REG 0x12
+#define ADIS16201_XACCL_SCALE_REG 0x14
+#define ADIS16201_YACCL_SCALE_REG 0x16
+#define ADIS16201_XINCL_OFFS_REG 0x18
+#define ADIS16201_YINCL_OFFS_REG 0x1A
+#define ADIS16201_XINCL_SCALE_REG 0x1C
+#define ADIS16201_YINCL_SCALE_REG 0x1E
+
+/* Alarm Register Definition */
+#define ADIS16201_ALM_MAG1_REG 0x20
+#define ADIS16201_ALM_MAG2_REG 0x22
+#define ADIS16201_ALM_SMPL1_REG 0x24
+#define ADIS16201_ALM_SMPL2_REG 0x26
+#define ADIS16201_ALM_CTRL_REG 0x28
+
+#define ADIS16201_AUX_DAC_REG 0x30
+#define ADIS16201_GPIO_CTRL_REG 0x32
+#define ADIS16201_SMPL_PRD_REG 0x36
+/* Operation, filter configuration */
+#define ADIS16201_AVG_CNT_REG 0x38
+#define ADIS16201_SLP_CNT_REG 0x3A
+
+/* Miscellaneous Control Register Definition */
+#define ADIS16201_MSC_CTRL_REG 0x34
+#define ADIS16201_MSC_CTRL_SELF_TEST_EN BIT(8)
+/* Data-ready enable: 1 = enabled, 0 = disabled */
+#define ADIS16201_MSC_CTRL_DATA_RDY_EN BIT(2)
+/* Data-ready polarity: 1 = active high, 0 = active low */
+#define ADIS16201_MSC_CTRL_ACTIVE_DATA_RDY_HIGH BIT(1)
+/* Data-ready line selection: 1 = DIO1, 0 = DIO0 */
+#define ADIS16201_MSC_CTRL_DATA_RDY_DIO1 BIT(0)
+
+/* Diagnostics System Status Register Definition */
+#define ADIS16201_DIAG_STAT_REG 0x3C
+#define ADIS16201_DIAG_STAT_ALARM2 BIT(9)
+#define ADIS16201_DIAG_STAT_ALARM1 BIT(8)
+#define ADIS16201_DIAG_STAT_SPI_FAIL_BIT 3
+#define ADIS16201_DIAG_STAT_FLASH_UPT_FAIL_BIT 2
+/* Power supply above 3.625 V */
+#define ADIS16201_DIAG_STAT_POWER_HIGH_BIT 1
+/* Power supply below 3.15 V */
+#define ADIS16201_DIAG_STAT_POWER_LOW_BIT 0
+
+/* System Command Register Definition */
+#define ADIS16201_GLOB_CMD_REG 0x3E
+#define ADIS16201_GLOB_CMD_SW_RESET BIT(7)
+#define ADIS16201_GLOB_CMD_FACTORY_RESET BIT(1)
+
+#define ADIS16201_ERROR_ACTIVE BIT(14)
+
+enum adis16201_scan {
+ ADIS16201_SCAN_ACC_X,
+ ADIS16201_SCAN_ACC_Y,
+ ADIS16201_SCAN_INCLI_X,
+ ADIS16201_SCAN_INCLI_Y,
+ ADIS16201_SCAN_SUPPLY,
+ ADIS16201_SCAN_AUX_ADC,
+ ADIS16201_SCAN_TEMP,
+};
+
+static const u8 adis16201_addresses[] = {
+ [ADIS16201_SCAN_ACC_X] = ADIS16201_XACCL_OFFS_REG,
+ [ADIS16201_SCAN_ACC_Y] = ADIS16201_YACCL_OFFS_REG,
+ [ADIS16201_SCAN_INCLI_X] = ADIS16201_XINCL_OFFS_REG,
+ [ADIS16201_SCAN_INCLI_Y] = ADIS16201_YINCL_OFFS_REG,
+};
+
+static int adis16201_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2,
+ long mask)
+{
+ struct adis *st = iio_priv(indio_dev);
+ int ret;
+ int bits;
+ u8 addr;
+ s16 val16;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ return adis_single_conversion(indio_dev, chan,
+ ADIS16201_ERROR_ACTIVE, val);
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->type) {
+ case IIO_VOLTAGE:
+ if (chan->channel == 0) {
+ /* Voltage base units are mV hence 1.22 mV */
+ *val = 1;
+ *val2 = 220000;
+ } else {
+ /* Voltage base units are mV hence 0.61 mV */
+ *val = 0;
+ *val2 = 610000;
+ }
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_TEMP:
+ *val = -470;
+ *val2 = 0;
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_ACCEL:
+ /*
+ * IIO base unit for sensitivity of accelerometer
+ * is milli g.
+ * 1 LSB represents 0.244 mg.
+ */
+ *val = 0;
+ *val2 = IIO_G_TO_M_S_2(462400);
+ return IIO_VAL_INT_PLUS_NANO;
+ case IIO_INCLI:
+ *val = 0;
+ *val2 = 100000;
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case IIO_CHAN_INFO_OFFSET:
+ /*
+ * The raw ADC value is 1278 when the temperature
+ * is 25 degrees and the scale factor per milli
+ * degree celcius is -470.
+ */
+ *val = 25000 / -470 - 1278;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_CALIBBIAS:
+ switch (chan->type) {
+ case IIO_ACCEL:
+ bits = 12;
+ break;
+ case IIO_INCLI:
+ bits = 9;
+ break;
+ default:
+ return -EINVAL;
+ }
+ addr = adis16201_addresses[chan->scan_index];
+ ret = adis_read_reg_16(st, addr, &val16);
+ if (ret)
+ return ret;
+
+ *val = sign_extend32(val16, bits - 1);
+ return IIO_VAL_INT;
+ }
+
+ return -EINVAL;
+}
+
+static int adis16201_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val,
+ int val2,
+ long mask)
+{
+ struct adis *st = iio_priv(indio_dev);
+ int m;
+
+ if (mask != IIO_CHAN_INFO_CALIBBIAS)
+ return -EINVAL;
+
+ switch (chan->type) {
+ case IIO_ACCEL:
+ m = GENMASK(11, 0);
+ break;
+ case IIO_INCLI:
+ m = GENMASK(8, 0);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return adis_write_reg_16(st, adis16201_addresses[chan->scan_index],
+ val & m);
+}
+
+static const struct iio_chan_spec adis16201_channels[] = {
+ ADIS_SUPPLY_CHAN(ADIS16201_SUPPLY_OUT_REG, ADIS16201_SCAN_SUPPLY, 0,
+ 12),
+ ADIS_TEMP_CHAN(ADIS16201_TEMP_OUT_REG, ADIS16201_SCAN_TEMP, 0, 12),
+ ADIS_ACCEL_CHAN(X, ADIS16201_XACCL_OUT_REG, ADIS16201_SCAN_ACC_X,
+ BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14),
+ ADIS_ACCEL_CHAN(Y, ADIS16201_YACCL_OUT_REG, ADIS16201_SCAN_ACC_Y,
+ BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14),
+ ADIS_AUX_ADC_CHAN(ADIS16201_AUX_ADC_REG, ADIS16201_SCAN_AUX_ADC, 0, 12),
+ ADIS_INCLI_CHAN(X, ADIS16201_XINCL_OUT_REG, ADIS16201_SCAN_INCLI_X,
+ BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14),
+ ADIS_INCLI_CHAN(X, ADIS16201_YINCL_OUT_REG, ADIS16201_SCAN_INCLI_Y,
+ BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14),
+ IIO_CHAN_SOFT_TIMESTAMP(7)
+};
+
+static const struct iio_info adis16201_info = {
+ .read_raw = adis16201_read_raw,
+ .write_raw = adis16201_write_raw,
+ .update_scan_mode = adis_update_scan_mode,
+};
+
+static const char * const adis16201_status_error_msgs[] = {
+ [ADIS16201_DIAG_STAT_SPI_FAIL_BIT] = "SPI failure",
+ [ADIS16201_DIAG_STAT_FLASH_UPT_FAIL_BIT] = "Flash update failed",
+ [ADIS16201_DIAG_STAT_POWER_HIGH_BIT] = "Power supply above 3.625V",
+ [ADIS16201_DIAG_STAT_POWER_LOW_BIT] = "Power supply below 3.15V",
+};
+
+static const struct adis_data adis16201_data = {
+ .read_delay = 20,
+ .msc_ctrl_reg = ADIS16201_MSC_CTRL_REG,
+ .glob_cmd_reg = ADIS16201_GLOB_CMD_REG,
+ .diag_stat_reg = ADIS16201_DIAG_STAT_REG,
+
+ .self_test_mask = ADIS16201_MSC_CTRL_SELF_TEST_EN,
+ .self_test_no_autoclear = true,
+ .startup_delay = ADIS16201_STARTUP_DELAY_MS,
+
+ .status_error_msgs = adis16201_status_error_msgs,
+ .status_error_mask = BIT(ADIS16201_DIAG_STAT_SPI_FAIL_BIT) |
+ BIT(ADIS16201_DIAG_STAT_FLASH_UPT_FAIL_BIT) |
+ BIT(ADIS16201_DIAG_STAT_POWER_HIGH_BIT) |
+ BIT(ADIS16201_DIAG_STAT_POWER_LOW_BIT),
+};
+
+static int adis16201_probe(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev;
+ struct adis *st;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+ spi_set_drvdata(spi, indio_dev);
+
+ indio_dev->name = spi->dev.driver->name;
+ indio_dev->dev.parent = &spi->dev;
+ indio_dev->info = &adis16201_info;
+
+ indio_dev->channels = adis16201_channels;
+ indio_dev->num_channels = ARRAY_SIZE(adis16201_channels);
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = adis_init(st, indio_dev, spi, &adis16201_data);
+ if (ret)
+ return ret;
+
+ ret = adis_setup_buffer_and_trigger(st, indio_dev, NULL);
+ if (ret)
+ return ret;
+
+ ret = adis_initial_startup(st);
+ if (ret)
+ goto error_cleanup_buffer_trigger;
+
+ ret = iio_device_register(indio_dev);
+ if (ret < 0)
+ goto error_cleanup_buffer_trigger;
+
+ return 0;
+
+error_cleanup_buffer_trigger:
+ adis_cleanup_buffer_and_trigger(st, indio_dev);
+ return ret;
+}
+
+static int adis16201_remove(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev = spi_get_drvdata(spi);
+ struct adis *st = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+ adis_cleanup_buffer_and_trigger(st, indio_dev);
+
+ return 0;
+}
+
+static struct spi_driver adis16201_driver = {
+ .driver = {
+ .name = "adis16201",
+ },
+ .probe = adis16201_probe,
+ .remove = adis16201_remove,
+};
+module_spi_driver(adis16201_driver);
+
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("spi:adis16201");
diff --git a/drivers/staging/iio/accel/adis16209.c b/drivers/iio/accel/adis16209.c
index 72a18cfe81ee..f2dc3a5f0463 100644
--- a/drivers/staging/iio/accel/adis16209.c
+++ b/drivers/iio/accel/adis16209.c
@@ -6,7 +6,6 @@
* Licensed under the GPL-2 or later.
*/
-#include <linux/delay.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/list.h>
@@ -16,8 +15,6 @@
#include <linux/sysfs.h>
#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
-#include <linux/iio/buffer.h>
#include <linux/iio/imu/adis.h>
#define ADIS16209_STARTUP_DELAY_MS 220
@@ -71,13 +68,13 @@
#define ADIS16209_STAT_REG 0x3C
#define ADIS16209_STAT_ALARM2 BIT(9)
#define ADIS16209_STAT_ALARM1 BIT(8)
-#define ADIS16209_STAT_SELFTEST_FAIL_BIT 5
-#define ADIS16209_STAT_SPI_FAIL_BIT 3
-#define ADIS16209_STAT_FLASH_UPT_FAIL_BIT 2
+#define ADIS16209_STAT_SELFTEST_FAIL_BIT 5
+#define ADIS16209_STAT_SPI_FAIL_BIT 3
+#define ADIS16209_STAT_FLASH_UPT_FAIL_BIT 2
/* Power supply above 3.625 V */
-#define ADIS16209_STAT_POWER_HIGH_BIT 1
+#define ADIS16209_STAT_POWER_HIGH_BIT 1
/* Power supply below 3.15 V */
-#define ADIS16209_STAT_POWER_LOW_BIT 0
+#define ADIS16209_STAT_POWER_LOW_BIT 0
#define ADIS16209_CMD_REG 0x3E
#define ADIS16209_CMD_SW_RESET BIT(7)
@@ -115,25 +112,22 @@ static int adis16209_write_raw(struct iio_dev *indio_dev,
long mask)
{
struct adis *st = iio_priv(indio_dev);
- int bits;
- s16 val16;
- u8 addr;
+ int m;
- switch (mask) {
- case IIO_CHAN_INFO_CALIBBIAS:
- switch (chan->type) {
- case IIO_ACCEL:
- case IIO_INCLI:
- bits = 14;
- break;
- default:
- return -EINVAL;
- }
- val16 = val & ((1 << bits) - 1);
- addr = adis16209_addresses[chan->scan_index][0];
- return adis_write_reg_16(st, addr, val16);
+ if (mask != IIO_CHAN_INFO_CALIBBIAS)
+ return -EINVAL;
+
+ switch (chan->type) {
+ case IIO_ACCEL:
+ case IIO_INCLI:
+ m = GENMASK(13, 0);
+ break;
+ default:
+ return -EINVAL;
}
- return -EINVAL;
+
+ return adis_write_reg_16(st, adis16209_addresses[chan->scan_index][0],
+ val & m);
}
static int adis16209_read_raw(struct iio_dev *indio_dev,
@@ -195,7 +189,7 @@ static int adis16209_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_OFFSET:
/*
* The raw ADC value is 0x4FE when the temperature
- * is 25 degrees and the scale factor per milli
+ * is 45 degrees and the scale factor per milli
* degree celcius is -470.
*/
*val = 25000 / -470 - 0x4FE;
@@ -270,13 +264,14 @@ static const struct adis_data adis16209_data = {
static int adis16209_probe(struct spi_device *spi)
{
- int ret;
- struct adis *st;
struct iio_dev *indio_dev;
+ struct adis *st;
+ int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
+
st = iio_priv(indio_dev);
spi_set_drvdata(spi, indio_dev);
@@ -290,6 +285,7 @@ static int adis16209_probe(struct spi_device *spi)
ret = adis_init(st, indio_dev, spi, &adis16209_data);
if (ret)
return ret;
+
ret = adis_setup_buffer_and_trigger(st, indio_dev, NULL);
if (ret)
return ret;
diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c
index 208f2d9f0e8a..383c802eb5b8 100644
--- a/drivers/iio/accel/bmc150-accel-core.c
+++ b/drivers/iio/accel/bmc150-accel-core.c
@@ -837,29 +837,12 @@ static int bmc150_accel_fifo_transfer(struct bmc150_accel_data *data,
int sample_length = 3 * 2;
int ret;
int total_length = samples * sample_length;
- int i;
- size_t step = regmap_get_raw_read_max(data->regmap);
-
- if (!step || step > total_length)
- step = total_length;
- else if (step < total_length)
- step = sample_length;
-
- /*
- * Seems we have a bus with size limitation so we have to execute
- * multiple reads
- */
- for (i = 0; i < total_length; i += step) {
- ret = regmap_raw_read(data->regmap, BMC150_ACCEL_REG_FIFO_DATA,
- &buffer[i], step);
- if (ret)
- break;
- }
+ ret = regmap_raw_read(data->regmap, BMC150_ACCEL_REG_FIFO_DATA,
+ buffer, total_length);
if (ret)
dev_err(dev,
- "Error transferring data from fifo in single steps of %zu\n",
- step);
+ "Error transferring data from fifo: %d\n", ret);
return ret;
}
diff --git a/drivers/iio/accel/sca3000.c b/drivers/iio/accel/sca3000.c
index f33dadf7b262..4dceb75e3586 100644
--- a/drivers/iio/accel/sca3000.c
+++ b/drivers/iio/accel/sca3000.c
@@ -1277,7 +1277,7 @@ static int sca3000_configure_ring(struct iio_dev *indio_dev)
{
struct iio_buffer *buffer;
- buffer = iio_kfifo_allocate();
+ buffer = devm_iio_kfifo_allocate(&indio_dev->dev);
if (!buffer)
return -ENOMEM;
@@ -1287,11 +1287,6 @@ static int sca3000_configure_ring(struct iio_dev *indio_dev)
return 0;
}
-static void sca3000_unconfigure_ring(struct iio_dev *indio_dev)
-{
- iio_kfifo_free(indio_dev->buffer);
-}
-
static inline
int __sca3000_hw_ring_state_set(struct iio_dev *indio_dev, bool state)
{
@@ -1486,7 +1481,9 @@ static int sca3000_probe(struct spi_device *spi)
}
indio_dev->modes = INDIO_DIRECT_MODE;
- sca3000_configure_ring(indio_dev);
+ ret = sca3000_configure_ring(indio_dev);
+ if (ret)
+ return ret;
if (spi->irq) {
ret = request_threaded_irq(spi->irq,
@@ -1546,8 +1543,6 @@ static int sca3000_remove(struct spi_device *spi)
if (spi->irq)
free_irq(spi->irq, indio_dev);
- sca3000_unconfigure_ring(indio_dev);
-
return 0;
}
diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c
index 6bdec8c451e0..056dddb27236 100644
--- a/drivers/iio/accel/st_accel_i2c.c
+++ b/drivers/iio/accel/st_accel_i2c.c
@@ -107,6 +107,7 @@ MODULE_DEVICE_TABLE(of, st_accel_of_match);
#ifdef CONFIG_ACPI
static const struct acpi_device_id st_accel_acpi_match[] = {
+ {"SMO8840", LNG2DM},
{"SMO8A90", LNG2DM},
{ },
};
diff --git a/drivers/iio/adc/ad7791.c b/drivers/iio/adc/ad7791.c
index 70fbf92f9827..a9ff0695ddf7 100644
--- a/drivers/iio/adc/ad7791.c
+++ b/drivers/iio/adc/ad7791.c
@@ -153,6 +153,17 @@ struct ad7791_state {
const struct ad7791_chip_info *info;
};
+static const int ad7791_sample_freq_avail[8][2] = {
+ [AD7791_FILTER_RATE_120] = { 120, 0 },
+ [AD7791_FILTER_RATE_100] = { 100, 0 },
+ [AD7791_FILTER_RATE_33_3] = { 33, 300000 },
+ [AD7791_FILTER_RATE_20] = { 20, 0 },
+ [AD7791_FILTER_RATE_16_6] = { 16, 600000 },
+ [AD7791_FILTER_RATE_16_7] = { 16, 700000 },
+ [AD7791_FILTER_RATE_13_3] = { 13, 300000 },
+ [AD7791_FILTER_RATE_9_5] = { 9, 500000 },
+};
+
static struct ad7791_state *ad_sigma_delta_to_ad7791(struct ad_sigma_delta *sd)
{
return container_of(sd, struct ad7791_state, sd);
@@ -202,6 +213,7 @@ static int ad7791_read_raw(struct iio_dev *indio_dev,
{
struct ad7791_state *st = iio_priv(indio_dev);
bool unipolar = !!(st->mode & AD7791_MODE_UNIPOLAR);
+ unsigned int rate;
switch (info) {
case IIO_CHAN_INFO_RAW:
@@ -239,63 +251,56 @@ static int ad7791_read_raw(struct iio_dev *indio_dev,
*val2 = chan->scan_type.realbits - 1;
return IIO_VAL_FRACTIONAL_LOG2;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ rate = st->filter & AD7791_FILTER_RATE_MASK;
+ *val = ad7791_sample_freq_avail[rate][0];
+ *val2 = ad7791_sample_freq_avail[rate][1];
+ return IIO_VAL_INT_PLUS_MICRO;
}
return -EINVAL;
}
-static const char * const ad7791_sample_freq_avail[] = {
- [AD7791_FILTER_RATE_120] = "120",
- [AD7791_FILTER_RATE_100] = "100",
- [AD7791_FILTER_RATE_33_3] = "33.3",
- [AD7791_FILTER_RATE_20] = "20",
- [AD7791_FILTER_RATE_16_6] = "16.6",
- [AD7791_FILTER_RATE_16_7] = "16.7",
- [AD7791_FILTER_RATE_13_3] = "13.3",
- [AD7791_FILTER_RATE_9_5] = "9.5",
-};
-
-static ssize_t ad7791_read_frequency(struct device *dev,
- struct device_attribute *attr, char *buf)
+static int ad7791_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val, int val2, long mask)
{
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7791_state *st = iio_priv(indio_dev);
- unsigned int rate = st->filter & AD7791_FILTER_RATE_MASK;
-
- return sprintf(buf, "%s\n", ad7791_sample_freq_avail[rate]);
-}
-
-static ssize_t ad7791_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 ad7791_state *st = iio_priv(indio_dev);
- int i, ret;
-
- i = sysfs_match_string(ad7791_sample_freq_avail, buf);
- if (i < 0)
- return i;
+ int ret, i;
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
- st->filter &= ~AD7791_FILTER_RATE_MASK;
- st->filter |= i;
- ad_sd_write_reg(&st->sd, AD7791_REG_FILTER, sizeof(st->filter),
- st->filter);
- iio_device_release_direct_mode(indio_dev);
- return len;
-}
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ for (i = 0; i < ARRAY_SIZE(ad7791_sample_freq_avail); i++) {
+ if (ad7791_sample_freq_avail[i][0] == val &&
+ ad7791_sample_freq_avail[i][1] == val2)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(ad7791_sample_freq_avail)) {
+ ret = -EINVAL;
+ break;
+ }
+
+ st->filter &= ~AD7791_FILTER_RATE_MASK;
+ st->filter |= i;
+ ad_sd_write_reg(&st->sd, AD7791_REG_FILTER,
+ sizeof(st->filter),
+ st->filter);
+ break;
+ default:
+ ret = -EINVAL;
+ }
-static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
- ad7791_read_frequency,
- ad7791_write_frequency);
+ iio_device_release_direct_mode(indio_dev);
+ return ret;
+}
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("120 100 33.3 20 16.7 16.6 13.3 9.5");
static struct attribute *ad7791_attributes[] = {
- &iio_dev_attr_sampling_frequency.dev_attr.attr,
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
NULL
};
@@ -306,12 +311,14 @@ static const struct attribute_group ad7791_attribute_group = {
static const struct iio_info ad7791_info = {
.read_raw = &ad7791_read_raw,
+ .write_raw = &ad7791_write_raw,
.attrs = &ad7791_attribute_group,
.validate_trigger = ad_sd_validate_trigger,
};
static const struct iio_info ad7791_no_filter_info = {
.read_raw = &ad7791_read_raw,
+ .write_raw = &ad7791_write_raw,
.validate_trigger = ad_sd_validate_trigger,
};
diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c
index ede955d9b2a4..2948909f3ee3 100644
--- a/drivers/iio/adc/meson_saradc.c
+++ b/drivers/iio/adc/meson_saradc.c
@@ -219,15 +219,19 @@ enum meson_sar_adc_chan7_mux_sel {
CHAN7_MUX_CH7_INPUT = 0x7,
};
-struct meson_sar_adc_data {
+struct meson_sar_adc_param {
bool has_bl30_integration;
unsigned long clock_rate;
u32 bandgap_reg;
unsigned int resolution;
- const char *name;
const struct regmap_config *regmap_config;
};
+struct meson_sar_adc_data {
+ const struct meson_sar_adc_param *param;
+ const char *name;
+};
+
struct meson_sar_adc_priv {
struct regmap *regmap;
struct regulator *vref;
@@ -276,7 +280,7 @@ static int meson_sar_adc_calib_val(struct iio_dev *indio_dev, int val)
/* use val_calib = scale * val_raw + offset calibration function */
tmp = div_s64((s64)val * priv->calibscale, MILLION) + priv->calibbias;
- return clamp(tmp, 0, (1 << priv->data->resolution) - 1);
+ return clamp(tmp, 0, (1 << priv->data->param->resolution) - 1);
}
static int meson_sar_adc_wait_busy_clear(struct iio_dev *indio_dev)
@@ -328,7 +332,7 @@ static int meson_sar_adc_read_raw_sample(struct iio_dev *indio_dev,
}
fifo_val = FIELD_GET(MESON_SAR_ADC_FIFO_RD_SAMPLE_VALUE_MASK, regval);
- fifo_val &= GENMASK(priv->data->resolution - 1, 0);
+ fifo_val &= GENMASK(priv->data->param->resolution - 1, 0);
*val = meson_sar_adc_calib_val(indio_dev, fifo_val);
return 0;
@@ -447,7 +451,7 @@ static int meson_sar_adc_lock(struct iio_dev *indio_dev)
mutex_lock(&indio_dev->mlock);
- if (priv->data->has_bl30_integration) {
+ if (priv->data->param->has_bl30_integration) {
/* prevent BL30 from using the SAR ADC while we are using it */
regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY,
MESON_SAR_ADC_DELAY_KERNEL_BUSY,
@@ -475,7 +479,7 @@ static void meson_sar_adc_unlock(struct iio_dev *indio_dev)
{
struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
- if (priv->data->has_bl30_integration)
+ if (priv->data->param->has_bl30_integration)
/* allow BL30 to use the SAR ADC again */
regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY,
MESON_SAR_ADC_DELAY_KERNEL_BUSY, 0);
@@ -559,7 +563,7 @@ static int meson_sar_adc_iio_info_read_raw(struct iio_dev *indio_dev,
}
*val = ret / 1000;
- *val2 = priv->data->resolution;
+ *val2 = priv->data->param->resolution;
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_CHAN_INFO_CALIBBIAS:
@@ -632,7 +636,7 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev)
*/
meson_sar_adc_set_chan7_mux(indio_dev, CHAN7_MUX_CH7_INPUT);
- if (priv->data->has_bl30_integration) {
+ if (priv->data->param->has_bl30_integration) {
/*
* leave sampling delay and the input clocks as configured by
* BL30 to make sure BL30 gets the values it expects when
@@ -712,7 +716,7 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev)
return ret;
}
- ret = clk_set_rate(priv->adc_clk, priv->data->clock_rate);
+ ret = clk_set_rate(priv->adc_clk, priv->data->param->clock_rate);
if (ret) {
dev_err(indio_dev->dev.parent,
"failed to set adc clock rate\n");
@@ -725,14 +729,15 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev)
static void meson_sar_adc_set_bandgap(struct iio_dev *indio_dev, bool on_off)
{
struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
+ const struct meson_sar_adc_param *param = priv->data->param;
u32 enable_mask;
- if (priv->data->bandgap_reg == MESON_SAR_ADC_REG11)
+ if (param->bandgap_reg == MESON_SAR_ADC_REG11)
enable_mask = MESON_SAR_ADC_REG11_BANDGAP_EN;
else
enable_mask = MESON_SAR_ADC_DELTA_10_TS_VBG_EN;
- regmap_update_bits(priv->regmap, priv->data->bandgap_reg, enable_mask,
+ regmap_update_bits(priv->regmap, param->bandgap_reg, enable_mask,
on_off ? enable_mask : 0);
}
@@ -844,8 +849,8 @@ static int meson_sar_adc_calib(struct iio_dev *indio_dev)
int ret, nominal0, nominal1, value0, value1;
/* use points 25% and 75% for calibration */
- nominal0 = (1 << priv->data->resolution) / 4;
- nominal1 = (1 << priv->data->resolution) * 3 / 4;
+ nominal0 = (1 << priv->data->param->resolution) / 4;
+ nominal1 = (1 << priv->data->param->resolution) * 3 / 4;
meson_sar_adc_set_chan7_mux(indio_dev, CHAN7_MUX_VDD_DIV4);
usleep_range(10, 20);
@@ -883,51 +888,60 @@ static const struct iio_info meson_sar_adc_iio_info = {
.read_raw = meson_sar_adc_iio_info_read_raw,
};
-static const struct meson_sar_adc_data meson_sar_adc_meson8_data = {
- .has_bl30_integration = false,
- .clock_rate = 1150000,
- .bandgap_reg = MESON_SAR_ADC_DELTA_10,
- .regmap_config = &meson_sar_adc_regmap_config_meson8,
- .resolution = 10,
- .name = "meson-meson8-saradc",
-};
-
-static const struct meson_sar_adc_data meson_sar_adc_meson8b_data = {
+static const struct meson_sar_adc_param meson_sar_adc_meson8_param = {
.has_bl30_integration = false,
.clock_rate = 1150000,
.bandgap_reg = MESON_SAR_ADC_DELTA_10,
.regmap_config = &meson_sar_adc_regmap_config_meson8,
.resolution = 10,
- .name = "meson-meson8b-saradc",
};
-static const struct meson_sar_adc_data meson_sar_adc_gxbb_data = {
+static const struct meson_sar_adc_param meson_sar_adc_gxbb_param = {
.has_bl30_integration = true,
.clock_rate = 1200000,
.bandgap_reg = MESON_SAR_ADC_REG11,
.regmap_config = &meson_sar_adc_regmap_config_gxbb,
.resolution = 10,
- .name = "meson-gxbb-saradc",
};
-static const struct meson_sar_adc_data meson_sar_adc_gxl_data = {
+static const struct meson_sar_adc_param meson_sar_adc_gxl_param = {
.has_bl30_integration = true,
.clock_rate = 1200000,
.bandgap_reg = MESON_SAR_ADC_REG11,
.regmap_config = &meson_sar_adc_regmap_config_gxbb,
.resolution = 12,
+};
+
+static const struct meson_sar_adc_data meson_sar_adc_meson8_data = {
+ .param = &meson_sar_adc_meson8_param,
+ .name = "meson-meson8-saradc",
+};
+
+static const struct meson_sar_adc_data meson_sar_adc_meson8b_data = {
+ .param = &meson_sar_adc_meson8_param,
+ .name = "meson-meson8b-saradc",
+};
+
+static const struct meson_sar_adc_data meson_sar_adc_gxbb_data = {
+ .param = &meson_sar_adc_gxbb_param,
+ .name = "meson-gxbb-saradc",
+};
+
+static const struct meson_sar_adc_data meson_sar_adc_gxl_data = {
+ .param = &meson_sar_adc_gxl_param,
.name = "meson-gxl-saradc",
};
static const struct meson_sar_adc_data meson_sar_adc_gxm_data = {
- .has_bl30_integration = true,
- .clock_rate = 1200000,
- .bandgap_reg = MESON_SAR_ADC_REG11,
- .regmap_config = &meson_sar_adc_regmap_config_gxbb,
- .resolution = 12,
+ .param = &meson_sar_adc_gxl_param,
.name = "meson-gxm-saradc",
};
+static const struct meson_sar_adc_data meson_sar_adc_axg_data = {
+ .param = &meson_sar_adc_gxl_param,
+ .name = "meson-axg-saradc",
+};
+
static const struct of_device_id meson_sar_adc_of_match[] = {
{
.compatible = "amlogic,meson8-saradc",
@@ -946,6 +960,9 @@ static const struct of_device_id meson_sar_adc_of_match[] = {
}, {
.compatible = "amlogic,meson-gxm-saradc",
.data = &meson_sar_adc_gxm_data,
+ }, {
+ .compatible = "amlogic,meson-axg-saradc",
+ .data = &meson_sar_adc_axg_data,
},
{},
};
@@ -1001,7 +1018,7 @@ static int meson_sar_adc_probe(struct platform_device *pdev)
return ret;
priv->regmap = devm_regmap_init_mmio(&pdev->dev, base,
- priv->data->regmap_config);
+ priv->data->param->regmap_config);
if (IS_ERR(priv->regmap))
return PTR_ERR(priv->regmap);
diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c
index 40be7d9fadbf..ca432e7b6ff1 100644
--- a/drivers/iio/adc/stm32-adc-core.c
+++ b/drivers/iio/adc/stm32-adc-core.c
@@ -34,9 +34,6 @@
#define STM32F4_ADC_ADCPRE_SHIFT 16
#define STM32F4_ADC_ADCPRE_MASK GENMASK(17, 16)
-/* STM32 F4 maximum analog clock rate (from datasheet) */
-#define STM32F4_ADC_MAX_CLK_RATE 36000000
-
/* STM32H7 - common registers for all ADC instances */
#define STM32H7_ADC_CSR (STM32_ADCX_COMN_OFFSET + 0x00)
#define STM32H7_ADC_CCR (STM32_ADCX_COMN_OFFSET + 0x08)
@@ -51,9 +48,6 @@
#define STM32H7_CKMODE_SHIFT 16
#define STM32H7_CKMODE_MASK GENMASK(17, 16)
-/* STM32 H7 maximum analog clock rate (from datasheet) */
-#define STM32H7_ADC_MAX_CLK_RATE 36000000
-
/**
* stm32_adc_common_regs - stm32 common registers, compatible dependent data
* @csr: common status register offset
@@ -74,15 +68,17 @@ struct stm32_adc_priv;
* stm32_adc_priv_cfg - stm32 core compatible configuration data
* @regs: common registers for all instances
* @clk_sel: clock selection routine
+ * @max_clk_rate_hz: maximum analog clock rate (Hz, from datasheet)
*/
struct stm32_adc_priv_cfg {
const struct stm32_adc_common_regs *regs;
int (*clk_sel)(struct platform_device *, struct stm32_adc_priv *);
+ u32 max_clk_rate_hz;
};
/**
* struct stm32_adc_priv - stm32 ADC core private data
- * @irq: irq for ADC block
+ * @irq: irq(s) for ADC block
* @domain: irq domain reference
* @aclk: clock reference for the analog circuitry
* @bclk: bus clock common for all ADCs, depends on part used
@@ -91,7 +87,7 @@ struct stm32_adc_priv_cfg {
* @common: common data for all ADC instances
*/
struct stm32_adc_priv {
- int irq;
+ int irq[STM32_ADC_MAX_ADCS];
struct irq_domain *domain;
struct clk *aclk;
struct clk *bclk;
@@ -133,7 +129,7 @@ static int stm32f4_adc_clk_sel(struct platform_device *pdev,
}
for (i = 0; i < ARRAY_SIZE(stm32f4_pclk_div); i++) {
- if ((rate / stm32f4_pclk_div[i]) <= STM32F4_ADC_MAX_CLK_RATE)
+ if ((rate / stm32f4_pclk_div[i]) <= priv->cfg->max_clk_rate_hz)
break;
}
if (i >= ARRAY_SIZE(stm32f4_pclk_div)) {
@@ -222,7 +218,7 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev,
if (ckmode)
continue;
- if ((rate / div) <= STM32H7_ADC_MAX_CLK_RATE)
+ if ((rate / div) <= priv->cfg->max_clk_rate_hz)
goto out;
}
}
@@ -242,7 +238,7 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev,
if (!ckmode)
continue;
- if ((rate / div) <= STM32H7_ADC_MAX_CLK_RATE)
+ if ((rate / div) <= priv->cfg->max_clk_rate_hz)
goto out;
}
@@ -328,11 +324,24 @@ static int stm32_adc_irq_probe(struct platform_device *pdev,
struct stm32_adc_priv *priv)
{
struct device_node *np = pdev->dev.of_node;
+ unsigned int i;
+
+ for (i = 0; i < STM32_ADC_MAX_ADCS; i++) {
+ priv->irq[i] = platform_get_irq(pdev, i);
+ if (priv->irq[i] < 0) {
+ /*
+ * At least one interrupt must be provided, make others
+ * optional:
+ * - stm32f4/h7 shares a common interrupt.
+ * - stm32mp1, has one line per ADC (either for ADC1,
+ * ADC2 or both).
+ */
+ if (i && priv->irq[i] == -ENXIO)
+ continue;
+ dev_err(&pdev->dev, "failed to get irq\n");
- priv->irq = platform_get_irq(pdev, 0);
- if (priv->irq < 0) {
- dev_err(&pdev->dev, "failed to get irq\n");
- return priv->irq;
+ return priv->irq[i];
+ }
}
priv->domain = irq_domain_add_simple(np, STM32_ADC_MAX_ADCS, 0,
@@ -343,8 +352,12 @@ static int stm32_adc_irq_probe(struct platform_device *pdev,
return -ENOMEM;
}
- irq_set_chained_handler(priv->irq, stm32_adc_irq_handler);
- irq_set_handler_data(priv->irq, priv);
+ for (i = 0; i < STM32_ADC_MAX_ADCS; i++) {
+ if (priv->irq[i] < 0)
+ continue;
+ irq_set_chained_handler(priv->irq[i], stm32_adc_irq_handler);
+ irq_set_handler_data(priv->irq[i], priv);
+ }
return 0;
}
@@ -353,11 +366,17 @@ static void stm32_adc_irq_remove(struct platform_device *pdev,
struct stm32_adc_priv *priv)
{
int hwirq;
+ unsigned int i;
for (hwirq = 0; hwirq < STM32_ADC_MAX_ADCS; hwirq++)
irq_dispose_mapping(irq_find_mapping(priv->domain, hwirq));
irq_domain_remove(priv->domain);
- irq_set_chained_handler(priv->irq, NULL);
+
+ for (i = 0; i < STM32_ADC_MAX_ADCS; i++) {
+ if (priv->irq[i] < 0)
+ continue;
+ irq_set_chained_handler(priv->irq[i], NULL);
+ }
}
static int stm32_adc_probe(struct platform_device *pdev)
@@ -497,11 +516,19 @@ static int stm32_adc_remove(struct platform_device *pdev)
static const struct stm32_adc_priv_cfg stm32f4_adc_priv_cfg = {
.regs = &stm32f4_adc_common_regs,
.clk_sel = stm32f4_adc_clk_sel,
+ .max_clk_rate_hz = 36000000,
};
static const struct stm32_adc_priv_cfg stm32h7_adc_priv_cfg = {
.regs = &stm32h7_adc_common_regs,
.clk_sel = stm32h7_adc_clk_sel,
+ .max_clk_rate_hz = 36000000,
+};
+
+static const struct stm32_adc_priv_cfg stm32mp1_adc_priv_cfg = {
+ .regs = &stm32h7_adc_common_regs,
+ .clk_sel = stm32h7_adc_clk_sel,
+ .max_clk_rate_hz = 40000000,
};
static const struct of_device_id stm32_adc_of_match[] = {
@@ -512,6 +539,9 @@ static const struct of_device_id stm32_adc_of_match[] = {
.compatible = "st,stm32h7-adc-core",
.data = (void *)&stm32h7_adc_priv_cfg
}, {
+ .compatible = "st,stm32mp1-adc-core",
+ .data = (void *)&stm32mp1_adc_priv_cfg
+ }, {
},
};
MODULE_DEVICE_TABLE(of, stm32_adc_of_match);
diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c
index 9a2583caedaa..378411853d75 100644
--- a/drivers/iio/adc/stm32-adc.c
+++ b/drivers/iio/adc/stm32-adc.c
@@ -84,6 +84,7 @@
#define STM32H7_ADC_CALFACT2 0xC8
/* STM32H7_ADC_ISR - bit fields */
+#define STM32MP1_VREGREADY BIT(12)
#define STM32H7_EOC BIT(2)
#define STM32H7_ADRDY BIT(0)
@@ -249,6 +250,7 @@ struct stm32_adc;
* @adc_info: per instance input channels definitions
* @trigs: external trigger sources
* @clk_required: clock is required
+ * @has_vregready: vregready status flag presence
* @selfcalib: optional routine for self-calibration
* @prepare: optional prepare routine (power-up, enable)
* @start_conv: routine to start conversions
@@ -261,6 +263,7 @@ struct stm32_adc_cfg {
const struct stm32_adc_info *adc_info;
struct stm32_adc_trig_info *trigs;
bool clk_required;
+ bool has_vregready;
int (*selfcalib)(struct stm32_adc *);
int (*prepare)(struct stm32_adc *);
void (*start_conv)(struct stm32_adc *, bool dma);
@@ -695,8 +698,12 @@ static void stm32h7_adc_stop_conv(struct stm32_adc *adc)
stm32_adc_clr_bits(adc, STM32H7_ADC_CFGR, STM32H7_DMNGT_MASK);
}
-static void stm32h7_adc_exit_pwr_down(struct stm32_adc *adc)
+static int stm32h7_adc_exit_pwr_down(struct stm32_adc *adc)
{
+ struct iio_dev *indio_dev = iio_priv_to_dev(adc);
+ int ret;
+ u32 val;
+
/* Exit deep power down, then enable ADC voltage regulator */
stm32_adc_clr_bits(adc, STM32H7_ADC_CR, STM32H7_DEEPPWD);
stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADVREGEN);
@@ -705,7 +712,20 @@ static void stm32h7_adc_exit_pwr_down(struct stm32_adc *adc)
stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_BOOST);
/* Wait for startup time */
- usleep_range(10, 20);
+ if (!adc->cfg->has_vregready) {
+ usleep_range(10, 20);
+ return 0;
+ }
+
+ ret = stm32_adc_readl_poll_timeout(STM32H7_ADC_ISR, val,
+ val & STM32MP1_VREGREADY, 100,
+ STM32_ADC_TIMEOUT_US);
+ if (ret) {
+ stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_DEEPPWD);
+ dev_err(&indio_dev->dev, "Failed to exit power down\n");
+ }
+
+ return ret;
}
static void stm32h7_adc_enter_pwr_down(struct stm32_adc *adc)
@@ -888,7 +908,9 @@ static int stm32h7_adc_selfcalib(struct stm32_adc *adc)
int ret;
u32 val;
- stm32h7_adc_exit_pwr_down(adc);
+ ret = stm32h7_adc_exit_pwr_down(adc);
+ if (ret)
+ return ret;
/*
* Select calibration mode:
@@ -952,7 +974,10 @@ static int stm32h7_adc_prepare(struct stm32_adc *adc)
{
int ret;
- stm32h7_adc_exit_pwr_down(adc);
+ ret = stm32h7_adc_exit_pwr_down(adc);
+ if (ret)
+ return ret;
+
stm32_adc_writel(adc, STM32H7_ADC_DIFSEL, adc->difsel);
ret = stm32h7_adc_enable(adc);
@@ -1944,9 +1969,23 @@ static const struct stm32_adc_cfg stm32h7_adc_cfg = {
.smp_cycles = stm32h7_adc_smp_cycles,
};
+static const struct stm32_adc_cfg stm32mp1_adc_cfg = {
+ .regs = &stm32h7_adc_regspec,
+ .adc_info = &stm32h7_adc_info,
+ .trigs = stm32h7_adc_trigs,
+ .has_vregready = true,
+ .selfcalib = stm32h7_adc_selfcalib,
+ .start_conv = stm32h7_adc_start_conv,
+ .stop_conv = stm32h7_adc_stop_conv,
+ .prepare = stm32h7_adc_prepare,
+ .unprepare = stm32h7_adc_unprepare,
+ .smp_cycles = stm32h7_adc_smp_cycles,
+};
+
static const struct of_device_id stm32_adc_of_match[] = {
{ .compatible = "st,stm32f4-adc", .data = (void *)&stm32f4_adc_cfg },
{ .compatible = "st,stm32h7-adc", .data = (void *)&stm32h7_adc_cfg },
+ { .compatible = "st,stm32mp1-adc", .data = (void *)&stm32mp1_adc_cfg },
{},
};
MODULE_DEVICE_TABLE(of, stm32_adc_of_match);
diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c
index 01422d11753c..1b78becaba5d 100644
--- a/drivers/iio/adc/stm32-dfsdm-adc.c
+++ b/drivers/iio/adc/stm32-dfsdm-adc.c
@@ -253,7 +253,8 @@ static int stm32_dfsdm_start_filter(struct stm32_dfsdm *dfsdm,
DFSDM_CR1_RSWSTART(1));
}
-static void stm32_dfsdm_stop_filter(struct stm32_dfsdm *dfsdm, unsigned int fl_id)
+static void stm32_dfsdm_stop_filter(struct stm32_dfsdm *dfsdm,
+ unsigned int fl_id)
{
/* Disable conversion */
regmap_update_bits(dfsdm->regmap, DFSDM_CR1(fl_id),
@@ -337,7 +338,7 @@ static int stm32_dfsdm_channel_parse_of(struct stm32_dfsdm *dfsdm,
"st,adc-channel-types", chan_idx,
&of_str);
if (!ret) {
- val = stm32_dfsdm_str2val(of_str, stm32_dfsdm_chan_type);
+ val = stm32_dfsdm_str2val(of_str, stm32_dfsdm_chan_type);
if (val < 0)
return val;
} else {
@@ -349,7 +350,7 @@ static int stm32_dfsdm_channel_parse_of(struct stm32_dfsdm *dfsdm,
"st,adc-channel-clk-src", chan_idx,
&of_str);
if (!ret) {
- val = stm32_dfsdm_str2val(of_str, stm32_dfsdm_chan_src);
+ val = stm32_dfsdm_str2val(of_str, stm32_dfsdm_chan_src);
if (val < 0)
return val;
} else {
@@ -1093,7 +1094,6 @@ static int stm32_dfsdm_adc_probe(struct platform_device *pdev)
char *name;
int ret, irq, val;
-
dev_data = of_device_get_match_data(dev);
iio = devm_iio_device_alloc(dev, sizeof(*adc));
if (!iio) {
@@ -1111,8 +1111,8 @@ static int stm32_dfsdm_adc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, adc);
ret = of_property_read_u32(dev->of_node, "reg", &adc->fl_id);
- if (ret != 0) {
- dev_err(dev, "Missing reg property\n");
+ if (ret != 0 || adc->fl_id >= adc->dfsdm->num_fls) {
+ dev_err(dev, "Missing or bad reg property\n");
return -EINVAL;
}
@@ -1161,7 +1161,6 @@ static int stm32_dfsdm_adc_probe(struct platform_device *pdev)
if (ret < 0)
goto err_cleanup;
- dev_err(dev, "of_platform_populate\n");
if (dev_data->type == DFSDM_AUDIO) {
ret = of_platform_populate(np, NULL, NULL, dev);
if (ret < 0) {
diff --git a/drivers/iio/adc/stm32-dfsdm-core.c b/drivers/iio/adc/stm32-dfsdm-core.c
index e50efdcc41ff..1d0d8238d9b5 100644
--- a/drivers/iio/adc/stm32-dfsdm-core.c
+++ b/drivers/iio/adc/stm32-dfsdm-core.c
@@ -227,6 +227,11 @@ static int stm32_dfsdm_parse_of(struct platform_device *pdev,
}
priv->spi_clk_out_div = div_u64_rem(clk_freq, spi_freq, &rem) - 1;
+ if (!priv->spi_clk_out_div) {
+ /* spi_clk_out_div == 0 means ckout is OFF */
+ dev_err(&pdev->dev, "spi-max-frequency not achievable\n");
+ return -EINVAL;
+ }
priv->dfsdm.spi_master_freq = spi_freq;
if (rem) {
diff --git a/drivers/iio/adc/stx104.c b/drivers/iio/adc/stx104.c
index 17b021f33180..0662ca199eb0 100644
--- a/drivers/iio/adc/stx104.c
+++ b/drivers/iio/adc/stx104.c
@@ -233,6 +233,16 @@ static int stx104_gpio_get(struct gpio_chip *chip, unsigned int offset)
return !!(inb(stx104gpio->base) & BIT(offset));
}
+static int stx104_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
+ unsigned long *bits)
+{
+ struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip);
+
+ *bits = inb(stx104gpio->base);
+
+ return 0;
+}
+
static void stx104_gpio_set(struct gpio_chip *chip, unsigned int offset,
int value)
{
@@ -342,6 +352,7 @@ static int stx104_probe(struct device *dev, unsigned int id)
stx104gpio->chip.direction_input = stx104_gpio_direction_input;
stx104gpio->chip.direction_output = stx104_gpio_direction_output;
stx104gpio->chip.get = stx104_gpio_get;
+ stx104gpio->chip.get_multiple = stx104_gpio_get_multiple;
stx104gpio->chip.set = stx104_gpio_set;
stx104gpio->chip.set_multiple = stx104_gpio_set_multiple;
stx104gpio->base = base[id] + 3;
diff --git a/drivers/iio/afe/Kconfig b/drivers/iio/afe/Kconfig
new file mode 100644
index 000000000000..c91eef04825a
--- /dev/null
+++ b/drivers/iio/afe/Kconfig
@@ -0,0 +1,19 @@
+#
+# Analog Front End drivers
+#
+# When adding new entries keep the list in alphabetical order
+
+menu "Analog Front Ends"
+
+config IIO_RESCALE
+ tristate "IIO rescale"
+ depends on OF || COMPILE_TEST
+ help
+ Say yes here to build support for the IIO rescaling
+ that handles voltage dividers, current sense shunts and
+ current sense amplifiers.
+
+ To compile this driver as a module, choose M here: the
+ module will be called iio-rescale.
+
+endmenu
diff --git a/drivers/iio/afe/Makefile b/drivers/iio/afe/Makefile
new file mode 100644
index 000000000000..5fabb7bcac47
--- /dev/null
+++ b/drivers/iio/afe/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for industrial I/O Analog Front Ends (AFE)
+#
+
+# When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_IIO_RESCALE) += iio-rescale.o
diff --git a/drivers/iio/afe/iio-rescale.c b/drivers/iio/afe/iio-rescale.c
new file mode 100644
index 000000000000..e9ceee66d1e7
--- /dev/null
+++ b/drivers/iio/afe/iio-rescale.c
@@ -0,0 +1,359 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * IIO rescale driver
+ *
+ * Copyright (C) 2018 Axentia Technologies AB
+ *
+ * Author: Peter Rosin <peda@axentia.se>
+ */
+
+#include <linux/err.h>
+#include <linux/gcd.h>
+#include <linux/iio/consumer.h>
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+
+struct rescale;
+
+struct rescale_cfg {
+ enum iio_chan_type type;
+ int (*props)(struct device *dev, struct rescale *rescale);
+};
+
+struct rescale {
+ const struct rescale_cfg *cfg;
+ struct iio_channel *source;
+ struct iio_chan_spec chan;
+ struct iio_chan_spec_ext_info *ext_info;
+ s32 numerator;
+ s32 denominator;
+};
+
+static int rescale_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct rescale *rescale = iio_priv(indio_dev);
+ unsigned long long tmp;
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ return iio_read_channel_raw(rescale->source, val);
+
+ case IIO_CHAN_INFO_SCALE:
+ ret = iio_read_channel_scale(rescale->source, val, val2);
+ switch (ret) {
+ case IIO_VAL_FRACTIONAL:
+ *val *= rescale->numerator;
+ *val2 *= rescale->denominator;
+ return ret;
+ case IIO_VAL_INT:
+ *val *= rescale->numerator;
+ if (rescale->denominator == 1)
+ return ret;
+ *val2 = rescale->denominator;
+ return IIO_VAL_FRACTIONAL;
+ case IIO_VAL_FRACTIONAL_LOG2:
+ tmp = *val * 1000000000LL;
+ do_div(tmp, rescale->denominator);
+ tmp *= rescale->numerator;
+ do_div(tmp, 1000000000LL);
+ *val = tmp;
+ return ret;
+ default:
+ return -EOPNOTSUPP;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int rescale_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long mask)
+{
+ struct rescale *rescale = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ *type = IIO_VAL_INT;
+ return iio_read_avail_channel_raw(rescale->source,
+ vals, length);
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info rescale_info = {
+ .read_raw = rescale_read_raw,
+ .read_avail = rescale_read_avail,
+};
+
+static ssize_t rescale_read_ext_info(struct iio_dev *indio_dev,
+ uintptr_t private,
+ struct iio_chan_spec const *chan,
+ char *buf)
+{
+ struct rescale *rescale = iio_priv(indio_dev);
+
+ return iio_read_channel_ext_info(rescale->source,
+ rescale->ext_info[private].name,
+ buf);
+}
+
+static ssize_t rescale_write_ext_info(struct iio_dev *indio_dev,
+ uintptr_t private,
+ struct iio_chan_spec const *chan,
+ const char *buf, size_t len)
+{
+ struct rescale *rescale = iio_priv(indio_dev);
+
+ return iio_write_channel_ext_info(rescale->source,
+ rescale->ext_info[private].name,
+ buf, len);
+}
+
+static int rescale_configure_channel(struct device *dev,
+ struct rescale *rescale)
+{
+ struct iio_chan_spec *chan = &rescale->chan;
+ struct iio_chan_spec const *schan = rescale->source->channel;
+
+ chan->indexed = 1;
+ chan->output = schan->output;
+ chan->ext_info = rescale->ext_info;
+ chan->type = rescale->cfg->type;
+
+ if (!iio_channel_has_info(schan, IIO_CHAN_INFO_RAW) ||
+ !iio_channel_has_info(schan, IIO_CHAN_INFO_SCALE)) {
+ dev_err(dev, "source channel does not support raw/scale\n");
+ return -EINVAL;
+ }
+
+ chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE);
+
+ if (iio_channel_has_available(schan, IIO_CHAN_INFO_RAW))
+ chan->info_mask_separate_available |= BIT(IIO_CHAN_INFO_RAW);
+
+ return 0;
+}
+
+static int rescale_current_sense_amplifier_props(struct device *dev,
+ struct rescale *rescale)
+{
+ u32 sense;
+ u32 gain_mult = 1;
+ u32 gain_div = 1;
+ u32 factor;
+ int ret;
+
+ ret = device_property_read_u32(dev, "sense-resistor-micro-ohms",
+ &sense);
+ if (ret) {
+ dev_err(dev, "failed to read the sense resistance: %d\n", ret);
+ return ret;
+ }
+
+ device_property_read_u32(dev, "sense-gain-mult", &gain_mult);
+ device_property_read_u32(dev, "sense-gain-div", &gain_div);
+
+ /*
+ * Calculate the scaling factor, 1 / (gain * sense), or
+ * gain_div / (gain_mult * sense), while trying to keep the
+ * numerator/denominator from overflowing.
+ */
+ factor = gcd(sense, 1000000);
+ rescale->numerator = 1000000 / factor;
+ rescale->denominator = sense / factor;
+
+ factor = gcd(rescale->numerator, gain_mult);
+ rescale->numerator /= factor;
+ rescale->denominator *= gain_mult / factor;
+
+ factor = gcd(rescale->denominator, gain_div);
+ rescale->numerator *= gain_div / factor;
+ rescale->denominator /= factor;
+
+ return 0;
+}
+
+static int rescale_current_sense_shunt_props(struct device *dev,
+ struct rescale *rescale)
+{
+ u32 shunt;
+ u32 factor;
+ int ret;
+
+ ret = device_property_read_u32(dev, "shunt-resistor-micro-ohms",
+ &shunt);
+ if (ret) {
+ dev_err(dev, "failed to read the shunt resistance: %d\n", ret);
+ return ret;
+ }
+
+ factor = gcd(shunt, 1000000);
+ rescale->numerator = 1000000 / factor;
+ rescale->denominator = shunt / factor;
+
+ return 0;
+}
+
+static int rescale_voltage_divider_props(struct device *dev,
+ struct rescale *rescale)
+{
+ int ret;
+ u32 factor;
+
+ ret = device_property_read_u32(dev, "output-ohms",
+ &rescale->denominator);
+ if (ret) {
+ dev_err(dev, "failed to read output-ohms: %d\n", ret);
+ return ret;
+ }
+
+ ret = device_property_read_u32(dev, "full-ohms",
+ &rescale->numerator);
+ if (ret) {
+ dev_err(dev, "failed to read full-ohms: %d\n", ret);
+ return ret;
+ }
+
+ factor = gcd(rescale->numerator, rescale->denominator);
+ rescale->numerator /= factor;
+ rescale->denominator /= factor;
+
+ return 0;
+}
+
+enum rescale_variant {
+ CURRENT_SENSE_AMPLIFIER,
+ CURRENT_SENSE_SHUNT,
+ VOLTAGE_DIVIDER,
+};
+
+static const struct rescale_cfg rescale_cfg[] = {
+ [CURRENT_SENSE_AMPLIFIER] = {
+ .type = IIO_CURRENT,
+ .props = rescale_current_sense_amplifier_props,
+ },
+ [CURRENT_SENSE_SHUNT] = {
+ .type = IIO_CURRENT,
+ .props = rescale_current_sense_shunt_props,
+ },
+ [VOLTAGE_DIVIDER] = {
+ .type = IIO_VOLTAGE,
+ .props = rescale_voltage_divider_props,
+ },
+};
+
+static const struct of_device_id rescale_match[] = {
+ { .compatible = "current-sense-amplifier",
+ .data = &rescale_cfg[CURRENT_SENSE_AMPLIFIER], },
+ { .compatible = "current-sense-shunt",
+ .data = &rescale_cfg[CURRENT_SENSE_SHUNT], },
+ { .compatible = "voltage-divider",
+ .data = &rescale_cfg[VOLTAGE_DIVIDER], },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, rescale_match);
+
+static int rescale_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct iio_dev *indio_dev;
+ struct iio_channel *source;
+ struct rescale *rescale;
+ int sizeof_ext_info;
+ int sizeof_priv;
+ int i;
+ int ret;
+
+ source = devm_iio_channel_get(dev, NULL);
+ if (IS_ERR(source)) {
+ if (PTR_ERR(source) != -EPROBE_DEFER)
+ dev_err(dev, "failed to get source channel\n");
+ return PTR_ERR(source);
+ }
+
+ sizeof_ext_info = iio_get_channel_ext_info_count(source);
+ if (sizeof_ext_info) {
+ sizeof_ext_info += 1; /* one extra entry for the sentinel */
+ sizeof_ext_info *= sizeof(*rescale->ext_info);
+ }
+
+ sizeof_priv = sizeof(*rescale) + sizeof_ext_info;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof_priv);
+ if (!indio_dev)
+ return -ENOMEM;
+
+ rescale = iio_priv(indio_dev);
+
+ rescale->cfg = of_device_get_match_data(dev);
+ rescale->numerator = 1;
+ rescale->denominator = 1;
+
+ ret = rescale->cfg->props(dev, rescale);
+ if (ret)
+ return ret;
+
+ if (!rescale->numerator || !rescale->denominator) {
+ dev_err(dev, "invalid scaling factor.\n");
+ return -EINVAL;
+ }
+
+ platform_set_drvdata(pdev, indio_dev);
+
+ rescale->source = source;
+
+ indio_dev->name = dev_name(dev);
+ indio_dev->dev.parent = dev;
+ indio_dev->info = &rescale_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = &rescale->chan;
+ indio_dev->num_channels = 1;
+ if (sizeof_ext_info) {
+ rescale->ext_info = devm_kmemdup(dev,
+ source->channel->ext_info,
+ sizeof_ext_info, GFP_KERNEL);
+ if (!rescale->ext_info)
+ return -ENOMEM;
+
+ for (i = 0; rescale->ext_info[i].name; ++i) {
+ struct iio_chan_spec_ext_info *ext_info =
+ &rescale->ext_info[i];
+
+ if (source->channel->ext_info[i].read)
+ ext_info->read = rescale_read_ext_info;
+ if (source->channel->ext_info[i].write)
+ ext_info->write = rescale_write_ext_info;
+ ext_info->private = i;
+ }
+ }
+
+ ret = rescale_configure_channel(dev, rescale);
+ if (ret)
+ return ret;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static struct platform_driver rescale_driver = {
+ .probe = rescale_probe,
+ .driver = {
+ .name = "iio-rescale",
+ .of_match_table = rescale_match,
+ },
+};
+module_platform_driver(rescale_driver);
+
+MODULE_DESCRIPTION("IIO rescale driver");
+MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/chemical/atlas-ph-sensor.c b/drivers/iio/chemical/atlas-ph-sensor.c
index abfc4bbc4cfc..a406ad31b096 100644
--- a/drivers/iio/chemical/atlas-ph-sensor.c
+++ b/drivers/iio/chemical/atlas-ph-sensor.c
@@ -61,9 +61,9 @@
#define ATLAS_REG_ORP_CALIB_STATUS 0x0d
#define ATLAS_REG_ORP_DATA 0x0e
-#define ATLAS_PH_INT_TIME_IN_US 450000
-#define ATLAS_EC_INT_TIME_IN_US 650000
-#define ATLAS_ORP_INT_TIME_IN_US 450000
+#define ATLAS_PH_INT_TIME_IN_MS 450
+#define ATLAS_EC_INT_TIME_IN_MS 650
+#define ATLAS_ORP_INT_TIME_IN_MS 450
enum {
ATLAS_PH_SM,
@@ -270,21 +270,21 @@ static struct atlas_device atlas_devices[] = {
.num_channels = 3,
.data_reg = ATLAS_REG_PH_DATA,
.calibration = &atlas_check_ph_calibration,
- .delay = ATLAS_PH_INT_TIME_IN_US,
+ .delay = ATLAS_PH_INT_TIME_IN_MS,
},
[ATLAS_EC_SM] = {
.channels = atlas_ec_channels,
.num_channels = 5,
.data_reg = ATLAS_REG_EC_DATA,
.calibration = &atlas_check_ec_calibration,
- .delay = ATLAS_EC_INT_TIME_IN_US,
+ .delay = ATLAS_EC_INT_TIME_IN_MS,
},
[ATLAS_ORP_SM] = {
.channels = atlas_orp_channels,
.num_channels = 2,
.data_reg = ATLAS_REG_ORP_DATA,
.calibration = &atlas_check_orp_calibration,
- .delay = ATLAS_ORP_INT_TIME_IN_US,
+ .delay = ATLAS_ORP_INT_TIME_IN_MS,
},
};
@@ -393,7 +393,7 @@ static int atlas_read_measurement(struct atlas_data *data, int reg, __be32 *val)
}
if (suspended)
- usleep_range(data->chip->delay, data->chip->delay + 100000);
+ msleep(data->chip->delay);
ret = regmap_bulk_read(data->regmap, reg, (u8 *) val, sizeof(*val));
diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c
index 705cb3e72663..89cb0066a6e0 100644
--- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c
+++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c
@@ -19,6 +19,7 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/iio/buffer.h>
+#include <linux/iio/common/cros_ec_sensors_core.h>
#include <linux/iio/iio.h>
#include <linux/iio/kfifo_buf.h>
#include <linux/iio/trigger_consumer.h>
@@ -31,8 +32,6 @@
#include <linux/slab.h>
#include <linux/sysfs.h>
-#include "cros_ec_sensors_core.h"
-
#define CROS_EC_SENSORS_MAX_CHANNELS 4
/* State data for ec_sensors iio driver. */
diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c
index a620eb5ce202..414cc43c287e 100644
--- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c
+++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c
@@ -16,6 +16,7 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/iio/buffer.h>
+#include <linux/iio/common/cros_ec_sensors_core.h>
#include <linux/iio/iio.h>
#include <linux/iio/kfifo_buf.h>
#include <linux/iio/trigger_consumer.h>
@@ -27,8 +28,6 @@
#include <linux/sysfs.h>
#include <linux/platform_device.h>
-#include "cros_ec_sensors_core.h"
-
static char *cros_ec_loc[] = {
[MOTIONSENSE_LOC_BASE] = "base",
[MOTIONSENSE_LOC_LID] = "lid",
@@ -448,8 +447,7 @@ EXPORT_SYMBOL_GPL(cros_ec_sensors_core_write);
static int __maybe_unused cros_ec_sensors_prepare(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct cros_ec_sensors_core_state *st = iio_priv(indio_dev);
if (st->curr_sampl_freq == 0)
@@ -471,8 +469,7 @@ static int __maybe_unused cros_ec_sensors_prepare(struct device *dev)
static void __maybe_unused cros_ec_sensors_complete(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct cros_ec_sensors_core_state *st = iio_priv(indio_dev);
if (st->curr_sampl_freq == 0)
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
index cfb6588565ba..2ce0efd98cc0 100644
--- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
+++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
@@ -304,8 +304,7 @@ EXPORT_SYMBOL(hid_sensor_setup_trigger);
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);
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct hid_sensor_common *attrb = iio_device_get_drvdata(indio_dev);
return _hid_sensor_power_state(attrb, false);
@@ -313,8 +312,7 @@ static int __maybe_unused hid_sensor_suspend(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);
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct hid_sensor_common *attrb = iio_device_get_drvdata(indio_dev);
schedule_work(&attrb->work);
return 0;
@@ -322,8 +320,7 @@ static int __maybe_unused hid_sensor_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);
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct hid_sensor_common *attrb = iio_device_get_drvdata(indio_dev);
return _hid_sensor_power_state(attrb, true);
}
diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
index 76db0768e454..06e90debb9f5 100644
--- a/drivers/iio/dac/Kconfig
+++ b/drivers/iio/dac/Kconfig
@@ -131,16 +131,31 @@ config LTC2632
module will be called ltc2632.
config AD5686
- tristate "Analog Devices AD5686R/AD5685R/AD5684R DAC SPI driver"
+ tristate
+
+config AD5686_SPI
+ tristate "Analog Devices AD5686 and similar multi-channel DACs (SPI)"
depends on SPI
+ select AD5686
help
- Say yes here to build support for Analog Devices AD5686R, AD5685R,
- AD5684R, AD5791 Voltage Output Digital to
- Analog Converter.
+ Say yes here to build support for Analog Devices AD5672R, AD5676,
+ AD5676R, AD5684, AD5684R, AD5684R, AD5685R, AD5686, AD5686R.
+ Voltage Output Digital to Analog Converter.
To compile this driver as a module, choose M here: the
module will be called ad5686.
+config AD5696_I2C
+ tristate "Analog Devices AD5696 and similar multi-channel DACs (I2C)"
+ depends on I2C
+ select AD5686
+ help
+ Say yes here to build support for Analog Devices AD5671R, AD5675R,
+ AD5694, AD5694R, AD5695R, AD5696, AD5696R Voltage Output Digital to
+ Analog Converter.
+ To compile this driver as a module, choose M here: the module will be
+ called ad5696.
+
config AD5755
tristate "Analog Devices AD5755/AD5755-1/AD5757/AD5735/AD5737 DAC driver"
depends on SPI_MASTER
@@ -321,6 +336,16 @@ config TI_DAC082S085
If compiled as a module, it will be called ti-dac082s085.
+config TI_DAC5571
+ tristate "Texas Instruments 8/10/12/16-bit 1/2/4-channel DAC driver"
+ depends on I2C
+ help
+ Driver for the Texas Instruments
+ DAC5571, DAC6571, DAC7571, DAC5574, DAC6574, DAC7574, DAC5573,
+ DAC6573, DAC7573, DAC8571, DAC8574.
+
+ If compiled as a module, it will be called ti-dac5571.
+
config VF610_DAC
tristate "Vybrid vf610 DAC driver"
depends on OF
diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile
index 81e710ed7491..57aa230d34ab 100644
--- a/drivers/iio/dac/Makefile
+++ b/drivers/iio/dac/Makefile
@@ -20,6 +20,8 @@ obj-$(CONFIG_AD5761) += ad5761.o
obj-$(CONFIG_AD5764) += ad5764.o
obj-$(CONFIG_AD5791) += ad5791.o
obj-$(CONFIG_AD5686) += ad5686.o
+obj-$(CONFIG_AD5686_SPI) += ad5686-spi.o
+obj-$(CONFIG_AD5696_I2C) += ad5696-i2c.o
obj-$(CONFIG_AD7303) += ad7303.o
obj-$(CONFIG_AD8801) += ad8801.o
obj-$(CONFIG_CIO_DAC) += cio-dac.o
@@ -35,4 +37,5 @@ obj-$(CONFIG_MCP4922) += mcp4922.o
obj-$(CONFIG_STM32_DAC_CORE) += stm32-dac-core.o
obj-$(CONFIG_STM32_DAC) += stm32-dac.o
obj-$(CONFIG_TI_DAC082S085) += ti-dac082s085.o
+obj-$(CONFIG_TI_DAC5571) += ti-dac5571.o
obj-$(CONFIG_VF610_DAC) += vf610_dac.o
diff --git a/drivers/iio/dac/ad5686-spi.c b/drivers/iio/dac/ad5686-spi.c
new file mode 100644
index 000000000000..6bb09e9259e6
--- /dev/null
+++ b/drivers/iio/dac/ad5686-spi.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * AD5672R, AD5676, AD5676R, AD5684, AD5684R, AD5684R, AD5685R, AD5686, AD5686R
+ * Digital to analog converters driver
+ *
+ * Copyright 2018 Analog Devices Inc.
+ */
+
+#include "ad5686.h"
+
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+
+static int ad5686_spi_write(struct ad5686_state *st,
+ u8 cmd, u8 addr, u16 val)
+{
+ struct spi_device *spi = to_spi_device(st->dev);
+
+ st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) |
+ AD5686_ADDR(addr) |
+ val);
+
+ return spi_write(spi, &st->data[0].d8[1], 3);
+}
+
+static int ad5686_spi_read(struct ad5686_state *st, u8 addr)
+{
+ struct spi_transfer t[] = {
+ {
+ .tx_buf = &st->data[0].d8[1],
+ .len = 3,
+ .cs_change = 1,
+ }, {
+ .tx_buf = &st->data[1].d8[1],
+ .rx_buf = &st->data[2].d8[1],
+ .len = 3,
+ },
+ };
+ struct spi_device *spi = to_spi_device(st->dev);
+ int ret;
+
+ st->data[0].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_READBACK_ENABLE) |
+ AD5686_ADDR(addr));
+ st->data[1].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_NOOP));
+
+ ret = spi_sync_transfer(spi, t, ARRAY_SIZE(t));
+ if (ret < 0)
+ return ret;
+
+ return be32_to_cpu(st->data[2].d32);
+}
+
+static int ad5686_spi_probe(struct spi_device *spi)
+{
+ const struct spi_device_id *id = spi_get_device_id(spi);
+
+ return ad5686_probe(&spi->dev, id->driver_data, id->name,
+ ad5686_spi_write, ad5686_spi_read);
+}
+
+static int ad5686_spi_remove(struct spi_device *spi)
+{
+ return ad5686_remove(&spi->dev);
+}
+
+static const struct spi_device_id ad5686_spi_id[] = {
+ {"ad5672r", ID_AD5672R},
+ {"ad5676", ID_AD5676},
+ {"ad5676r", ID_AD5676R},
+ {"ad5684", ID_AD5684},
+ {"ad5684r", ID_AD5684R},
+ {"ad5685", ID_AD5685R}, /* Does not exist */
+ {"ad5685r", ID_AD5685R},
+ {"ad5686", ID_AD5686},
+ {"ad5686r", ID_AD5686R},
+ {}
+};
+MODULE_DEVICE_TABLE(spi, ad5686_spi_id);
+
+static struct spi_driver ad5686_spi_driver = {
+ .driver = {
+ .name = "ad5686",
+ },
+ .probe = ad5686_spi_probe,
+ .remove = ad5686_spi_remove,
+ .id_table = ad5686_spi_id,
+};
+
+module_spi_driver(ad5686_spi_driver);
+
+MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>");
+MODULE_DESCRIPTION("Analog Devices AD5686 and similar multi-channel DACs");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c
index 20254df7f9c7..89c5f089ae7f 100644
--- a/drivers/iio/dac/ad5686.c
+++ b/drivers/iio/dac/ad5686.c
@@ -1,9 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* AD5686R, AD5685R, AD5684R Digital to analog converters driver
*
* Copyright 2011 Analog Devices Inc.
- *
- * Licensed under the GPL-2.
*/
#include <linux/interrupt.h>
@@ -11,7 +10,6 @@
#include <linux/device.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>
@@ -19,116 +17,7 @@
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
-#define AD5686_DAC_CHANNELS 4
-
-#define AD5686_ADDR(x) ((x) << 16)
-#define AD5686_CMD(x) ((x) << 20)
-
-#define AD5686_ADDR_DAC(chan) (0x1 << (chan))
-#define AD5686_ADDR_ALL_DAC 0xF
-
-#define AD5686_CMD_NOOP 0x0
-#define AD5686_CMD_WRITE_INPUT_N 0x1
-#define AD5686_CMD_UPDATE_DAC_N 0x2
-#define AD5686_CMD_WRITE_INPUT_N_UPDATE_N 0x3
-#define AD5686_CMD_POWERDOWN_DAC 0x4
-#define AD5686_CMD_LDAC_MASK 0x5
-#define AD5686_CMD_RESET 0x6
-#define AD5686_CMD_INTERNAL_REFER_SETUP 0x7
-#define AD5686_CMD_DAISY_CHAIN_ENABLE 0x8
-#define AD5686_CMD_READBACK_ENABLE 0x9
-
-#define AD5686_LDAC_PWRDN_NONE 0x0
-#define AD5686_LDAC_PWRDN_1K 0x1
-#define AD5686_LDAC_PWRDN_100K 0x2
-#define AD5686_LDAC_PWRDN_3STATE 0x3
-
-/**
- * struct ad5686_chip_info - chip specific information
- * @int_vref_mv: AD5620/40/60: the internal reference voltage
- * @channel: channel specification
-*/
-
-struct ad5686_chip_info {
- u16 int_vref_mv;
- struct iio_chan_spec channel[AD5686_DAC_CHANNELS];
-};
-
-/**
- * struct ad5446_state - driver instance specific data
- * @spi: spi_device
- * @chip_info: chip model specific constants, available modes etc
- * @reg: supply regulator
- * @vref_mv: actual reference voltage used
- * @pwr_down_mask: power down mask
- * @pwr_down_mode: current power down mode
- * @data: spi transfer buffers
- */
-
-struct ad5686_state {
- struct spi_device *spi;
- const struct ad5686_chip_info *chip_info;
- struct regulator *reg;
- unsigned short vref_mv;
- unsigned pwr_down_mask;
- unsigned pwr_down_mode;
- /*
- * DMA (thus cache coherency maintenance) requires the
- * transfer buffers to live in their own cache lines.
- */
-
- union {
- __be32 d32;
- u8 d8[4];
- } data[3] ____cacheline_aligned;
-};
-
-/**
- * ad5686_supported_device_ids:
- */
-
-enum ad5686_supported_device_ids {
- ID_AD5684,
- ID_AD5685,
- ID_AD5686,
-};
-static int ad5686_spi_write(struct ad5686_state *st,
- u8 cmd, u8 addr, u16 val, u8 shift)
-{
- val <<= shift;
-
- st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) |
- AD5686_ADDR(addr) |
- val);
-
- return spi_write(st->spi, &st->data[0].d8[1], 3);
-}
-
-static int ad5686_spi_read(struct ad5686_state *st, u8 addr)
-{
- struct spi_transfer t[] = {
- {
- .tx_buf = &st->data[0].d8[1],
- .len = 3,
- .cs_change = 1,
- }, {
- .tx_buf = &st->data[1].d8[1],
- .rx_buf = &st->data[2].d8[1],
- .len = 3,
- },
- };
- int ret;
-
- st->data[0].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_READBACK_ENABLE) |
- AD5686_ADDR(addr));
- st->data[1].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_NOOP));
-
- ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t));
- if (ret < 0)
- return ret;
-
- return be32_to_cpu(st->data[2].d32);
-}
+#include "ad5686.h"
static const char * const ad5686_powerdown_modes[] = {
"1kohm_to_gnd",
@@ -137,7 +26,7 @@ static const char * const ad5686_powerdown_modes[] = {
};
static int ad5686_get_powerdown_mode(struct iio_dev *indio_dev,
- const struct iio_chan_spec *chan)
+ const struct iio_chan_spec *chan)
{
struct ad5686_state *st = iio_priv(indio_dev);
@@ -145,7 +34,8 @@ static int ad5686_get_powerdown_mode(struct iio_dev *indio_dev,
}
static int ad5686_set_powerdown_mode(struct iio_dev *indio_dev,
- const struct iio_chan_spec *chan, unsigned int mode)
+ const struct iio_chan_spec *chan,
+ unsigned int mode)
{
struct ad5686_state *st = iio_priv(indio_dev);
@@ -163,17 +53,19 @@ static const struct iio_enum ad5686_powerdown_mode_enum = {
};
static ssize_t ad5686_read_dac_powerdown(struct iio_dev *indio_dev,
- uintptr_t private, const struct iio_chan_spec *chan, char *buf)
+ uintptr_t private, const struct iio_chan_spec *chan, char *buf)
{
struct ad5686_state *st = iio_priv(indio_dev);
return sprintf(buf, "%d\n", !!(st->pwr_down_mask &
- (0x3 << (chan->channel * 2))));
+ (0x3 << (chan->channel * 2))));
}
static ssize_t ad5686_write_dac_powerdown(struct iio_dev *indio_dev,
- uintptr_t private, const struct iio_chan_spec *chan, const char *buf,
- size_t len)
+ uintptr_t private,
+ const struct iio_chan_spec *chan,
+ const char *buf,
+ size_t len)
{
bool readin;
int ret;
@@ -188,8 +80,9 @@ static ssize_t ad5686_write_dac_powerdown(struct iio_dev *indio_dev,
else
st->pwr_down_mask &= ~(0x3 << (chan->channel * 2));
- ret = ad5686_spi_write(st, AD5686_CMD_POWERDOWN_DAC, 0,
- st->pwr_down_mask & st->pwr_down_mode, 0);
+ ret = st->write(st, AD5686_CMD_POWERDOWN_DAC, 0,
+ st->pwr_down_mask & st->pwr_down_mode);
+
return ret ? ret : len;
}
@@ -206,7 +99,7 @@ static int ad5686_read_raw(struct iio_dev *indio_dev,
switch (m) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
- ret = ad5686_spi_read(st, chan->address);
+ ret = st->read(st, chan->address);
mutex_unlock(&indio_dev->mlock);
if (ret < 0)
return ret;
@@ -221,10 +114,10 @@ static int ad5686_read_raw(struct iio_dev *indio_dev,
}
static int ad5686_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int val,
- int val2,
- long mask)
+ struct iio_chan_spec const *chan,
+ int val,
+ int val2,
+ long mask)
{
struct ad5686_state *st = iio_priv(indio_dev);
int ret;
@@ -235,11 +128,10 @@ static int ad5686_write_raw(struct iio_dev *indio_dev,
return -EINVAL;
mutex_lock(&indio_dev->mlock);
- ret = ad5686_spi_write(st,
- AD5686_CMD_WRITE_INPUT_N_UPDATE_N,
- chan->address,
- val,
- chan->scan_type.shift);
+ ret = st->write(st,
+ AD5686_CMD_WRITE_INPUT_N_UPDATE_N,
+ chan->address,
+ val << chan->scan_type.shift);
mutex_unlock(&indio_dev->mlock);
break;
default:
@@ -266,14 +158,14 @@ static const struct iio_chan_spec_ext_info ad5686_ext_info[] = {
{ },
};
-#define AD5868_CHANNEL(chan, bits, _shift) { \
+#define AD5868_CHANNEL(chan, addr, bits, _shift) { \
.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),\
- .address = AD5686_ADDR_DAC(chan), \
+ .address = addr, \
.scan_type = { \
.sign = 'u', \
.realbits = (bits), \
@@ -283,45 +175,121 @@ static const struct iio_chan_spec_ext_info ad5686_ext_info[] = {
.ext_info = ad5686_ext_info, \
}
+#define DECLARE_AD5686_CHANNELS(name, bits, _shift) \
+static struct iio_chan_spec name[] = { \
+ AD5868_CHANNEL(0, 1, bits, _shift), \
+ AD5868_CHANNEL(1, 2, bits, _shift), \
+ AD5868_CHANNEL(2, 4, bits, _shift), \
+ AD5868_CHANNEL(3, 8, bits, _shift), \
+}
+
+#define DECLARE_AD5676_CHANNELS(name, bits, _shift) \
+static struct iio_chan_spec name[] = { \
+ AD5868_CHANNEL(0, 0, bits, _shift), \
+ AD5868_CHANNEL(1, 1, bits, _shift), \
+ AD5868_CHANNEL(2, 2, bits, _shift), \
+ AD5868_CHANNEL(3, 3, bits, _shift), \
+ AD5868_CHANNEL(4, 4, bits, _shift), \
+ AD5868_CHANNEL(5, 5, bits, _shift), \
+ AD5868_CHANNEL(6, 6, bits, _shift), \
+ AD5868_CHANNEL(7, 7, bits, _shift), \
+}
+
+DECLARE_AD5676_CHANNELS(ad5672_channels, 12, 4);
+DECLARE_AD5676_CHANNELS(ad5676_channels, 16, 0);
+DECLARE_AD5686_CHANNELS(ad5684_channels, 12, 4);
+DECLARE_AD5686_CHANNELS(ad5685r_channels, 14, 2);
+DECLARE_AD5686_CHANNELS(ad5686_channels, 16, 0);
+
static const struct ad5686_chip_info ad5686_chip_info_tbl[] = {
+ [ID_AD5671R] = {
+ .channels = ad5672_channels,
+ .int_vref_mv = 2500,
+ .num_channels = 8,
+ },
+ [ID_AD5672R] = {
+ .channels = ad5672_channels,
+ .int_vref_mv = 2500,
+ .num_channels = 8,
+ },
+ [ID_AD5675R] = {
+ .channels = ad5676_channels,
+ .int_vref_mv = 2500,
+ .num_channels = 8,
+ },
+ [ID_AD5676] = {
+ .channels = ad5676_channels,
+ .num_channels = 8,
+ },
+ [ID_AD5676R] = {
+ .channels = ad5676_channels,
+ .int_vref_mv = 2500,
+ .num_channels = 8,
+ },
[ID_AD5684] = {
- .channel[0] = AD5868_CHANNEL(0, 12, 4),
- .channel[1] = AD5868_CHANNEL(1, 12, 4),
- .channel[2] = AD5868_CHANNEL(2, 12, 4),
- .channel[3] = AD5868_CHANNEL(3, 12, 4),
+ .channels = ad5684_channels,
+ .num_channels = 4,
+ },
+ [ID_AD5684R] = {
+ .channels = ad5684_channels,
.int_vref_mv = 2500,
+ .num_channels = 4,
},
- [ID_AD5685] = {
- .channel[0] = AD5868_CHANNEL(0, 14, 2),
- .channel[1] = AD5868_CHANNEL(1, 14, 2),
- .channel[2] = AD5868_CHANNEL(2, 14, 2),
- .channel[3] = AD5868_CHANNEL(3, 14, 2),
+ [ID_AD5685R] = {
+ .channels = ad5685r_channels,
.int_vref_mv = 2500,
+ .num_channels = 4,
},
[ID_AD5686] = {
- .channel[0] = AD5868_CHANNEL(0, 16, 0),
- .channel[1] = AD5868_CHANNEL(1, 16, 0),
- .channel[2] = AD5868_CHANNEL(2, 16, 0),
- .channel[3] = AD5868_CHANNEL(3, 16, 0),
+ .channels = ad5686_channels,
+ .num_channels = 4,
+ },
+ [ID_AD5686R] = {
+ .channels = ad5686_channels,
.int_vref_mv = 2500,
+ .num_channels = 4,
+ },
+ [ID_AD5694] = {
+ .channels = ad5684_channels,
+ .num_channels = 4,
+ },
+ [ID_AD5694R] = {
+ .channels = ad5684_channels,
+ .int_vref_mv = 2500,
+ .num_channels = 4,
+ },
+ [ID_AD5696] = {
+ .channels = ad5686_channels,
+ .num_channels = 4,
+ },
+ [ID_AD5696R] = {
+ .channels = ad5686_channels,
+ .int_vref_mv = 2500,
+ .num_channels = 4,
},
};
-
-static int ad5686_probe(struct spi_device *spi)
+int ad5686_probe(struct device *dev,
+ enum ad5686_supported_device_ids chip_type,
+ const char *name, ad5686_write_func write,
+ ad5686_read_func read)
{
struct ad5686_state *st;
struct iio_dev *indio_dev;
int ret, voltage_uv = 0;
- indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
st = iio_priv(indio_dev);
- spi_set_drvdata(spi, indio_dev);
+ dev_set_drvdata(dev, indio_dev);
+
+ st->dev = dev;
+ st->write = write;
+ st->read = read;
- st->reg = devm_regulator_get_optional(&spi->dev, "vcc");
+ st->reg = devm_regulator_get_optional(dev, "vcc");
if (!IS_ERR(st->reg)) {
ret = regulator_enable(st->reg);
if (ret)
@@ -334,28 +302,25 @@ static int ad5686_probe(struct spi_device *spi)
voltage_uv = ret;
}
- st->chip_info =
- &ad5686_chip_info_tbl[spi_get_device_id(spi)->driver_data];
+ st->chip_info = &ad5686_chip_info_tbl[chip_type];
if (voltage_uv)
st->vref_mv = voltage_uv / 1000;
else
st->vref_mv = st->chip_info->int_vref_mv;
- st->spi = spi;
-
/* Set all the power down mode for all channels to 1K pulldown */
st->pwr_down_mode = 0x55;
- indio_dev->dev.parent = &spi->dev;
- indio_dev->name = spi_get_device_id(spi)->name;
+ indio_dev->dev.parent = dev;
+ indio_dev->name = name;
indio_dev->info = &ad5686_info;
indio_dev->modes = INDIO_DIRECT_MODE;
- indio_dev->channels = st->chip_info->channel;
- indio_dev->num_channels = AD5686_DAC_CHANNELS;
+ indio_dev->channels = st->chip_info->channels;
+ indio_dev->num_channels = st->chip_info->num_channels;
- ret = ad5686_spi_write(st, AD5686_CMD_INTERNAL_REFER_SETUP, 0,
- !!voltage_uv, 0);
+ ret = st->write(st, AD5686_CMD_INTERNAL_REFER_SETUP,
+ 0, !!voltage_uv);
if (ret)
goto error_disable_reg;
@@ -370,10 +335,11 @@ error_disable_reg:
regulator_disable(st->reg);
return ret;
}
+EXPORT_SYMBOL_GPL(ad5686_probe);
-static int ad5686_remove(struct spi_device *spi)
+int ad5686_remove(struct device *dev)
{
- struct iio_dev *indio_dev = spi_get_drvdata(spi);
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ad5686_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
@@ -382,24 +348,7 @@ static int ad5686_remove(struct spi_device *spi)
return 0;
}
-
-static const struct spi_device_id ad5686_id[] = {
- {"ad5684", ID_AD5684},
- {"ad5685", ID_AD5685},
- {"ad5686", ID_AD5686},
- {}
-};
-MODULE_DEVICE_TABLE(spi, ad5686_id);
-
-static struct spi_driver ad5686_driver = {
- .driver = {
- .name = "ad5686",
- },
- .probe = ad5686_probe,
- .remove = ad5686_remove,
- .id_table = ad5686_id,
-};
-module_spi_driver(ad5686_driver);
+EXPORT_SYMBOL_GPL(ad5686_remove);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("Analog Devices AD5686/85/84 DAC");
diff --git a/drivers/iio/dac/ad5686.h b/drivers/iio/dac/ad5686.h
new file mode 100644
index 000000000000..05f0ce9d2de1
--- /dev/null
+++ b/drivers/iio/dac/ad5686.h
@@ -0,0 +1,121 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * This file is part of AD5686 DAC driver
+ *
+ * Copyright 2018 Analog Devices Inc.
+ */
+
+#ifndef __DRIVERS_IIO_DAC_AD5686_H__
+#define __DRIVERS_IIO_DAC_AD5686_H__
+
+#include <linux/types.h>
+#include <linux/cache.h>
+#include <linux/mutex.h>
+#include <linux/kernel.h>
+
+#define AD5686_ADDR(x) ((x) << 16)
+#define AD5686_CMD(x) ((x) << 20)
+
+#define AD5686_ADDR_DAC(chan) (0x1 << (chan))
+#define AD5686_ADDR_ALL_DAC 0xF
+
+#define AD5686_CMD_NOOP 0x0
+#define AD5686_CMD_WRITE_INPUT_N 0x1
+#define AD5686_CMD_UPDATE_DAC_N 0x2
+#define AD5686_CMD_WRITE_INPUT_N_UPDATE_N 0x3
+#define AD5686_CMD_POWERDOWN_DAC 0x4
+#define AD5686_CMD_LDAC_MASK 0x5
+#define AD5686_CMD_RESET 0x6
+#define AD5686_CMD_INTERNAL_REFER_SETUP 0x7
+#define AD5686_CMD_DAISY_CHAIN_ENABLE 0x8
+#define AD5686_CMD_READBACK_ENABLE 0x9
+
+#define AD5686_LDAC_PWRDN_NONE 0x0
+#define AD5686_LDAC_PWRDN_1K 0x1
+#define AD5686_LDAC_PWRDN_100K 0x2
+#define AD5686_LDAC_PWRDN_3STATE 0x3
+
+/**
+ * ad5686_supported_device_ids:
+ */
+enum ad5686_supported_device_ids {
+ ID_AD5671R,
+ ID_AD5672R,
+ ID_AD5675R,
+ ID_AD5676,
+ ID_AD5676R,
+ ID_AD5684,
+ ID_AD5684R,
+ ID_AD5685R,
+ ID_AD5686,
+ ID_AD5686R,
+ ID_AD5694,
+ ID_AD5694R,
+ ID_AD5695R,
+ ID_AD5696,
+ ID_AD5696R,
+};
+
+struct ad5686_state;
+
+typedef int (*ad5686_write_func)(struct ad5686_state *st,
+ u8 cmd, u8 addr, u16 val);
+
+typedef int (*ad5686_read_func)(struct ad5686_state *st, u8 addr);
+
+/**
+ * struct ad5686_chip_info - chip specific information
+ * @int_vref_mv: AD5620/40/60: the internal reference voltage
+ * @num_channels: number of channels
+ * @channel: channel specification
+ */
+
+struct ad5686_chip_info {
+ u16 int_vref_mv;
+ unsigned int num_channels;
+ struct iio_chan_spec *channels;
+};
+
+/**
+ * struct ad5446_state - driver instance specific data
+ * @spi: spi_device
+ * @chip_info: chip model specific constants, available modes etc
+ * @reg: supply regulator
+ * @vref_mv: actual reference voltage used
+ * @pwr_down_mask: power down mask
+ * @pwr_down_mode: current power down mode
+ * @data: spi transfer buffers
+ */
+
+struct ad5686_state {
+ struct device *dev;
+ const struct ad5686_chip_info *chip_info;
+ struct regulator *reg;
+ unsigned short vref_mv;
+ unsigned int pwr_down_mask;
+ unsigned int pwr_down_mode;
+ ad5686_write_func write;
+ ad5686_read_func read;
+
+ /*
+ * DMA (thus cache coherency maintenance) requires the
+ * transfer buffers to live in their own cache lines.
+ */
+
+ union {
+ __be32 d32;
+ __be16 d16;
+ u8 d8[4];
+ } data[3] ____cacheline_aligned;
+};
+
+
+int ad5686_probe(struct device *dev,
+ enum ad5686_supported_device_ids chip_type,
+ const char *name, ad5686_write_func write,
+ ad5686_read_func read);
+
+int ad5686_remove(struct device *dev);
+
+
+#endif /* __DRIVERS_IIO_DAC_AD5686_H__ */
diff --git a/drivers/iio/dac/ad5696-i2c.c b/drivers/iio/dac/ad5696-i2c.c
new file mode 100644
index 000000000000..275e0321bcf8
--- /dev/null
+++ b/drivers/iio/dac/ad5696-i2c.c
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * AD5671R, AD5675R, AD5694, AD5694R, AD5695R, AD5696, AD5696R
+ * Digital to analog converters driver
+ *
+ * Copyright 2018 Analog Devices Inc.
+ */
+
+#include "ad5686.h"
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+
+static int ad5686_i2c_read(struct ad5686_state *st, u8 addr)
+{
+ struct i2c_client *i2c = to_i2c_client(st->dev);
+ struct i2c_msg msg[2] = {
+ {
+ .addr = i2c->addr,
+ .flags = i2c->flags,
+ .len = 3,
+ .buf = &st->data[0].d8[1],
+ },
+ {
+ .addr = i2c->addr,
+ .flags = i2c->flags | I2C_M_RD,
+ .len = 2,
+ .buf = (char *)&st->data[0].d16,
+ },
+ };
+ int ret;
+
+ st->data[0].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_NOOP) |
+ AD5686_ADDR(addr) |
+ 0x00);
+
+ ret = i2c_transfer(i2c->adapter, msg, 2);
+ if (ret < 0)
+ return ret;
+
+ return be16_to_cpu(st->data[0].d16);
+}
+
+static int ad5686_i2c_write(struct ad5686_state *st,
+ u8 cmd, u8 addr, u16 val)
+{
+ struct i2c_client *i2c = to_i2c_client(st->dev);
+ int ret;
+
+ st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) | AD5686_ADDR(addr)
+ | val);
+
+ ret = i2c_master_send(i2c, &st->data[0].d8[1], 3);
+ if (ret < 0)
+ return ret;
+
+ return (ret != 3) ? -EIO : 0;
+}
+
+static int ad5686_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ return ad5686_probe(&i2c->dev, id->driver_data, id->name,
+ ad5686_i2c_write, ad5686_i2c_read);
+}
+
+static int ad5686_i2c_remove(struct i2c_client *i2c)
+{
+ return ad5686_remove(&i2c->dev);
+}
+
+static const struct i2c_device_id ad5686_i2c_id[] = {
+ {"ad5671r", ID_AD5671R},
+ {"ad5675r", ID_AD5675R},
+ {"ad5694", ID_AD5694},
+ {"ad5694r", ID_AD5694R},
+ {"ad5695r", ID_AD5695R},
+ {"ad5696", ID_AD5696},
+ {"ad5696r", ID_AD5696R},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, ad5686_i2c_id);
+
+static struct i2c_driver ad5686_i2c_driver = {
+ .driver = {
+ .name = "ad5696",
+ },
+ .probe = ad5686_i2c_probe,
+ .remove = ad5686_i2c_remove,
+ .id_table = ad5686_i2c_id,
+};
+
+module_i2c_driver(ad5686_i2c_driver);
+
+MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>");
+MODULE_DESCRIPTION("Analog Devices AD5686 and similar multi-channel DACs");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/dac/ti-dac5571.c b/drivers/iio/dac/ti-dac5571.c
new file mode 100644
index 000000000000..dd21eebed6a8
--- /dev/null
+++ b/drivers/iio/dac/ti-dac5571.c
@@ -0,0 +1,439 @@
+/*
+ * ti-dac5571.c - Texas Instruments 8/10/12-bit 1/4-channel DAC driver
+ *
+ * Copyright (C) 2018 Prevas A/S
+ *
+ * http://www.ti.com/lit/ds/symlink/dac5571.pdf
+ * http://www.ti.com/lit/ds/symlink/dac6571.pdf
+ * http://www.ti.com/lit/ds/symlink/dac7571.pdf
+ * http://www.ti.com/lit/ds/symlink/dac5574.pdf
+ * http://www.ti.com/lit/ds/symlink/dac6574.pdf
+ * http://www.ti.com/lit/ds/symlink/dac7574.pdf
+ * http://www.ti.com/lit/ds/symlink/dac5573.pdf
+ * http://www.ti.com/lit/ds/symlink/dac6573.pdf
+ * http://www.ti.com/lit/ds/symlink/dac7573.pdf
+ *
+ * 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/iio/iio.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+
+enum chip_id {
+ single_8bit, single_10bit, single_12bit,
+ quad_8bit, quad_10bit, quad_12bit
+};
+
+struct dac5571_spec {
+ u8 num_channels;
+ u8 resolution;
+};
+
+static const struct dac5571_spec dac5571_spec[] = {
+ [single_8bit] = {.num_channels = 1, .resolution = 8},
+ [single_10bit] = {.num_channels = 1, .resolution = 10},
+ [single_12bit] = {.num_channels = 1, .resolution = 12},
+ [quad_8bit] = {.num_channels = 4, .resolution = 8},
+ [quad_10bit] = {.num_channels = 4, .resolution = 10},
+ [quad_12bit] = {.num_channels = 4, .resolution = 12},
+};
+
+struct dac5571_data {
+ struct i2c_client *client;
+ int id;
+ struct mutex lock;
+ struct regulator *vref;
+ u16 val[4];
+ bool powerdown;
+ u8 powerdown_mode;
+ struct dac5571_spec const *spec;
+ int (*dac5571_cmd)(struct dac5571_data *data, int channel, u16 val);
+ int (*dac5571_pwrdwn)(struct dac5571_data *data, int channel, u8 pwrdwn);
+ u8 buf[3] ____cacheline_aligned;
+};
+
+#define DAC5571_POWERDOWN(mode) ((mode) + 1)
+#define DAC5571_POWERDOWN_FLAG BIT(0)
+#define DAC5571_CHANNEL_SELECT 1
+#define DAC5571_LOADMODE_DIRECT BIT(4)
+#define DAC5571_SINGLE_PWRDWN_BITS 4
+#define DAC5571_QUAD_PWRDWN_BITS 6
+
+static int dac5571_cmd_single(struct dac5571_data *data, int channel, u16 val)
+{
+ unsigned int shift;
+
+ shift = 12 - data->spec->resolution;
+ data->buf[1] = val << shift;
+ data->buf[0] = val >> (8 - shift);
+
+ if (i2c_master_send(data->client, data->buf, 2) != 2)
+ return -EIO;
+
+ return 0;
+}
+
+static int dac5571_cmd_quad(struct dac5571_data *data, int channel, u16 val)
+{
+ unsigned int shift;
+
+ shift = 16 - data->spec->resolution;
+ data->buf[2] = val << shift;
+ data->buf[1] = (val >> (8 - shift));
+ data->buf[0] = (channel << DAC5571_CHANNEL_SELECT) |
+ DAC5571_LOADMODE_DIRECT;
+
+ if (i2c_master_send(data->client, data->buf, 3) != 3)
+ return -EIO;
+
+ return 0;
+}
+
+static int dac5571_pwrdwn_single(struct dac5571_data *data, int channel, u8 pwrdwn)
+{
+ unsigned int shift;
+
+ shift = 12 - data->spec->resolution;
+ data->buf[1] = 0;
+ data->buf[0] = pwrdwn << DAC5571_SINGLE_PWRDWN_BITS;
+
+ if (i2c_master_send(data->client, data->buf, 2) != 2)
+ return -EIO;
+
+ return 0;
+}
+
+static int dac5571_pwrdwn_quad(struct dac5571_data *data, int channel, u8 pwrdwn)
+{
+ unsigned int shift;
+
+ shift = 16 - data->spec->resolution;
+ data->buf[2] = 0;
+ data->buf[1] = pwrdwn << DAC5571_QUAD_PWRDWN_BITS;
+ data->buf[0] = (channel << DAC5571_CHANNEL_SELECT) |
+ DAC5571_LOADMODE_DIRECT | DAC5571_POWERDOWN_FLAG;
+
+ if (i2c_master_send(data->client, data->buf, 3) != 3)
+ return -EIO;
+
+ return 0;
+}
+
+static const char *const dac5571_powerdown_modes[] = {
+ "1kohm_to_gnd", "100kohm_to_gnd", "three_state",
+};
+
+static int dac5571_get_powerdown_mode(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan)
+{
+ struct dac5571_data *data = iio_priv(indio_dev);
+
+ return data->powerdown_mode;
+}
+
+static int dac5571_set_powerdown_mode(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ unsigned int mode)
+{
+ struct dac5571_data *data = iio_priv(indio_dev);
+ int ret = 0;
+
+ if (data->powerdown_mode == mode)
+ return 0;
+
+ mutex_lock(&data->lock);
+ if (data->powerdown) {
+ ret = data->dac5571_pwrdwn(data, chan->channel,
+ DAC5571_POWERDOWN(mode));
+ if (ret)
+ goto out;
+ }
+ data->powerdown_mode = mode;
+
+ out:
+ mutex_unlock(&data->lock);
+
+ return ret;
+}
+
+static const struct iio_enum dac5571_powerdown_mode = {
+ .items = dac5571_powerdown_modes,
+ .num_items = ARRAY_SIZE(dac5571_powerdown_modes),
+ .get = dac5571_get_powerdown_mode,
+ .set = dac5571_set_powerdown_mode,
+};
+
+static ssize_t dac5571_read_powerdown(struct iio_dev *indio_dev,
+ uintptr_t private,
+ const struct iio_chan_spec *chan,
+ char *buf)
+{
+ struct dac5571_data *data = iio_priv(indio_dev);
+
+ return sprintf(buf, "%d\n", data->powerdown);
+}
+
+static ssize_t dac5571_write_powerdown(struct iio_dev *indio_dev,
+ uintptr_t private,
+ const struct iio_chan_spec *chan,
+ const char *buf, size_t len)
+{
+ struct dac5571_data *data = iio_priv(indio_dev);
+ bool powerdown;
+ int ret;
+
+ ret = strtobool(buf, &powerdown);
+ if (ret)
+ return ret;
+
+ if (data->powerdown == powerdown)
+ return len;
+
+ mutex_lock(&data->lock);
+ if (powerdown)
+ ret = data->dac5571_pwrdwn(data, chan->channel,
+ DAC5571_POWERDOWN(data->powerdown_mode));
+ else
+ ret = data->dac5571_cmd(data, chan->channel, data->val[0]);
+ if (ret)
+ goto out;
+
+ data->powerdown = powerdown;
+
+ out:
+ mutex_unlock(&data->lock);
+
+ return ret ? ret : len;
+}
+
+
+static const struct iio_chan_spec_ext_info dac5571_ext_info[] = {
+ {
+ .name = "powerdown",
+ .read = dac5571_read_powerdown,
+ .write = dac5571_write_powerdown,
+ .shared = IIO_SHARED_BY_TYPE,
+ },
+ IIO_ENUM("powerdown_mode", IIO_SHARED_BY_TYPE, &dac5571_powerdown_mode),
+ IIO_ENUM_AVAILABLE("powerdown_mode", &dac5571_powerdown_mode),
+ {},
+};
+
+#define dac5571_CHANNEL(chan, name) { \
+ .type = IIO_VOLTAGE, \
+ .channel = (chan), \
+ .address = (chan), \
+ .indexed = true, \
+ .output = true, \
+ .datasheet_name = name, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .ext_info = dac5571_ext_info, \
+}
+
+static const struct iio_chan_spec dac5571_channels[] = {
+ dac5571_CHANNEL(0, "A"),
+ dac5571_CHANNEL(1, "B"),
+ dac5571_CHANNEL(2, "C"),
+ dac5571_CHANNEL(3, "D"),
+};
+
+static int dac5571_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct dac5571_data *data = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ *val = data->val[chan->channel];
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_SCALE:
+ ret = regulator_get_voltage(data->vref);
+ if (ret < 0)
+ return ret;
+
+ *val = ret / 1000;
+ *val2 = data->spec->resolution;
+ return IIO_VAL_FRACTIONAL_LOG2;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int dac5571_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct dac5571_data *data = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ if (data->val[chan->channel] == val)
+ return 0;
+
+ if (val >= (1 << data->spec->resolution) || val < 0)
+ return -EINVAL;
+
+ if (data->powerdown)
+ return -EBUSY;
+
+ mutex_lock(&data->lock);
+ ret = data->dac5571_cmd(data, chan->channel, val);
+ if (ret == 0)
+ data->val[chan->channel] = val;
+ mutex_unlock(&data->lock);
+ return ret;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int dac5571_write_raw_get_fmt(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ long mask)
+{
+ return IIO_VAL_INT;
+}
+
+static const struct iio_info dac5571_info = {
+ .read_raw = dac5571_read_raw,
+ .write_raw = dac5571_write_raw,
+ .write_raw_get_fmt = dac5571_write_raw_get_fmt,
+};
+
+static int dac5571_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ const struct dac5571_spec *spec;
+ struct dac5571_data *data;
+ struct iio_dev *indio_dev;
+ int ret, i;
+
+ indio_dev = devm_iio_device_alloc(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 = dev;
+ indio_dev->dev.of_node = client->dev.of_node;
+ indio_dev->info = &dac5571_info;
+ indio_dev->name = id->name;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = dac5571_channels;
+
+ spec = &dac5571_spec[id->driver_data];
+ indio_dev->num_channels = spec->num_channels;
+ data->spec = spec;
+
+ data->vref = devm_regulator_get(dev, "vref");
+ if (IS_ERR(data->vref))
+ return PTR_ERR(data->vref);
+
+ ret = regulator_enable(data->vref);
+ if (ret < 0)
+ return ret;
+
+ mutex_init(&data->lock);
+
+ switch (spec->num_channels) {
+ case 1:
+ data->dac5571_cmd = dac5571_cmd_single;
+ data->dac5571_pwrdwn = dac5571_pwrdwn_single;
+ break;
+ case 4:
+ data->dac5571_cmd = dac5571_cmd_quad;
+ data->dac5571_pwrdwn = dac5571_pwrdwn_quad;
+ break;
+ default:
+ goto err;
+ }
+
+ for (i = 0; i < spec->num_channels; i++) {
+ ret = data->dac5571_cmd(data, i, 0);
+ if (ret) {
+ dev_err(dev, "failed to initialize channel %d to 0\n", i);
+ goto err;
+ }
+ }
+
+ ret = iio_device_register(indio_dev);
+ if (ret)
+ goto err;
+
+ return 0;
+
+ err:
+ regulator_disable(data->vref);
+ return ret;
+}
+
+static int dac5571_remove(struct i2c_client *i2c)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(i2c);
+ struct dac5571_data *data = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+ regulator_disable(data->vref);
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id dac5571_of_id[] = {
+ {.compatible = "ti,dac5571"},
+ {.compatible = "ti,dac6571"},
+ {.compatible = "ti,dac7571"},
+ {.compatible = "ti,dac5574"},
+ {.compatible = "ti,dac6574"},
+ {.compatible = "ti,dac7574"},
+ {.compatible = "ti,dac5573"},
+ {.compatible = "ti,dac6573"},
+ {.compatible = "ti,dac7573"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, dac5571_of_id);
+#endif
+
+static const struct i2c_device_id dac5571_id[] = {
+ {"dac5571", single_8bit},
+ {"dac6571", single_10bit},
+ {"dac7571", single_12bit},
+ {"dac5574", quad_8bit},
+ {"dac6574", quad_10bit},
+ {"dac7574", quad_12bit},
+ {"dac5573", quad_8bit},
+ {"dac6573", quad_10bit},
+ {"dac7573", quad_12bit},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, dac5571_id);
+
+static struct i2c_driver dac5571_driver = {
+ .driver = {
+ .name = "ti-dac5571",
+ },
+ .probe = dac5571_probe,
+ .remove = dac5571_remove,
+ .id_table = dac5571_id,
+};
+module_i2c_driver(dac5571_driver);
+
+MODULE_AUTHOR("Sean Nyekjaer <sean.nyekjaer@prevas.dk>");
+MODULE_DESCRIPTION("Texas Instruments 8/10/12-bit 1/4-channel DAC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
index 7d64be353403..43fba5f7532b 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
@@ -24,6 +24,7 @@
#include <linux/spinlock.h>
#include <linux/iio/iio.h>
#include <linux/acpi.h>
+#include <linux/platform_device.h>
#include "inv_mpu_iio.h"
/*
@@ -52,6 +53,7 @@ static const struct inv_mpu6050_reg_map reg_set_6500 = {
.raw_accl = INV_MPU6050_REG_RAW_ACCEL,
.temperature = INV_MPU6050_REG_TEMPERATURE,
.int_enable = INV_MPU6050_REG_INT_ENABLE,
+ .int_status = INV_MPU6050_REG_INT_STATUS,
.pwr_mgmt_1 = INV_MPU6050_REG_PWR_MGMT_1,
.pwr_mgmt_2 = INV_MPU6050_REG_PWR_MGMT_2,
.int_pin_cfg = INV_MPU6050_REG_INT_PIN_CFG,
@@ -86,6 +88,7 @@ static const struct inv_mpu6050_chip_config chip_config_6050 = {
.gyro_fifo_enable = false,
.accl_fifo_enable = false,
.accl_fs = INV_MPU6050_FS_02G,
+ .user_ctrl = 0,
};
/* Indexed by enum inv_devices */
@@ -121,6 +124,12 @@ static const struct inv_mpu6050_hw hw_info[] = {
.config = &chip_config_6050,
},
{
+ .whoami = INV_MPU9255_WHOAMI_VALUE,
+ .name = "MPU9255",
+ .reg = &reg_set_6500,
+ .config = &chip_config_6050,
+ },
+ {
.whoami = INV_ICM20608_WHOAMI_VALUE,
.name = "ICM20608",
.reg = &reg_set_6500,
@@ -168,7 +177,7 @@ int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask)
return result;
if (en) {
- /* Wait for output stabilize */
+ /* Wait for output to stabilize */
msleep(INV_MPU6050_TEMP_UP_TIME);
if (mask == INV_MPU6050_BIT_PWR_GYRO_STBY) {
/* switch internal clock to PLL */
@@ -185,26 +194,29 @@ int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask)
int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on)
{
- int result = 0;
+ int result;
if (power_on) {
- if (!st->powerup_count)
+ if (!st->powerup_count) {
result = regmap_write(st->map, st->reg->pwr_mgmt_1, 0);
- if (!result)
- st->powerup_count++;
+ if (result)
+ return result;
+ usleep_range(INV_MPU6050_REG_UP_TIME_MIN,
+ INV_MPU6050_REG_UP_TIME_MAX);
+ }
+ st->powerup_count++;
} else {
- st->powerup_count--;
- if (!st->powerup_count)
+ if (st->powerup_count == 1) {
result = regmap_write(st->map, st->reg->pwr_mgmt_1,
INV_MPU6050_BIT_SLEEP);
+ if (result)
+ return result;
+ }
+ st->powerup_count--;
}
- if (result)
- return result;
-
- if (power_on)
- usleep_range(INV_MPU6050_REG_UP_TIME_MIN,
- INV_MPU6050_REG_UP_TIME_MAX);
+ dev_dbg(regmap_get_device(st->map), "set power %d, count=%u\n",
+ power_on, st->powerup_count);
return 0;
}
@@ -262,26 +274,33 @@ static int inv_mpu6050_init_config(struct iio_dev *indio_dev)
d = (INV_MPU6050_FSR_2000DPS << INV_MPU6050_GYRO_CONFIG_FSR_SHIFT);
result = regmap_write(st->map, st->reg->gyro_config, d);
if (result)
- return result;
+ goto error_power_off;
result = inv_mpu6050_set_lpf_regs(st, INV_MPU6050_FILTER_20HZ);
if (result)
- return result;
+ goto error_power_off;
d = INV_MPU6050_ONE_K_HZ / INV_MPU6050_INIT_FIFO_RATE - 1;
result = regmap_write(st->map, st->reg->sample_rate_div, d);
if (result)
- return result;
+ goto error_power_off;
d = (INV_MPU6050_FS_02G << INV_MPU6050_ACCL_CONFIG_FSR_SHIFT);
result = regmap_write(st->map, st->reg->accl_config, d);
if (result)
+ goto error_power_off;
+
+ result = regmap_write(st->map, st->reg->int_pin_cfg, st->irq_mask);
+ if (result)
return result;
memcpy(&st->chip_config, hw_info[st->chip_type].config,
sizeof(struct inv_mpu6050_chip_config));
- result = inv_mpu6050_set_power_itg(st, false);
+ return inv_mpu6050_set_power_itg(st, false);
+
+error_power_off:
+ inv_mpu6050_set_power_itg(st, false);
return result;
}
@@ -314,6 +333,65 @@ static int inv_mpu6050_sensor_show(struct inv_mpu6050_state *st, int reg,
return IIO_VAL_INT;
}
+static int inv_mpu6050_read_channel_data(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val)
+{
+ struct inv_mpu6050_state *st = iio_priv(indio_dev);
+ int result;
+ int ret;
+
+ result = inv_mpu6050_set_power_itg(st, true);
+ if (result)
+ return result;
+
+ switch (chan->type) {
+ case IIO_ANGL_VEL:
+ result = inv_mpu6050_switch_engine(st, true,
+ INV_MPU6050_BIT_PWR_GYRO_STBY);
+ if (result)
+ goto error_power_off;
+ ret = inv_mpu6050_sensor_show(st, st->reg->raw_gyro,
+ chan->channel2, val);
+ result = inv_mpu6050_switch_engine(st, false,
+ INV_MPU6050_BIT_PWR_GYRO_STBY);
+ if (result)
+ goto error_power_off;
+ break;
+ case IIO_ACCEL:
+ result = inv_mpu6050_switch_engine(st, true,
+ INV_MPU6050_BIT_PWR_ACCL_STBY);
+ if (result)
+ goto error_power_off;
+ ret = inv_mpu6050_sensor_show(st, st->reg->raw_accl,
+ chan->channel2, val);
+ result = inv_mpu6050_switch_engine(st, false,
+ INV_MPU6050_BIT_PWR_ACCL_STBY);
+ if (result)
+ goto error_power_off;
+ break;
+ case IIO_TEMP:
+ /* wait for stablization */
+ msleep(INV_MPU6050_SENSOR_UP_TIME);
+ ret = inv_mpu6050_sensor_show(st, st->reg->temperature,
+ IIO_MOD_X, val);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ result = inv_mpu6050_set_power_itg(st, false);
+ if (result)
+ goto error_power_off;
+
+ return ret;
+
+error_power_off:
+ inv_mpu6050_set_power_itg(st, false);
+ return result;
+}
+
static int
inv_mpu6050_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
@@ -324,63 +402,14 @@ inv_mpu6050_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- {
- int result;
-
- ret = IIO_VAL_INT;
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret)
+ return ret;
mutex_lock(&st->lock);
- result = iio_device_claim_direct_mode(indio_dev);
- if (result)
- goto error_read_raw_unlock;
- result = inv_mpu6050_set_power_itg(st, true);
- if (result)
- goto error_read_raw_release;
- switch (chan->type) {
- case IIO_ANGL_VEL:
- result = inv_mpu6050_switch_engine(st, true,
- INV_MPU6050_BIT_PWR_GYRO_STBY);
- if (result)
- goto error_read_raw_power_off;
- ret = inv_mpu6050_sensor_show(st, st->reg->raw_gyro,
- chan->channel2, val);
- result = inv_mpu6050_switch_engine(st, false,
- INV_MPU6050_BIT_PWR_GYRO_STBY);
- if (result)
- goto error_read_raw_power_off;
- break;
- case IIO_ACCEL:
- result = inv_mpu6050_switch_engine(st, true,
- INV_MPU6050_BIT_PWR_ACCL_STBY);
- if (result)
- goto error_read_raw_power_off;
- ret = inv_mpu6050_sensor_show(st, st->reg->raw_accl,
- chan->channel2, val);
- result = inv_mpu6050_switch_engine(st, false,
- INV_MPU6050_BIT_PWR_ACCL_STBY);
- if (result)
- goto error_read_raw_power_off;
- break;
- case IIO_TEMP:
- /* wait for stablization */
- msleep(INV_MPU6050_SENSOR_UP_TIME);
- ret = inv_mpu6050_sensor_show(st, st->reg->temperature,
- IIO_MOD_X, val);
- break;
- default:
- ret = -EINVAL;
- break;
- }
-error_read_raw_power_off:
- result |= inv_mpu6050_set_power_itg(st, false);
-error_read_raw_release:
- iio_device_release_direct_mode(indio_dev);
-error_read_raw_unlock:
+ ret = inv_mpu6050_read_channel_data(indio_dev, chan, val);
mutex_unlock(&st->lock);
- if (result)
- return result;
-
+ iio_device_release_direct_mode(indio_dev);
return ret;
- }
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_ANGL_VEL:
@@ -502,17 +531,18 @@ static int inv_mpu6050_write_raw(struct iio_dev *indio_dev,
struct inv_mpu6050_state *st = iio_priv(indio_dev);
int result;
- mutex_lock(&st->lock);
/*
* we should only update scale when the chip is disabled, i.e.
* not running
*/
result = iio_device_claim_direct_mode(indio_dev);
if (result)
- goto error_write_raw_unlock;
+ return result;
+
+ mutex_lock(&st->lock);
result = inv_mpu6050_set_power_itg(st, true);
if (result)
- goto error_write_raw_release;
+ goto error_write_raw_unlock;
switch (mask) {
case IIO_CHAN_INFO_SCALE:
@@ -551,10 +581,9 @@ static int inv_mpu6050_write_raw(struct iio_dev *indio_dev,
}
result |= inv_mpu6050_set_power_itg(st, false);
-error_write_raw_release:
- iio_device_release_direct_mode(indio_dev);
error_write_raw_unlock:
mutex_unlock(&st->lock);
+ iio_device_release_direct_mode(indio_dev);
return result;
}
@@ -613,17 +642,18 @@ inv_mpu6050_fifo_rate_store(struct device *dev, struct device_attribute *attr,
fifo_rate > INV_MPU6050_MAX_FIFO_RATE)
return -EINVAL;
+ result = iio_device_claim_direct_mode(indio_dev);
+ if (result)
+ return result;
+
mutex_lock(&st->lock);
if (fifo_rate == st->chip_config.fifo_rate) {
result = 0;
goto fifo_rate_fail_unlock;
}
- result = iio_device_claim_direct_mode(indio_dev);
- if (result)
- goto fifo_rate_fail_unlock;
result = inv_mpu6050_set_power_itg(st, true);
if (result)
- goto fifo_rate_fail_release;
+ goto fifo_rate_fail_unlock;
d = INV_MPU6050_ONE_K_HZ / fifo_rate - 1;
result = regmap_write(st->map, st->reg->sample_rate_div, d);
@@ -637,10 +667,9 @@ inv_mpu6050_fifo_rate_store(struct device *dev, struct device_attribute *attr,
fifo_rate_fail_power_off:
result |= inv_mpu6050_set_power_itg(st, false);
-fifo_rate_fail_release:
- iio_device_release_direct_mode(indio_dev);
fifo_rate_fail_unlock:
mutex_unlock(&st->lock);
+ iio_device_release_direct_mode(indio_dev);
if (result)
return result;
@@ -850,14 +879,11 @@ static int inv_check_and_setup_chip(struct inv_mpu6050_state *st)
msleep(INV_MPU6050_POWER_UP_TIME);
/*
- * toggle power state. After reset, the sleep bit could be on
- * or off depending on the OTP settings. Toggling power would
+ * Turn power on. After reset, the sleep bit could be on
+ * or off depending on the OTP settings. Turning power on
* make it in a definite state as well as making the hardware
* state align with the software state
*/
- result = inv_mpu6050_set_power_itg(st, false);
- if (result)
- return result;
result = inv_mpu6050_set_power_itg(st, true);
if (result)
return result;
@@ -865,13 +891,17 @@ static int inv_check_and_setup_chip(struct inv_mpu6050_state *st)
result = inv_mpu6050_switch_engine(st, false,
INV_MPU6050_BIT_PWR_ACCL_STBY);
if (result)
- return result;
+ goto error_power_off;
result = inv_mpu6050_switch_engine(st, false,
INV_MPU6050_BIT_PWR_GYRO_STBY);
if (result)
- return result;
+ goto error_power_off;
- return 0;
+ return inv_mpu6050_set_power_itg(st, false);
+
+error_power_off:
+ inv_mpu6050_set_power_itg(st, false);
+ return result;
}
int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
@@ -882,6 +912,8 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
struct inv_mpu6050_platform_data *pdata;
struct device *dev = regmap_get_device(regmap);
int result;
+ struct irq_data *desc;
+ int irq_type;
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (!indio_dev)
@@ -913,20 +945,43 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
st->plat_data = *pdata;
}
+ desc = irq_get_irq_data(irq);
+ if (!desc) {
+ dev_err(dev, "Could not find IRQ %d\n", irq);
+ return -EINVAL;
+ }
+
+ irq_type = irqd_get_trigger_type(desc);
+ if (irq_type == IRQF_TRIGGER_RISING)
+ st->irq_mask = INV_MPU6050_ACTIVE_HIGH;
+ else if (irq_type == IRQF_TRIGGER_FALLING)
+ st->irq_mask = INV_MPU6050_ACTIVE_LOW;
+ else if (irq_type == IRQF_TRIGGER_HIGH)
+ st->irq_mask = INV_MPU6050_ACTIVE_HIGH |
+ INV_MPU6050_LATCH_INT_EN;
+ else if (irq_type == IRQF_TRIGGER_LOW)
+ st->irq_mask = INV_MPU6050_ACTIVE_LOW |
+ INV_MPU6050_LATCH_INT_EN;
+ else {
+ dev_err(dev, "Invalid interrupt type 0x%x specified\n",
+ irq_type);
+ return -EINVAL;
+ }
+
/* power is turned on inside check chip type*/
result = inv_check_and_setup_chip(st);
if (result)
return result;
- if (inv_mpu_bus_setup)
- inv_mpu_bus_setup(indio_dev);
-
result = inv_mpu6050_init_config(indio_dev);
if (result) {
dev_err(dev, "Could not initialize device.\n");
return result;
}
+ if (inv_mpu_bus_setup)
+ inv_mpu_bus_setup(indio_dev);
+
dev_set_drvdata(dev, indio_dev);
indio_dev->dev.parent = dev;
/* name will be NULL when enumerated via ACPI */
@@ -940,50 +995,32 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
indio_dev->info = &mpu_info;
indio_dev->modes = INDIO_BUFFER_TRIGGERED;
- result = iio_triggered_buffer_setup(indio_dev,
- inv_mpu6050_irq_handler,
- inv_mpu6050_read_fifo,
- NULL);
+ result = devm_iio_triggered_buffer_setup(dev, indio_dev,
+ inv_mpu6050_irq_handler,
+ inv_mpu6050_read_fifo,
+ NULL);
if (result) {
dev_err(dev, "configure buffer fail %d\n", result);
return result;
}
- result = inv_mpu6050_probe_trigger(indio_dev);
+ result = inv_mpu6050_probe_trigger(indio_dev, irq_type);
if (result) {
dev_err(dev, "trigger probe fail %d\n", result);
- goto out_unreg_ring;
+ return result;
}
INIT_KFIFO(st->timestamps);
spin_lock_init(&st->time_stamp_lock);
- result = iio_device_register(indio_dev);
+ result = devm_iio_device_register(dev, indio_dev);
if (result) {
dev_err(dev, "IIO register fail %d\n", result);
- goto out_remove_trigger;
+ return result;
}
return 0;
-
-out_remove_trigger:
- inv_mpu6050_remove_trigger(st);
-out_unreg_ring:
- iio_triggered_buffer_cleanup(indio_dev);
- return result;
}
EXPORT_SYMBOL_GPL(inv_mpu_core_probe);
-int inv_mpu_core_remove(struct device *dev)
-{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
-
- iio_device_unregister(indio_dev);
- inv_mpu6050_remove_trigger(iio_priv(indio_dev));
- iio_triggered_buffer_cleanup(indio_dev);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(inv_mpu_core_remove);
-
#ifdef CONFIG_PM_SLEEP
static int inv_mpu_resume(struct device *dev)
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c
index fcd7a92b6cf8..495409d56207 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c
@@ -29,25 +29,18 @@ static int inv_mpu6050_select_bypass(struct i2c_mux_core *muxc, u32 chan_id)
{
struct iio_dev *indio_dev = i2c_mux_priv(muxc);
struct inv_mpu6050_state *st = iio_priv(indio_dev);
- int ret = 0;
+ int ret;
- /* Use the same mutex which was used everywhere to protect power-op */
mutex_lock(&st->lock);
- if (!st->powerup_count) {
- ret = regmap_write(st->map, st->reg->pwr_mgmt_1, 0);
- if (ret)
- goto write_error;
- usleep_range(INV_MPU6050_REG_UP_TIME_MIN,
- INV_MPU6050_REG_UP_TIME_MAX);
- }
- if (!ret) {
- st->powerup_count++;
- ret = regmap_write(st->map, st->reg->int_pin_cfg,
- INV_MPU6050_INT_PIN_CFG |
- INV_MPU6050_BIT_BYPASS_EN);
- }
-write_error:
+ ret = inv_mpu6050_set_power_itg(st, true);
+ if (ret)
+ goto error_unlock;
+
+ ret = regmap_write(st->map, st->reg->int_pin_cfg,
+ st->irq_mask | INV_MPU6050_BIT_BYPASS_EN);
+
+error_unlock:
mutex_unlock(&st->lock);
return ret;
@@ -59,12 +52,11 @@ static int inv_mpu6050_deselect_bypass(struct i2c_mux_core *muxc, u32 chan_id)
struct inv_mpu6050_state *st = iio_priv(indio_dev);
mutex_lock(&st->lock);
- /* It doesn't really mattter, if any of the calls fails */
- regmap_write(st->map, st->reg->int_pin_cfg, INV_MPU6050_INT_PIN_CFG);
- st->powerup_count--;
- if (!st->powerup_count)
- regmap_write(st->map, st->reg->pwr_mgmt_1,
- INV_MPU6050_BIT_SLEEP);
+
+ /* It doesn't really matter if any of the calls fail */
+ regmap_write(st->map, st->reg->int_pin_cfg, st->irq_mask);
+ inv_mpu6050_set_power_itg(st, false);
+
mutex_unlock(&st->lock);
return 0;
@@ -133,29 +125,32 @@ static int inv_mpu_probe(struct i2c_client *client,
return result;
st = iio_priv(dev_get_drvdata(&client->dev));
- st->muxc = i2c_mux_alloc(client->adapter, &client->dev,
- 1, 0, I2C_MUX_LOCKED | I2C_MUX_GATE,
- inv_mpu6050_select_bypass,
- inv_mpu6050_deselect_bypass);
- if (!st->muxc) {
- result = -ENOMEM;
- goto out_unreg_device;
+ switch (st->chip_type) {
+ case INV_ICM20608:
+ /* no i2c auxiliary bus on the chip */
+ break;
+ default:
+ /* declare i2c auxiliary bus */
+ st->muxc = i2c_mux_alloc(client->adapter, &client->dev,
+ 1, 0, I2C_MUX_LOCKED | I2C_MUX_GATE,
+ inv_mpu6050_select_bypass,
+ inv_mpu6050_deselect_bypass);
+ if (!st->muxc)
+ return -ENOMEM;
+ st->muxc->priv = dev_get_drvdata(&client->dev);
+ result = i2c_mux_add_adapter(st->muxc, 0, 0, 0);
+ if (result)
+ return result;
+ result = inv_mpu_acpi_create_mux_client(client);
+ if (result)
+ goto out_del_mux;
+ break;
}
- st->muxc->priv = dev_get_drvdata(&client->dev);
- result = i2c_mux_add_adapter(st->muxc, 0, 0, 0);
- if (result)
- goto out_unreg_device;
-
- result = inv_mpu_acpi_create_mux_client(client);
- if (result)
- goto out_del_mux;
return 0;
out_del_mux:
i2c_mux_del_adapters(st->muxc);
-out_unreg_device:
- inv_mpu_core_remove(&client->dev);
return result;
}
@@ -164,10 +159,12 @@ static int inv_mpu_remove(struct i2c_client *client)
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct inv_mpu6050_state *st = iio_priv(indio_dev);
- inv_mpu_acpi_delete_mux_client(client);
- i2c_mux_del_adapters(st->muxc);
+ if (st->muxc) {
+ inv_mpu_acpi_delete_mux_client(client);
+ i2c_mux_del_adapters(st->muxc);
+ }
- return inv_mpu_core_remove(&client->dev);
+ return 0;
}
/*
@@ -179,6 +176,7 @@ static const struct i2c_device_id inv_mpu_id[] = {
{"mpu6500", INV_MPU6500},
{"mpu9150", INV_MPU9150},
{"mpu9250", INV_MPU9250},
+ {"mpu9255", INV_MPU9255},
{"icm20608", INV_ICM20608},
{}
};
@@ -203,6 +201,10 @@ static const struct of_device_id inv_of_match[] = {
.data = (void *)INV_MPU9250
},
{
+ .compatible = "invensense,mpu9255",
+ .data = (void *)INV_MPU9255
+ },
+ {
.compatible = "invensense,icm20608",
.data = (void *)INV_ICM20608
},
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
index 065794162d65..c54da777945d 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
@@ -40,6 +40,7 @@
* @raw_accl: Address of first accel register.
* @temperature: temperature register
* @int_enable: Interrupt enable register.
+ * @int_status: Interrupt status register.
* @pwr_mgmt_1: Controls chip's power state and clock source.
* @pwr_mgmt_2: Controls power state of individual sensors.
* @int_pin_cfg; Controls interrupt pin configuration.
@@ -60,6 +61,7 @@ struct inv_mpu6050_reg_map {
u8 raw_accl;
u8 temperature;
u8 int_enable;
+ u8 int_status;
u8 pwr_mgmt_1;
u8 pwr_mgmt_2;
u8 int_pin_cfg;
@@ -74,6 +76,7 @@ enum inv_devices {
INV_MPU6000,
INV_MPU9150,
INV_MPU9250,
+ INV_MPU9255,
INV_ICM20608,
INV_NUM_PARTS
};
@@ -94,6 +97,7 @@ struct inv_mpu6050_chip_config {
unsigned int accl_fifo_enable:1;
unsigned int gyro_fifo_enable:1;
u16 fifo_rate;
+ u8 user_ctrl;
};
/**
@@ -125,6 +129,7 @@ struct inv_mpu6050_hw {
* @timestamps: kfifo queue to store time stamp.
* @map regmap pointer.
* @irq interrupt number.
+ * @irq_mask the int_pin_cfg mask to configure interrupt type.
*/
struct inv_mpu6050_state {
#define TIMESTAMP_FIFO_SIZE 16
@@ -143,6 +148,8 @@ struct inv_mpu6050_state {
DECLARE_KFIFO(timestamps, long long, TIMESTAMP_FIFO_SIZE);
struct regmap *map;
int irq;
+ u8 irq_mask;
+ unsigned skip_samples;
};
/*register and associated bit definition*/
@@ -166,6 +173,9 @@ struct inv_mpu6050_state {
#define INV_MPU6050_REG_TEMPERATURE 0x41
#define INV_MPU6050_REG_RAW_GYRO 0x43
+#define INV_MPU6050_REG_INT_STATUS 0x3A
+#define INV_MPU6050_BIT_RAW_DATA_RDY_INT 0x01
+
#define INV_MPU6050_REG_USER_CTRL 0x6A
#define INV_MPU6050_BIT_FIFO_RST 0x04
#define INV_MPU6050_BIT_DMP_RST 0x08
@@ -215,8 +225,12 @@ struct inv_mpu6050_state {
#define INV_MPU6050_OUTPUT_DATA_SIZE 24
#define INV_MPU6050_REG_INT_PIN_CFG 0x37
+#define INV_MPU6050_ACTIVE_HIGH 0x00
+#define INV_MPU6050_ACTIVE_LOW 0x80
+/* enable level triggering */
+#define INV_MPU6050_LATCH_INT_EN 0x20
#define INV_MPU6050_BIT_BYPASS_EN 0x2
-#define INV_MPU6050_INT_PIN_CFG 0
+
/* init parameters */
#define INV_MPU6050_INIT_FIFO_RATE 50
@@ -232,6 +246,7 @@ struct inv_mpu6050_state {
#define INV_MPU6500_WHOAMI_VALUE 0x70
#define INV_MPU9150_WHOAMI_VALUE 0x68
#define INV_MPU9250_WHOAMI_VALUE 0x71
+#define INV_MPU9255_WHOAMI_VALUE 0x73
#define INV_ICM20608_WHOAMI_VALUE 0xAF
/* scan element definition */
@@ -287,8 +302,7 @@ enum inv_mpu6050_clock_sel_e {
irqreturn_t inv_mpu6050_irq_handler(int irq, void *p);
irqreturn_t inv_mpu6050_read_fifo(int irq, void *p);
-int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev);
-void inv_mpu6050_remove_trigger(struct inv_mpu6050_state *st);
+int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev, int irq_type);
int inv_reset_fifo(struct iio_dev *indio_dev);
int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask);
int inv_mpu6050_write_reg(struct inv_mpu6050_state *st, int reg, u8 val);
@@ -297,6 +311,4 @@ int inv_mpu_acpi_create_mux_client(struct i2c_client *client);
void inv_mpu_acpi_delete_mux_client(struct i2c_client *client);
int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
int (*inv_mpu_bus_setup)(struct iio_dev *), int chip_type);
-int inv_mpu_core_remove(struct device *dev);
-int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on);
extern const struct dev_pm_ops inv_mpu_pmops;
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c
index ff81c6aa009d..97d965181635 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c
@@ -51,13 +51,14 @@ int inv_reset_fifo(struct iio_dev *indio_dev)
if (result)
goto reset_fifo_fail;
/* disable fifo reading */
- result = regmap_write(st->map, st->reg->user_ctrl, 0);
+ result = regmap_write(st->map, st->reg->user_ctrl,
+ st->chip_config.user_ctrl);
if (result)
goto reset_fifo_fail;
/* reset FIFO*/
- result = regmap_write(st->map, st->reg->user_ctrl,
- INV_MPU6050_BIT_FIFO_RST);
+ d = st->chip_config.user_ctrl | INV_MPU6050_BIT_FIFO_RST;
+ result = regmap_write(st->map, st->reg->user_ctrl, d);
if (result)
goto reset_fifo_fail;
@@ -72,9 +73,9 @@ int inv_reset_fifo(struct iio_dev *indio_dev)
if (result)
return result;
}
- /* enable FIFO reading and I2C master interface*/
- result = regmap_write(st->map, st->reg->user_ctrl,
- INV_MPU6050_BIT_FIFO_EN);
+ /* enable FIFO reading */
+ d = st->chip_config.user_ctrl | INV_MPU6050_BIT_FIFO_EN;
+ result = regmap_write(st->map, st->reg->user_ctrl, d);
if (result)
goto reset_fifo_fail;
/* enable sensor output to FIFO */
@@ -127,8 +128,23 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p)
u8 data[INV_MPU6050_OUTPUT_DATA_SIZE];
u16 fifo_count;
s64 timestamp;
+ int int_status;
mutex_lock(&st->lock);
+
+ /* ack interrupt and check status */
+ result = regmap_read(st->map, st->reg->int_status, &int_status);
+ if (result) {
+ dev_err(regmap_get_device(st->map),
+ "failed to ack interrupt\n");
+ goto flush_fifo;
+ }
+ if (!(int_status & INV_MPU6050_BIT_RAW_DATA_RDY_INT)) {
+ dev_warn(regmap_get_device(st->map),
+ "spurious interrupt with status 0x%x\n", int_status);
+ goto end_session;
+ }
+
if (!(st->chip_config.accl_fifo_enable |
st->chip_config.gyro_fifo_enable))
goto end_session;
@@ -140,7 +156,7 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p)
bytes_per_datum += INV_MPU6050_BYTES_PER_3AXIS_SENSOR;
/*
- * read fifo_count register to know how many bytes inside FIFO
+ * read fifo_count register to know how many bytes are inside the FIFO
* right now
*/
result = regmap_bulk_read(st->map, st->reg->fifo_count_h, data,
@@ -150,7 +166,7 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p)
fifo_count = be16_to_cpup((__be16 *)(&data[0]));
if (fifo_count < bytes_per_datum)
goto end_session;
- /* fifo count can't be odd number, if it is odd, reset fifo*/
+ /* fifo count can't be an odd number. If it is odd, reset the FIFO. */
if (fifo_count & 1)
goto flush_fifo;
if (fifo_count > INV_MPU6050_FIFO_THRESHOLD)
@@ -170,10 +186,13 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p)
if (result == 0)
timestamp = 0;
- result = iio_push_to_buffers_with_timestamp(indio_dev, data,
- timestamp);
- if (result)
- goto flush_fifo;
+ /* skip first samples if needed */
+ if (st->skip_samples)
+ st->skip_samples--;
+ else
+ iio_push_to_buffers_with_timestamp(indio_dev, data,
+ timestamp);
+
fifo_count -= bytes_per_datum;
}
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c
index 74506e5ac0db..227f50afff22 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c
@@ -31,8 +31,9 @@ static int inv_mpu_i2c_disable(struct iio_dev *indio_dev)
if (ret)
return ret;
- ret = regmap_write(st->map, INV_MPU6050_REG_USER_CTRL,
- INV_MPU6050_BIT_I2C_IF_DIS);
+ st->chip_config.user_ctrl |= INV_MPU6050_BIT_I2C_IF_DIS;
+ ret = regmap_write(st->map, st->reg->user_ctrl,
+ st->chip_config.user_ctrl);
if (ret) {
inv_mpu6050_set_power_itg(st, false);
return ret;
@@ -69,11 +70,6 @@ static int inv_mpu_probe(struct spi_device *spi)
inv_mpu_i2c_disable, chip_type);
}
-static int inv_mpu_remove(struct spi_device *spi)
-{
- return inv_mpu_core_remove(&spi->dev);
-}
-
/*
* device id table is used to identify what device can be
* supported by this driver
@@ -83,6 +79,7 @@ static const struct spi_device_id inv_mpu_id[] = {
{"mpu6500", INV_MPU6500},
{"mpu9150", INV_MPU9150},
{"mpu9250", INV_MPU9250},
+ {"mpu9255", INV_MPU9255},
{"icm20608", INV_ICM20608},
{}
};
@@ -97,7 +94,6 @@ MODULE_DEVICE_TABLE(acpi, inv_acpi_match);
static struct spi_driver inv_mpu_driver = {
.probe = inv_mpu_probe,
- .remove = inv_mpu_remove,
.id_table = inv_mpu_id,
.driver = {
.acpi_match_table = ACPI_PTR(inv_acpi_match),
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c
index f963f9fc98c0..6c3e1652a687 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c
@@ -49,49 +49,66 @@ static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable)
if (result)
return result;
inv_scan_query(indio_dev);
+ st->skip_samples = 0;
if (st->chip_config.gyro_fifo_enable) {
result = inv_mpu6050_switch_engine(st, true,
INV_MPU6050_BIT_PWR_GYRO_STBY);
if (result)
- return result;
+ goto error_power_off;
+ /* gyro first sample is out of specs, skip it */
+ st->skip_samples = 1;
}
if (st->chip_config.accl_fifo_enable) {
result = inv_mpu6050_switch_engine(st, true,
INV_MPU6050_BIT_PWR_ACCL_STBY);
if (result)
- return result;
+ goto error_gyro_off;
}
result = inv_reset_fifo(indio_dev);
if (result)
- return result;
+ goto error_accl_off;
} else {
result = regmap_write(st->map, st->reg->fifo_en, 0);
if (result)
- return result;
+ goto error_accl_off;
result = regmap_write(st->map, st->reg->int_enable, 0);
if (result)
- return result;
+ goto error_accl_off;
- result = regmap_write(st->map, st->reg->user_ctrl, 0);
+ result = regmap_write(st->map, st->reg->user_ctrl,
+ st->chip_config.user_ctrl);
if (result)
- return result;
+ goto error_accl_off;
result = inv_mpu6050_switch_engine(st, false,
- INV_MPU6050_BIT_PWR_GYRO_STBY);
+ INV_MPU6050_BIT_PWR_ACCL_STBY);
if (result)
- return result;
+ goto error_accl_off;
result = inv_mpu6050_switch_engine(st, false,
- INV_MPU6050_BIT_PWR_ACCL_STBY);
+ INV_MPU6050_BIT_PWR_GYRO_STBY);
if (result)
- return result;
+ goto error_gyro_off;
+
result = inv_mpu6050_set_power_itg(st, false);
if (result)
- return result;
+ goto error_power_off;
}
return 0;
+
+error_accl_off:
+ if (st->chip_config.accl_fifo_enable)
+ inv_mpu6050_switch_engine(st, false,
+ INV_MPU6050_BIT_PWR_ACCL_STBY);
+error_gyro_off:
+ if (st->chip_config.gyro_fifo_enable)
+ inv_mpu6050_switch_engine(st, false,
+ INV_MPU6050_BIT_PWR_GYRO_STBY);
+error_power_off:
+ inv_mpu6050_set_power_itg(st, false);
+ return result;
}
/**
@@ -117,7 +134,7 @@ static const struct iio_trigger_ops inv_mpu_trigger_ops = {
.set_trigger_state = &inv_mpu_data_rdy_trigger_set_state,
};
-int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev)
+int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev, int irq_type)
{
int ret;
struct inv_mpu6050_state *st = iio_priv(indio_dev);
@@ -131,7 +148,7 @@ int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev)
ret = devm_request_irq(&indio_dev->dev, st->irq,
&iio_trigger_generic_data_rdy_poll,
- IRQF_TRIGGER_RISING,
+ irq_type,
"inv_mpu",
st->trig);
if (ret)
@@ -141,7 +158,7 @@ int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev)
st->trig->ops = &inv_mpu_trigger_ops;
iio_trigger_set_drvdata(st->trig, indio_dev);
- ret = iio_trigger_register(st->trig);
+ ret = devm_iio_trigger_register(&indio_dev->dev, st->trig);
if (ret)
return ret;
@@ -149,8 +166,3 @@ int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev)
return 0;
}
-
-void inv_mpu6050_remove_trigger(struct inv_mpu6050_state *st)
-{
- iio_trigger_unregister(st->trig);
-}
diff --git a/drivers/iio/imu/st_lsm6dsx/Kconfig b/drivers/iio/imu/st_lsm6dsx/Kconfig
index 14f2eb6e9fb7..ccc817e17eb8 100644
--- a/drivers/iio/imu/st_lsm6dsx/Kconfig
+++ b/drivers/iio/imu/st_lsm6dsx/Kconfig
@@ -8,7 +8,8 @@ config IIO_ST_LSM6DSX
select IIO_ST_LSM6DSX_SPI if (SPI_MASTER)
help
Say yes here to build support for STMicroelectronics LSM6DSx imu
- sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm
+ sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm,
+ ism330dlc
To compile this driver as a module, choose M here: the module
will be called st_lsm6dsx.
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
index a3cc7cd97026..edcd838037cd 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
@@ -18,12 +18,14 @@
#define ST_LSM6DS3H_DEV_NAME "lsm6ds3h"
#define ST_LSM6DSL_DEV_NAME "lsm6dsl"
#define ST_LSM6DSM_DEV_NAME "lsm6dsm"
+#define ST_ISM330DLC_DEV_NAME "ism330dlc"
enum st_lsm6dsx_hw_id {
ST_LSM6DS3_ID,
ST_LSM6DS3H_ID,
ST_LSM6DSL_ID,
ST_LSM6DSM_ID,
+ ST_ISM330DLC_ID,
ST_LSM6DSX_MAX_ID,
};
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
index 1045e025e92b..4994f920a836 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
@@ -1,10 +1,10 @@
/*
* STMicroelectronics st_lsm6dsx FIFO buffer library driver
*
- * LSM6DS3/LSM6DS3H/LSM6DSL/LSM6DSM: The FIFO buffer can be configured
- * to store data from gyroscope and accelerometer. Samples are queued
- * without any tag according to a specific pattern based on 'FIFO data sets'
- * (6 bytes each):
+ * LSM6DS3/LSM6DS3H/LSM6DSL/LSM6DSM/ISM330DLC: The FIFO buffer can be
+ * configured to store data from gyroscope and accelerometer. Samples are
+ * queued without any tag according to a specific pattern based on
+ * 'FIFO data sets' (6 bytes each):
* - 1st data set is reserved for gyroscope data
* - 2nd data set is reserved for accelerometer data
* The FIFO pattern changes depending on the ODRs and decimation factors
@@ -276,7 +276,7 @@ static inline int st_lsm6dsx_read_block(struct st_lsm6dsx_hw *hw, u8 *data,
#define ST_LSM6DSX_IIO_BUFF_SIZE (ALIGN(ST_LSM6DSX_SAMPLE_SIZE, \
sizeof(s64)) + sizeof(s64))
/**
- * st_lsm6dsx_read_fifo() - LSM6DS3-LSM6DS3H-LSM6DSL-LSM6DSM read FIFO routine
+ * st_lsm6dsx_read_fifo() - hw FIFO read routine
* @hw: Pointer to instance of struct st_lsm6dsx_hw.
*
* Read samples from the hw FIFO and push them to IIO buffers.
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
index 8656d72ef4ee..aebbe0ddd8d8 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
@@ -17,7 +17,7 @@
* - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
* - FIFO size: 8KB
*
- * - LSM6DS3H/LSM6DSL/LSM6DSM:
+ * - LSM6DS3H/LSM6DSL/LSM6DSM/ISM330DLC:
* - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416
* - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
* - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
@@ -252,6 +252,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.id = {
[0] = ST_LSM6DSL_ID,
[1] = ST_LSM6DSM_ID,
+ [2] = ST_ISM330DLC_ID,
},
.decimator = {
[ST_LSM6DSX_ID_ACC] = {
@@ -266,11 +267,11 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.fifo_ops = {
.fifo_th = {
.addr = 0x06,
- .mask = GENMASK(11, 0),
+ .mask = GENMASK(10, 0),
},
.fifo_diff = {
.addr = 0x3a,
- .mask = GENMASK(11, 0),
+ .mask = GENMASK(10, 0),
},
.th_wl = 3, /* 1LSB = 2B */
},
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c
index 41525dd2aab7..377c4e9997da 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c
@@ -57,6 +57,10 @@ static const struct of_device_id st_lsm6dsx_i2c_of_match[] = {
.compatible = "st,lsm6dsm",
.data = (void *)ST_LSM6DSM_ID,
},
+ {
+ .compatible = "st,ism330dlc",
+ .data = (void *)ST_ISM330DLC_ID,
+ },
{},
};
MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match);
@@ -66,6 +70,7 @@ static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = {
{ ST_LSM6DS3H_DEV_NAME, ST_LSM6DS3H_ID },
{ ST_LSM6DSL_DEV_NAME, ST_LSM6DSL_ID },
{ ST_LSM6DSM_DEV_NAME, ST_LSM6DSM_ID },
+ { ST_ISM330DLC_DEV_NAME, ST_ISM330DLC_ID },
{},
};
MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table);
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
index 2c8135834479..fec5c6ce7eb7 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
@@ -57,6 +57,10 @@ static const struct of_device_id st_lsm6dsx_spi_of_match[] = {
.compatible = "st,lsm6dsm",
.data = (void *)ST_LSM6DSM_ID,
},
+ {
+ .compatible = "st,ism330dlc",
+ .data = (void *)ST_ISM330DLC_ID,
+ },
{},
};
MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match);
@@ -66,6 +70,7 @@ static const struct spi_device_id st_lsm6dsx_spi_id_table[] = {
{ ST_LSM6DS3H_DEV_NAME, ST_LSM6DS3H_ID },
{ ST_LSM6DSL_DEV_NAME, ST_LSM6DSL_ID },
{ ST_LSM6DSM_DEV_NAME, ST_LSM6DSM_ID },
+ { ST_ISM330DLC_DEV_NAME, ST_ISM330DLC_ID },
{},
};
MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table);
diff --git a/drivers/iio/light/cros_ec_light_prox.c b/drivers/iio/light/cros_ec_light_prox.c
index 8e8a0e7f78d1..fd1609e975ab 100644
--- a/drivers/iio/light/cros_ec_light_prox.c
+++ b/drivers/iio/light/cros_ec_light_prox.c
@@ -16,6 +16,7 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/iio/buffer.h>
+#include <linux/iio/common/cros_ec_sensors_core.h>
#include <linux/iio/iio.h>
#include <linux/iio/kfifo_buf.h>
#include <linux/iio/trigger.h>
@@ -29,8 +30,6 @@
#include <linux/slab.h>
#include <linux/sysfs.h>
-#include "../common/cros_ec_sensors/cros_ec_sensors_core.h"
-
/*
* We only represent one entry for light or proximity. EC is merging different
* light sensors to return the what the eye would see. For proximity, we
diff --git a/drivers/iio/potentiometer/mcp4018.c b/drivers/iio/potentiometer/mcp4018.c
index 601b25d1f387..320a7c929777 100644
--- a/drivers/iio/potentiometer/mcp4018.c
+++ b/drivers/iio/potentiometer/mcp4018.c
@@ -99,6 +99,23 @@ static const struct iio_info mcp4018_info = {
.write_raw = mcp4018_write_raw,
};
+static const struct i2c_device_id mcp4018_id[] = {
+ { "mcp4017-502", MCP4018_502 },
+ { "mcp4017-103", MCP4018_103 },
+ { "mcp4017-503", MCP4018_503 },
+ { "mcp4017-104", MCP4018_104 },
+ { "mcp4018-502", MCP4018_502 },
+ { "mcp4018-103", MCP4018_103 },
+ { "mcp4018-503", MCP4018_503 },
+ { "mcp4018-104", MCP4018_104 },
+ { "mcp4019-502", MCP4018_502 },
+ { "mcp4019-103", MCP4018_103 },
+ { "mcp4019-503", MCP4018_503 },
+ { "mcp4019-104", MCP4018_104 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, mcp4018_id);
+
#ifdef CONFIG_OF
#define MCP4018_COMPATIBLE(of_compatible, cfg) { \
@@ -125,8 +142,7 @@ MODULE_DEVICE_TABLE(of, mcp4018_of_match);
#endif
-static int mcp4018_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int mcp4018_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct mcp4018_data *data;
@@ -150,7 +166,7 @@ static int mcp4018_probe(struct i2c_client *client,
if (match)
data->cfg = of_device_get_match_data(dev);
else
- data->cfg = &mcp4018_cfg[id->driver_data];
+ data->cfg = &mcp4018_cfg[i2c_match_id(mcp4018_id, client)->driver_data];
indio_dev->dev.parent = dev;
indio_dev->info = &mcp4018_info;
@@ -161,29 +177,12 @@ static int mcp4018_probe(struct i2c_client *client,
return devm_iio_device_register(dev, indio_dev);
}
-static const struct i2c_device_id mcp4018_id[] = {
- { "mcp4017-502", MCP4018_502 },
- { "mcp4017-103", MCP4018_103 },
- { "mcp4017-503", MCP4018_503 },
- { "mcp4017-104", MCP4018_104 },
- { "mcp4018-502", MCP4018_502 },
- { "mcp4018-103", MCP4018_103 },
- { "mcp4018-503", MCP4018_503 },
- { "mcp4018-104", MCP4018_104 },
- { "mcp4019-502", MCP4018_502 },
- { "mcp4019-103", MCP4018_103 },
- { "mcp4019-503", MCP4018_503 },
- { "mcp4019-104", MCP4018_104 },
- {}
-};
-MODULE_DEVICE_TABLE(i2c, mcp4018_id);
-
static struct i2c_driver mcp4018_driver = {
.driver = {
.name = "mcp4018",
.of_match_table = of_match_ptr(mcp4018_of_match),
},
- .probe = mcp4018_probe,
+ .probe_new = mcp4018_probe,
.id_table = mcp4018_id,
};
diff --git a/drivers/iio/potentiometer/mcp4531.c b/drivers/iio/potentiometer/mcp4531.c
index 114ab876fcc6..df894af6cccb 100644
--- a/drivers/iio/potentiometer/mcp4531.c
+++ b/drivers/iio/potentiometer/mcp4531.c
@@ -209,6 +209,75 @@ static const struct iio_info mcp4531_info = {
.write_raw = mcp4531_write_raw,
};
+static const struct i2c_device_id mcp4531_id[] = {
+ { "mcp4531-502", MCP453x_502 },
+ { "mcp4531-103", MCP453x_103 },
+ { "mcp4531-503", MCP453x_503 },
+ { "mcp4531-104", MCP453x_104 },
+ { "mcp4532-502", MCP453x_502 },
+ { "mcp4532-103", MCP453x_103 },
+ { "mcp4532-503", MCP453x_503 },
+ { "mcp4532-104", MCP453x_104 },
+ { "mcp4541-502", MCP454x_502 },
+ { "mcp4541-103", MCP454x_103 },
+ { "mcp4541-503", MCP454x_503 },
+ { "mcp4541-104", MCP454x_104 },
+ { "mcp4542-502", MCP454x_502 },
+ { "mcp4542-103", MCP454x_103 },
+ { "mcp4542-503", MCP454x_503 },
+ { "mcp4542-104", MCP454x_104 },
+ { "mcp4551-502", MCP455x_502 },
+ { "mcp4551-103", MCP455x_103 },
+ { "mcp4551-503", MCP455x_503 },
+ { "mcp4551-104", MCP455x_104 },
+ { "mcp4552-502", MCP455x_502 },
+ { "mcp4552-103", MCP455x_103 },
+ { "mcp4552-503", MCP455x_503 },
+ { "mcp4552-104", MCP455x_104 },
+ { "mcp4561-502", MCP456x_502 },
+ { "mcp4561-103", MCP456x_103 },
+ { "mcp4561-503", MCP456x_503 },
+ { "mcp4561-104", MCP456x_104 },
+ { "mcp4562-502", MCP456x_502 },
+ { "mcp4562-103", MCP456x_103 },
+ { "mcp4562-503", MCP456x_503 },
+ { "mcp4562-104", MCP456x_104 },
+ { "mcp4631-502", MCP463x_502 },
+ { "mcp4631-103", MCP463x_103 },
+ { "mcp4631-503", MCP463x_503 },
+ { "mcp4631-104", MCP463x_104 },
+ { "mcp4632-502", MCP463x_502 },
+ { "mcp4632-103", MCP463x_103 },
+ { "mcp4632-503", MCP463x_503 },
+ { "mcp4632-104", MCP463x_104 },
+ { "mcp4641-502", MCP464x_502 },
+ { "mcp4641-103", MCP464x_103 },
+ { "mcp4641-503", MCP464x_503 },
+ { "mcp4641-104", MCP464x_104 },
+ { "mcp4642-502", MCP464x_502 },
+ { "mcp4642-103", MCP464x_103 },
+ { "mcp4642-503", MCP464x_503 },
+ { "mcp4642-104", MCP464x_104 },
+ { "mcp4651-502", MCP465x_502 },
+ { "mcp4651-103", MCP465x_103 },
+ { "mcp4651-503", MCP465x_503 },
+ { "mcp4651-104", MCP465x_104 },
+ { "mcp4652-502", MCP465x_502 },
+ { "mcp4652-103", MCP465x_103 },
+ { "mcp4652-503", MCP465x_503 },
+ { "mcp4652-104", MCP465x_104 },
+ { "mcp4661-502", MCP466x_502 },
+ { "mcp4661-103", MCP466x_103 },
+ { "mcp4661-503", MCP466x_503 },
+ { "mcp4661-104", MCP466x_104 },
+ { "mcp4662-502", MCP466x_502 },
+ { "mcp4662-103", MCP466x_103 },
+ { "mcp4662-503", MCP466x_503 },
+ { "mcp4662-104", MCP466x_104 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, mcp4531_id);
+
#ifdef CONFIG_OF
#define MCP4531_COMPATIBLE(of_compatible, cfg) { \
@@ -286,8 +355,7 @@ static const struct of_device_id mcp4531_of_match[] = {
MODULE_DEVICE_TABLE(of, mcp4531_of_match);
#endif
-static int mcp4531_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int mcp4531_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct mcp4531_data *data;
@@ -311,7 +379,7 @@ static int mcp4531_probe(struct i2c_client *client,
if (match)
data->cfg = of_device_get_match_data(dev);
else
- data->cfg = &mcp4531_cfg[id->driver_data];
+ data->cfg = &mcp4531_cfg[i2c_match_id(mcp4531_id, client)->driver_data];
indio_dev->dev.parent = dev;
indio_dev->info = &mcp4531_info;
@@ -322,81 +390,12 @@ static int mcp4531_probe(struct i2c_client *client,
return devm_iio_device_register(dev, indio_dev);
}
-static const struct i2c_device_id mcp4531_id[] = {
- { "mcp4531-502", MCP453x_502 },
- { "mcp4531-103", MCP453x_103 },
- { "mcp4531-503", MCP453x_503 },
- { "mcp4531-104", MCP453x_104 },
- { "mcp4532-502", MCP453x_502 },
- { "mcp4532-103", MCP453x_103 },
- { "mcp4532-503", MCP453x_503 },
- { "mcp4532-104", MCP453x_104 },
- { "mcp4541-502", MCP454x_502 },
- { "mcp4541-103", MCP454x_103 },
- { "mcp4541-503", MCP454x_503 },
- { "mcp4541-104", MCP454x_104 },
- { "mcp4542-502", MCP454x_502 },
- { "mcp4542-103", MCP454x_103 },
- { "mcp4542-503", MCP454x_503 },
- { "mcp4542-104", MCP454x_104 },
- { "mcp4551-502", MCP455x_502 },
- { "mcp4551-103", MCP455x_103 },
- { "mcp4551-503", MCP455x_503 },
- { "mcp4551-104", MCP455x_104 },
- { "mcp4552-502", MCP455x_502 },
- { "mcp4552-103", MCP455x_103 },
- { "mcp4552-503", MCP455x_503 },
- { "mcp4552-104", MCP455x_104 },
- { "mcp4561-502", MCP456x_502 },
- { "mcp4561-103", MCP456x_103 },
- { "mcp4561-503", MCP456x_503 },
- { "mcp4561-104", MCP456x_104 },
- { "mcp4562-502", MCP456x_502 },
- { "mcp4562-103", MCP456x_103 },
- { "mcp4562-503", MCP456x_503 },
- { "mcp4562-104", MCP456x_104 },
- { "mcp4631-502", MCP463x_502 },
- { "mcp4631-103", MCP463x_103 },
- { "mcp4631-503", MCP463x_503 },
- { "mcp4631-104", MCP463x_104 },
- { "mcp4632-502", MCP463x_502 },
- { "mcp4632-103", MCP463x_103 },
- { "mcp4632-503", MCP463x_503 },
- { "mcp4632-104", MCP463x_104 },
- { "mcp4641-502", MCP464x_502 },
- { "mcp4641-103", MCP464x_103 },
- { "mcp4641-503", MCP464x_503 },
- { "mcp4641-104", MCP464x_104 },
- { "mcp4642-502", MCP464x_502 },
- { "mcp4642-103", MCP464x_103 },
- { "mcp4642-503", MCP464x_503 },
- { "mcp4642-104", MCP464x_104 },
- { "mcp4651-502", MCP465x_502 },
- { "mcp4651-103", MCP465x_103 },
- { "mcp4651-503", MCP465x_503 },
- { "mcp4651-104", MCP465x_104 },
- { "mcp4652-502", MCP465x_502 },
- { "mcp4652-103", MCP465x_103 },
- { "mcp4652-503", MCP465x_503 },
- { "mcp4652-104", MCP465x_104 },
- { "mcp4661-502", MCP466x_502 },
- { "mcp4661-103", MCP466x_103 },
- { "mcp4661-503", MCP466x_503 },
- { "mcp4661-104", MCP466x_104 },
- { "mcp4662-502", MCP466x_502 },
- { "mcp4662-103", MCP466x_103 },
- { "mcp4662-503", MCP466x_503 },
- { "mcp4662-104", MCP466x_104 },
- {}
-};
-MODULE_DEVICE_TABLE(i2c, mcp4531_id);
-
static struct i2c_driver mcp4531_driver = {
.driver = {
.name = "mcp4531",
.of_match_table = of_match_ptr(mcp4531_of_match),
},
- .probe = mcp4531_probe,
+ .probe_new = mcp4531_probe,
.id_table = mcp4531_id,
};
diff --git a/drivers/iio/pressure/cros_ec_baro.c b/drivers/iio/pressure/cros_ec_baro.c
index 4599fde4dd25..87c07af9181f 100644
--- a/drivers/iio/pressure/cros_ec_baro.c
+++ b/drivers/iio/pressure/cros_ec_baro.c
@@ -16,6 +16,7 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/iio/buffer.h>
+#include <linux/iio/common/cros_ec_sensors_core.h>
#include <linux/iio/iio.h>
#include <linux/iio/kfifo_buf.h>
#include <linux/iio/trigger.h>
@@ -28,8 +29,6 @@
#include <linux/slab.h>
#include <linux/platform_device.h>
-#include "../common/cros_ec_sensors/cros_ec_sensors_core.h"
-
/*
* One channel for pressure, the other for timestamp.
*/
diff --git a/drivers/staging/iio/accel/Kconfig b/drivers/staging/iio/accel/Kconfig
index c6b0f5eae7ab..befbbfe911c2 100644
--- a/drivers/staging/iio/accel/Kconfig
+++ b/drivers/staging/iio/accel/Kconfig
@@ -3,18 +3,6 @@
#
menu "Accelerometers"
-config ADIS16201
- tristate "Analog Devices ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer"
- depends on SPI
- select IIO_ADIS_LIB
- select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
- help
- Say Y here to build support for Analog Devices adis16201 dual-axis
- digital inclinometer and accelerometer.
-
- To compile this driver as a module, say M here: the module will
- be called adis16201.
-
config ADIS16203
tristate "Analog Devices ADIS16203 Programmable 360 Degrees Inclinometer"
depends on SPI
@@ -27,18 +15,6 @@ config ADIS16203
To compile this driver as a module, say M here: the module will be
called adis16203.
-config ADIS16209
- tristate "Analog Devices ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer"
- depends on SPI
- select IIO_ADIS_LIB
- select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
- help
- Say Y here to build support for Analog Devices adis16209 dual-axis digital inclinometer
- and accelerometer.
-
- To compile this driver as a module, say M here: the module will be
- called adis16209.
-
config ADIS16240
tristate "Analog Devices ADIS16240 Programmable Impact Sensor and Recorder"
depends on SPI
diff --git a/drivers/staging/iio/accel/Makefile b/drivers/staging/iio/accel/Makefile
index 5d8ad21a0dae..773212e0c859 100644
--- a/drivers/staging/iio/accel/Makefile
+++ b/drivers/staging/iio/accel/Makefile
@@ -2,7 +2,5 @@
# Makefile for industrial I/O accelerometer drivers
#
-obj-$(CONFIG_ADIS16201) += adis16201.o
obj-$(CONFIG_ADIS16203) += adis16203.o
-obj-$(CONFIG_ADIS16209) += adis16209.o
obj-$(CONFIG_ADIS16240) += adis16240.o
diff --git a/drivers/staging/iio/accel/adis16201.c b/drivers/staging/iio/accel/adis16201.c
deleted file mode 100644
index 0fae8aaf1cf4..000000000000
--- a/drivers/staging/iio/accel/adis16201.c
+++ /dev/null
@@ -1,385 +0,0 @@
-/*
- * ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer
- *
- * Copyright 2010 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
- */
-
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-#include <linux/spi/spi.h>
-#include <linux/sysfs.h>
-
-#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
-#include <linux/iio/buffer.h>
-#include <linux/iio/imu/adis.h>
-
-#define ADIS16201_STARTUP_DELAY 220 /* ms */
-
-/* Flash memory write count */
-#define ADIS16201_FLASH_CNT 0x00
-
-/* Output, power supply */
-#define ADIS16201_SUPPLY_OUT 0x02
-
-/* Output, x-axis accelerometer */
-#define ADIS16201_XACCL_OUT 0x04
-
-/* Output, y-axis accelerometer */
-#define ADIS16201_YACCL_OUT 0x06
-
-/* Output, auxiliary ADC input */
-#define ADIS16201_AUX_ADC 0x08
-
-/* Output, temperature */
-#define ADIS16201_TEMP_OUT 0x0A
-
-/* Output, x-axis inclination */
-#define ADIS16201_XINCL_OUT 0x0C
-
-/* Output, y-axis inclination */
-#define ADIS16201_YINCL_OUT 0x0E
-
-/* Calibration, x-axis acceleration offset */
-#define ADIS16201_XACCL_OFFS 0x10
-
-/* Calibration, y-axis acceleration offset */
-#define ADIS16201_YACCL_OFFS 0x12
-
-/* x-axis acceleration scale factor */
-#define ADIS16201_XACCL_SCALE 0x14
-
-/* y-axis acceleration scale factor */
-#define ADIS16201_YACCL_SCALE 0x16
-
-/* Calibration, x-axis inclination offset */
-#define ADIS16201_XINCL_OFFS 0x18
-
-/* Calibration, y-axis inclination offset */
-#define ADIS16201_YINCL_OFFS 0x1A
-
-/* x-axis inclination scale factor */
-#define ADIS16201_XINCL_SCALE 0x1C
-
-/* y-axis inclination scale factor */
-#define ADIS16201_YINCL_SCALE 0x1E
-
-/* Alarm 1 amplitude threshold */
-#define ADIS16201_ALM_MAG1 0x20
-
-/* Alarm 2 amplitude threshold */
-#define ADIS16201_ALM_MAG2 0x22
-
-/* Alarm 1, sample period */
-#define ADIS16201_ALM_SMPL1 0x24
-
-/* Alarm 2, sample period */
-#define ADIS16201_ALM_SMPL2 0x26
-
-/* Alarm control */
-#define ADIS16201_ALM_CTRL 0x28
-
-/* Auxiliary DAC data */
-#define ADIS16201_AUX_DAC 0x30
-
-/* General-purpose digital input/output control */
-#define ADIS16201_GPIO_CTRL 0x32
-
-/* Miscellaneous control */
-#define ADIS16201_MSC_CTRL 0x34
-
-/* Internal sample period (rate) control */
-#define ADIS16201_SMPL_PRD 0x36
-
-/* Operation, filter configuration */
-#define ADIS16201_AVG_CNT 0x38
-
-/* Operation, sleep mode control */
-#define ADIS16201_SLP_CNT 0x3A
-
-/* Diagnostics, system status register */
-#define ADIS16201_DIAG_STAT 0x3C
-
-/* Operation, system command register */
-#define ADIS16201_GLOB_CMD 0x3E
-
-/* MSC_CTRL */
-
-/* Self-test enable */
-#define ADIS16201_MSC_CTRL_SELF_TEST_EN BIT(8)
-
-/* Data-ready enable: 1 = enabled, 0 = disabled */
-#define ADIS16201_MSC_CTRL_DATA_RDY_EN BIT(2)
-
-/* Data-ready polarity: 1 = active high, 0 = active low */
-#define ADIS16201_MSC_CTRL_ACTIVE_HIGH BIT(1)
-
-/* Data-ready line selection: 1 = DIO1, 0 = DIO0 */
-#define ADIS16201_MSC_CTRL_DATA_RDY_DIO1 BIT(0)
-
-/* DIAG_STAT */
-
-/* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */
-#define ADIS16201_DIAG_STAT_ALARM2 BIT(9)
-
-/* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */
-#define ADIS16201_DIAG_STAT_ALARM1 BIT(8)
-
-/* SPI communications failure */
-#define ADIS16201_DIAG_STAT_SPI_FAIL_BIT 3
-
-/* Flash update failure */
-#define ADIS16201_DIAG_STAT_FLASH_UPT_BIT 2
-
-/* Power supply above 3.625 V */
-#define ADIS16201_DIAG_STAT_POWER_HIGH_BIT 1
-
-/* Power supply below 3.15 V */
-#define ADIS16201_DIAG_STAT_POWER_LOW_BIT 0
-
-/* GLOB_CMD */
-
-#define ADIS16201_GLOB_CMD_SW_RESET BIT(7)
-#define ADIS16201_GLOB_CMD_FACTORY_CAL BIT(1)
-
-#define ADIS16201_ERROR_ACTIVE BIT(14)
-
-enum adis16201_scan {
- ADIS16201_SCAN_ACC_X,
- ADIS16201_SCAN_ACC_Y,
- ADIS16201_SCAN_INCLI_X,
- ADIS16201_SCAN_INCLI_Y,
- ADIS16201_SCAN_SUPPLY,
- ADIS16201_SCAN_AUX_ADC,
- ADIS16201_SCAN_TEMP,
-};
-
-static const u8 adis16201_addresses[] = {
- [ADIS16201_SCAN_ACC_X] = ADIS16201_XACCL_OFFS,
- [ADIS16201_SCAN_ACC_Y] = ADIS16201_YACCL_OFFS,
- [ADIS16201_SCAN_INCLI_X] = ADIS16201_XINCL_OFFS,
- [ADIS16201_SCAN_INCLI_Y] = ADIS16201_YINCL_OFFS,
-};
-
-static int adis16201_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int *val, int *val2,
- long mask)
-{
- struct adis *st = iio_priv(indio_dev);
- int ret;
- int bits;
- u8 addr;
- s16 val16;
-
- switch (mask) {
- case IIO_CHAN_INFO_RAW:
- return adis_single_conversion(indio_dev, chan,
- ADIS16201_ERROR_ACTIVE, val);
- case IIO_CHAN_INFO_SCALE:
- switch (chan->type) {
- case IIO_VOLTAGE:
- if (chan->channel == 0) {
- *val = 1;
- *val2 = 220000; /* 1.22 mV */
- } else {
- *val = 0;
- *val2 = 610000; /* 0.610 mV */
- }
- return IIO_VAL_INT_PLUS_MICRO;
- case IIO_TEMP:
- *val = -470; /* 0.47 C */
- *val2 = 0;
- return IIO_VAL_INT_PLUS_MICRO;
- case IIO_ACCEL:
- *val = 0;
- *val2 = IIO_G_TO_M_S_2(462400); /* 0.4624 mg */
- return IIO_VAL_INT_PLUS_NANO;
- case IIO_INCLI:
- *val = 0;
- *val2 = 100000; /* 0.1 degree */
- return IIO_VAL_INT_PLUS_MICRO;
- default:
- return -EINVAL;
- }
- break;
- case IIO_CHAN_INFO_OFFSET:
- *val = 25000 / -470 - 1278; /* 25 C = 1278 */
- return IIO_VAL_INT;
- case IIO_CHAN_INFO_CALIBBIAS:
- switch (chan->type) {
- case IIO_ACCEL:
- bits = 12;
- break;
- case IIO_INCLI:
- bits = 9;
- break;
- default:
- return -EINVAL;
- }
- addr = adis16201_addresses[chan->scan_index];
- ret = adis_read_reg_16(st, addr, &val16);
- if (ret)
- return ret;
- val16 &= (1 << bits) - 1;
- val16 = (s16)(val16 << (16 - bits)) >> (16 - bits);
- *val = val16;
- return IIO_VAL_INT;
- }
-
- return -EINVAL;
-}
-
-static int adis16201_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int val,
- int val2,
- long mask)
-{
- struct adis *st = iio_priv(indio_dev);
- int bits;
- s16 val16;
- u8 addr;
-
- switch (mask) {
- case IIO_CHAN_INFO_CALIBBIAS:
- switch (chan->type) {
- case IIO_ACCEL:
- bits = 12;
- break;
- case IIO_INCLI:
- bits = 9;
- break;
- default:
- return -EINVAL;
- }
- val16 = val & ((1 << bits) - 1);
- addr = adis16201_addresses[chan->scan_index];
- return adis_write_reg_16(st, addr, val16);
- }
-
- return -EINVAL;
-}
-
-static const struct iio_chan_spec adis16201_channels[] = {
- ADIS_SUPPLY_CHAN(ADIS16201_SUPPLY_OUT, ADIS16201_SCAN_SUPPLY, 0, 12),
- ADIS_TEMP_CHAN(ADIS16201_TEMP_OUT, ADIS16201_SCAN_TEMP, 0, 12),
- ADIS_ACCEL_CHAN(X, ADIS16201_XACCL_OUT, ADIS16201_SCAN_ACC_X,
- BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14),
- ADIS_ACCEL_CHAN(Y, ADIS16201_YACCL_OUT, ADIS16201_SCAN_ACC_Y,
- BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14),
- ADIS_AUX_ADC_CHAN(ADIS16201_AUX_ADC, ADIS16201_SCAN_AUX_ADC, 0, 12),
- ADIS_INCLI_CHAN(X, ADIS16201_XINCL_OUT, ADIS16201_SCAN_INCLI_X,
- BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14),
- ADIS_INCLI_CHAN(X, ADIS16201_YINCL_OUT, ADIS16201_SCAN_INCLI_Y,
- BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14),
- IIO_CHAN_SOFT_TIMESTAMP(7)
-};
-
-static const struct iio_info adis16201_info = {
- .read_raw = adis16201_read_raw,
- .write_raw = adis16201_write_raw,
- .update_scan_mode = adis_update_scan_mode,
-};
-
-static const char * const adis16201_status_error_msgs[] = {
- [ADIS16201_DIAG_STAT_SPI_FAIL_BIT] = "SPI failure",
- [ADIS16201_DIAG_STAT_FLASH_UPT_BIT] = "Flash update failed",
- [ADIS16201_DIAG_STAT_POWER_HIGH_BIT] = "Power supply above 3.625V",
- [ADIS16201_DIAG_STAT_POWER_LOW_BIT] = "Power supply below 3.15V",
-};
-
-static const struct adis_data adis16201_data = {
- .read_delay = 20,
- .msc_ctrl_reg = ADIS16201_MSC_CTRL,
- .glob_cmd_reg = ADIS16201_GLOB_CMD,
- .diag_stat_reg = ADIS16201_DIAG_STAT,
-
- .self_test_mask = ADIS16201_MSC_CTRL_SELF_TEST_EN,
- .self_test_no_autoclear = true,
- .startup_delay = ADIS16201_STARTUP_DELAY,
-
- .status_error_msgs = adis16201_status_error_msgs,
- .status_error_mask = BIT(ADIS16201_DIAG_STAT_SPI_FAIL_BIT) |
- BIT(ADIS16201_DIAG_STAT_FLASH_UPT_BIT) |
- BIT(ADIS16201_DIAG_STAT_POWER_HIGH_BIT) |
- BIT(ADIS16201_DIAG_STAT_POWER_LOW_BIT),
-};
-
-static int adis16201_probe(struct spi_device *spi)
-{
- int ret;
- struct adis *st;
- struct iio_dev *indio_dev;
-
- /* setup the industrialio driver allocated elements */
- indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
- if (!indio_dev)
- return -ENOMEM;
-
- st = iio_priv(indio_dev);
- /* this is only used for removal purposes */
- spi_set_drvdata(spi, indio_dev);
-
- indio_dev->name = spi->dev.driver->name;
- indio_dev->dev.parent = &spi->dev;
- indio_dev->info = &adis16201_info;
-
- indio_dev->channels = adis16201_channels;
- indio_dev->num_channels = ARRAY_SIZE(adis16201_channels);
- indio_dev->modes = INDIO_DIRECT_MODE;
-
- ret = adis_init(st, indio_dev, spi, &adis16201_data);
- if (ret)
- return ret;
-
- ret = adis_setup_buffer_and_trigger(st, indio_dev, NULL);
- if (ret)
- return ret;
-
- /* Get the device into a sane initial state */
- ret = adis_initial_startup(st);
- if (ret)
- goto error_cleanup_buffer_trigger;
-
- ret = iio_device_register(indio_dev);
- if (ret < 0)
- goto error_cleanup_buffer_trigger;
-
- return 0;
-
-error_cleanup_buffer_trigger:
- adis_cleanup_buffer_and_trigger(st, indio_dev);
- return ret;
-}
-
-static int adis16201_remove(struct spi_device *spi)
-{
- struct iio_dev *indio_dev = spi_get_drvdata(spi);
- struct adis *st = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
- adis_cleanup_buffer_and_trigger(st, indio_dev);
-
- return 0;
-}
-
-static struct spi_driver adis16201_driver = {
- .driver = {
- .name = "adis16201",
- },
- .probe = adis16201_probe,
- .remove = adis16201_remove,
-};
-module_spi_driver(adis16201_driver);
-
-MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
-MODULE_DESCRIPTION("Analog Devices ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("spi:adis16201");
diff --git a/drivers/staging/iio/adc/ad7606_par.c b/drivers/staging/iio/adc/ad7606_par.c
index 3eb6f8f312dd..a34c2a1d5373 100644
--- a/drivers/staging/iio/adc/ad7606_par.c
+++ b/drivers/staging/iio/adc/ad7606_par.c
@@ -18,8 +18,7 @@
static int ad7606_par16_read_block(struct device *dev,
int count, void *buf)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ad7606_state *st = iio_priv(indio_dev);
insw((unsigned long)st->base_address, buf, count);
@@ -34,8 +33,7 @@ static const struct ad7606_bus_ops ad7606_par16_bops = {
static int ad7606_par8_read_block(struct device *dev,
int count, void *buf)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ad7606_state *st = iio_priv(indio_dev);
insb((unsigned long)st->base_address, buf, count * 2);
diff --git a/drivers/staging/iio/adc/ad7780.c b/drivers/staging/iio/adc/ad7780.c
index a7797af579b9..16d72072c076 100644
--- a/drivers/staging/iio/adc/ad7780.c
+++ b/drivers/staging/iio/adc/ad7780.c
@@ -128,7 +128,7 @@ static const struct ad_sigma_delta_info ad7780_sigma_delta_info = {
};
#define AD7780_CHANNEL(bits, wordsize) \
- AD_SD_CHANNEL(1, 0, 0, bits, 32, wordsize - bits)
+ AD_SD_CHANNEL_NO_SAMP_FREQ(1, 0, 0, bits, 32, wordsize - bits)
static const struct ad7780_chip_info ad7780_chip_info_tbl[] = {
[ID_AD7170] = {
diff --git a/drivers/staging/iio/cdc/ad7746.c b/drivers/staging/iio/cdc/ad7746.c
index 4882dbc81c53..f53612a6461d 100644
--- a/drivers/staging/iio/cdc/ad7746.c
+++ b/drivers/staging/iio/cdc/ad7746.c
@@ -6,15 +6,15 @@
* Licensed under the GPL-2.
*/
-#include <linux/interrupt.h>
+#include <linux/delay.h>
#include <linux/device.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/sysfs.h>
#include <linux/i2c.h>
-#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/slab.h>
#include <linux/stat.h>
+#include <linux/sysfs.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@@ -220,8 +220,8 @@ static int ad7746_select_channel(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan)
{
struct ad7746_chip_info *chip = iio_priv(indio_dev);
- int ret, delay, idx;
u8 vt_setup, cap_setup;
+ int ret, delay, idx;
switch (chan->type) {
case IIO_CAPACITANCE:
@@ -289,8 +289,8 @@ static inline ssize_t ad7746_start_calib(struct device *dev,
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7746_chip_info *chip = iio_priv(indio_dev);
- bool doit;
int ret, timeout = 10;
+ bool doit;
ret = strtobool(buf, &doit);
if (ret < 0)
@@ -410,8 +410,7 @@ static struct attribute *ad7746_attributes[] = {
&iio_dev_attr_in_capacitance1_calibbias_calibration.dev_attr.attr,
&iio_dev_attr_in_voltage0_calibscale_calibration.dev_attr.attr,
&iio_const_attr_in_voltage_sampling_frequency_available.dev_attr.attr,
- &iio_const_attr_in_capacitance_sampling_frequency_available.
- dev_attr.attr,
+ &iio_const_attr_in_capacitance_sampling_frequency_available.dev_attr.attr,
NULL,
};
@@ -451,26 +450,26 @@ static int ad7746_write_raw(struct iio_dev *indio_dev,
goto out;
}
- ret = i2c_smbus_write_word_data(chip->client, reg, swab16(val));
+ ret = i2c_smbus_write_word_swapped(chip->client, reg, val);
if (ret < 0)
goto out;
ret = 0;
break;
case IIO_CHAN_INFO_CALIBBIAS:
- if ((val < 0) | (val > 0xFFFF)) {
+ if (val < 0 || val > 0xFFFF) {
ret = -EINVAL;
goto out;
}
- ret = i2c_smbus_write_word_data(chip->client,
- AD7746_REG_CAP_OFFH, swab16(val));
+ ret = i2c_smbus_write_word_swapped(chip->client,
+ AD7746_REG_CAP_OFFH, val);
if (ret < 0)
goto out;
ret = 0;
break;
case IIO_CHAN_INFO_OFFSET:
- if ((val < 0) | (val > 43008000)) { /* 21pF */
+ if (val < 0 || val > 43008000) { /* 21pF */
ret = -EINVAL;
goto out;
}
@@ -556,7 +555,8 @@ static int ad7746_read_raw(struct iio_dev *indio_dev,
/* Now read the actual register */
ret = i2c_smbus_read_i2c_block_data(chip->client,
- chan->address >> 8, 3, &chip->data.d8[1]);
+ chan->address >> 8, 3,
+ &chip->data.d8[1]);
if (ret < 0)
goto out;
@@ -594,27 +594,27 @@ static int ad7746_read_raw(struct iio_dev *indio_dev,
goto out;
}
- ret = i2c_smbus_read_word_data(chip->client, reg);
+ ret = i2c_smbus_read_word_swapped(chip->client, reg);
if (ret < 0)
goto out;
/* 1 + gain_val / 2^16 */
*val = 1;
- *val2 = (15625 * swab16(ret)) / 1024;
+ *val2 = (15625 * ret) / 1024;
ret = IIO_VAL_INT_PLUS_MICRO;
break;
case IIO_CHAN_INFO_CALIBBIAS:
- ret = i2c_smbus_read_word_data(chip->client,
- AD7746_REG_CAP_OFFH);
+ ret = i2c_smbus_read_word_swapped(chip->client,
+ AD7746_REG_CAP_OFFH);
if (ret < 0)
goto out;
- *val = swab16(ret);
+ *val = ret;
ret = IIO_VAL_INT;
break;
case IIO_CHAN_INFO_OFFSET:
*val = AD7746_CAPDAC_DACP(chip->capdac[chan->channel]
- [chan->differential]) * 338646;
+ [chan->differential]) * 338646;
ret = IIO_VAL_INT;
break;
@@ -680,8 +680,8 @@ static int ad7746_probe(struct i2c_client *client,
struct ad7746_platform_data *pdata = client->dev.platform_data;
struct ad7746_chip_info *chip;
struct iio_dev *indio_dev;
- int ret = 0;
unsigned char regval = 0;
+ int ret = 0;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
if (!indio_dev)
diff --git a/drivers/staging/iio/light/tsl2x7x.c b/drivers/staging/iio/light/tsl2x7x.c
index 82681300e106..cc863e8927f5 100644
--- a/drivers/staging/iio/light/tsl2x7x.c
+++ b/drivers/staging/iio/light/tsl2x7x.c
@@ -1,18 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
- * Device driver for monitoring ambient light intensity in (lux)
- * and proximity detection (prox) within the TAOS TSL2X7X family of devices.
+ * Device driver for monitoring ambient light intensity in (lux) and proximity
+ * detection (prox) within the TAOS TSL2X7X family of devices.
*
* Copyright (c) 2012, TAOS Corporation.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
+ * Copyright (c) 2017-2018 Brian Masney <masneyb@onstation.org>
*/
#include <linux/delay.h>
@@ -28,7 +20,7 @@
#include <linux/iio/sysfs.h>
#include "tsl2x7x.h"
-/* Cal defs*/
+/* Cal defs */
#define PROX_STAT_CAL 0
#define PROX_STAT_SAMP 1
#define MAX_SAMPLES_CAL 200
@@ -41,10 +33,11 @@
/* Lux calculation constants */
#define TSL2X7X_LUX_CALC_OVER_FLOW 65535
-/* TAOS Register definitions - note:
- * depending on device, some of these register are not used and the
- * register address is benign.
+/*
+ * TAOS Register definitions - Note: depending on device, some of these register
+ * are not used and the register address is benign.
*/
+
/* 2X7X register offsets */
#define TSL2X7X_MAX_CONFIG_REG 16
@@ -62,7 +55,7 @@
#define TSL2X7X_PRX_MAXTHRESHLO 0X0A
#define TSL2X7X_PRX_MAXTHRESHHI 0X0B
#define TSL2X7X_PERSISTENCE 0x0C
-#define TSL2X7X_PRX_CONFIG 0x0D
+#define TSL2X7X_ALS_PRX_CONFIG 0x0D
#define TSL2X7X_PRX_COUNT 0x0E
#define TSL2X7X_GAIN 0x0F
#define TSL2X7X_NOTUSED 0x10
@@ -79,6 +72,8 @@
/* tsl2X7X cmd reg masks */
#define TSL2X7X_CMD_REG 0x80
#define TSL2X7X_CMD_SPL_FN 0x60
+#define TSL2X7X_CMD_REPEAT_PROTO 0x00
+#define TSL2X7X_CMD_AUTOINC_PROTO 0x20
#define TSL2X7X_CMD_PROX_INT_CLR 0X05
#define TSL2X7X_CMD_ALS_INT_CLR 0x06
@@ -108,18 +103,6 @@
#define TSL2X7X_CNTL_PROXPON_ENBL 0x0F
#define TSL2X7X_CNTL_INTPROXPON_ENBL 0x2F
-/*Prox diode to use */
-#define TSL2X7X_DIODE0 0x01
-#define TSL2X7X_DIODE1 0x02
-#define TSL2X7X_DIODE_BOTH 0x03
-
-/* LED Power */
-#define TSL2X7X_100_mA 0x00
-#define TSL2X7X_50_mA 0x01
-#define TSL2X7X_25_mA 0x02
-#define TSL2X7X_13_mA 0x03
-#define TSL2X7X_MAX_TIMER_CNT 0xFF
-
#define TSL2X7X_MIN_ITIME 3
/* TAOS txx2x7x Device family members */
@@ -149,17 +132,11 @@ struct tsl2x7x_als_info {
u16 lux;
};
-struct tsl2x7x_prox_stat {
- int min;
- int max;
- int mean;
- unsigned long stddev;
-};
-
struct tsl2x7x_chip_info {
int chan_table_elements;
- struct iio_chan_spec channel[4];
- const struct iio_info *info;
+ struct iio_chan_spec channel_with_events[4];
+ struct iio_chan_spec channel_without_events[4];
+ const struct iio_info *info;
};
struct tsl2X7X_chip {
@@ -171,7 +148,7 @@ struct tsl2X7X_chip {
struct tsl2x7x_als_info als_cur_info;
struct tsl2x7x_settings settings;
struct tsl2X7X_platform_data *pdata;
- int als_time_scale;
+ int als_gain_time_scale;
int als_saturation;
int tsl2x7x_chip_status;
u8 tsl2x7x_config[TSL2X7X_MAX_CONFIG_REG];
@@ -186,29 +163,36 @@ struct tsl2X7X_chip {
struct tsl2x7x_lux tsl2x7x_device_lux[TSL2X7X_MAX_LUX_TABLE_SIZE];
};
-/* Different devices require different coefficents */
+/*
+ * Different devices require different coefficents, and these numbers were
+ * derived from the 'Lux Equation' section of the various device datasheets.
+ * All of these coefficients assume a Glass Attenuation (GA) factor of 1.
+ * The coefficients are multiplied by 1000 to avoid floating point operations.
+ * The two rows in each table correspond to the Lux1 and Lux2 equations from
+ * the datasheets.
+ */
static const struct tsl2x7x_lux tsl2x71_lux_table[TSL2X7X_DEF_LUX_TABLE_SZ] = {
- { 14461, 611, 1211 },
- { 18540, 352, 623 },
- { 0, 0, 0 },
+ { 53000, 106000 },
+ { 31800, 53000 },
+ { 0, 0 },
};
static const struct tsl2x7x_lux tmd2x71_lux_table[TSL2X7X_DEF_LUX_TABLE_SZ] = {
- { 11635, 115, 256 },
- { 15536, 87, 179 },
- { 0, 0, 0 },
+ { 24000, 48000 },
+ { 14400, 24000 },
+ { 0, 0 },
};
static const struct tsl2x7x_lux tsl2x72_lux_table[TSL2X7X_DEF_LUX_TABLE_SZ] = {
- { 14013, 466, 917 },
- { 18222, 310, 552 },
- { 0, 0, 0 },
+ { 60000, 112200 },
+ { 37800, 60000 },
+ { 0, 0 },
};
static const struct tsl2x7x_lux tmd2x72_lux_table[TSL2X7X_DEF_LUX_TABLE_SZ] = {
- { 13218, 130, 262 },
- { 17592, 92, 169 },
- { 0, 0, 0 },
+ { 20000, 35000 },
+ { 12600, 20000 },
+ { 0, 0 },
};
static const struct tsl2x7x_lux *tsl2x7x_default_lux_table_group[] = {
@@ -225,18 +209,20 @@ static const struct tsl2x7x_lux *tsl2x7x_default_lux_table_group[] = {
};
static const struct tsl2x7x_settings tsl2x7x_default_settings = {
- .als_time = 219, /* 101 ms */
+ .als_time = 255, /* 2.73 ms */
.als_gain = 0,
- .prx_time = 254, /* 5.4 ms */
+ .prox_time = 255, /* 2.73 ms */
.prox_gain = 0,
- .wait_time = 245,
- .prox_config = 0,
+ .wait_time = 255,
+ .als_prox_config = 0,
.als_gain_trim = 1000,
.als_cal_target = 150,
+ .als_persistence = 1,
+ .als_interrupt_en = false,
.als_thresh_low = 200,
.als_thresh_high = 256,
- .persistence = 255,
- .interrupts_en = 0,
+ .prox_persistence = 1,
+ .prox_interrupt_en = false,
.prox_thres_low = 0,
.prox_thres_high = 512,
.prox_max_samples_cal = 30,
@@ -252,7 +238,7 @@ static const s16 tsl2x7x_als_gain[] = {
120
};
-static const s16 tsl2x7x_prx_gain[] = {
+static const s16 tsl2x7x_prox_gain[] = {
1,
2,
4,
@@ -269,32 +255,18 @@ enum {
};
static const u8 device_channel_config[] = {
- ALS,
- PRX,
- PRX,
- ALSPRX,
- ALSPRX,
- ALS,
- PRX2,
- PRX2,
- ALSPRX2,
- ALSPRX2
+ [tsl2571] = ALS,
+ [tsl2671] = PRX,
+ [tmd2671] = PRX,
+ [tsl2771] = ALSPRX,
+ [tmd2771] = ALSPRX,
+ [tsl2572] = ALS,
+ [tsl2672] = PRX2,
+ [tmd2672] = PRX2,
+ [tsl2772] = ALSPRX2,
+ [tmd2772] = ALSPRX2
};
-static int tsl2x7x_clear_interrupts(struct tsl2X7X_chip *chip, int reg)
-{
- int ret;
-
- ret = i2c_smbus_write_byte(chip->client,
- TSL2X7X_CMD_REG | TSL2X7X_CMD_SPL_FN | reg);
- if (ret < 0)
- dev_err(&chip->client->dev,
- "%s: failed to clear interrupt status %x: %d\n",
- __func__, reg, ret);
-
- return ret;
-}
-
static int tsl2x7x_read_status(struct tsl2X7X_chip *chip)
{
int ret;
@@ -324,38 +296,76 @@ static int tsl2x7x_write_control_reg(struct tsl2X7X_chip *chip, u8 data)
return ret;
}
+static int tsl2x7x_read_autoinc_regs(struct tsl2X7X_chip *chip, int lower_reg,
+ int upper_reg)
+{
+ u8 buf[2];
+ int ret;
+
+ ret = i2c_smbus_write_byte(chip->client,
+ TSL2X7X_CMD_REG | TSL2X7X_CMD_AUTOINC_PROTO |
+ lower_reg);
+ if (ret < 0) {
+ dev_err(&chip->client->dev,
+ "%s: failed to enable auto increment protocol: %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ ret = i2c_smbus_read_byte_data(chip->client,
+ TSL2X7X_CMD_REG | lower_reg);
+ if (ret < 0) {
+ dev_err(&chip->client->dev,
+ "%s: failed to read from register %x: %d\n", __func__,
+ lower_reg, ret);
+ return ret;
+ }
+ buf[0] = ret;
+
+ ret = i2c_smbus_read_byte_data(chip->client,
+ TSL2X7X_CMD_REG | upper_reg);
+ if (ret < 0) {
+ dev_err(&chip->client->dev,
+ "%s: failed to read from register %x: %d\n", __func__,
+ upper_reg, ret);
+ return ret;
+ }
+ buf[1] = ret;
+
+ ret = i2c_smbus_write_byte(chip->client,
+ TSL2X7X_CMD_REG | TSL2X7X_CMD_REPEAT_PROTO |
+ lower_reg);
+ if (ret < 0) {
+ dev_err(&chip->client->dev,
+ "%s: failed to enable repeated byte protocol: %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ return le16_to_cpup((const __le16 *)&buf[0]);
+}
+
/**
* tsl2x7x_get_lux() - Reads and calculates current lux value.
* @indio_dev: pointer to IIO device
*
* The raw ch0 and ch1 values of the ambient light sensed in the last
- * integration cycle are read from the device.
- * Time scale factor array values are adjusted based on the integration time.
- * The raw values are multiplied by a scale factor, and device gain is obtained
- * using gain index. Limit checks are done next, then the ratio of a multiple
- * of ch1 value, to the ch0 value, is calculated. Array tsl2x7x_device_lux[]
- * is then scanned to find the first ratio value that is just above the ratio
- * we just calculated. The ch0 and ch1 multiplier constants in the array are
- * then used along with the time scale factor array values, to calculate the
- * lux.
+ * integration cycle are read from the device. The raw values are multiplied
+ * by a device-specific scale factor, and divided by the integration time and
+ * device gain. The code supports multiple lux equations through the lux table
+ * coefficients. A lux gain trim is applied to each lux equation, and then the
+ * maximum lux within the interval 0..65535 is selected.
*/
static int tsl2x7x_get_lux(struct iio_dev *indio_dev)
{
- u16 ch0, ch1; /* separated ch0/ch1 data from device */
- u32 lux; /* raw lux calculated from device data */
- u64 lux64;
- u32 ratio;
- u8 buf[4];
- struct tsl2x7x_lux *p;
struct tsl2X7X_chip *chip = iio_priv(indio_dev);
- int i, ret;
- u32 ch0lux = 0;
- u32 ch1lux = 0;
+ struct tsl2x7x_lux *p;
+ int max_lux, ret;
+ bool overflow;
mutex_lock(&chip->als_mutex);
if (chip->tsl2x7x_chip_status != TSL2X7X_CHIP_WORKING) {
- /* device is not enabled */
dev_err(&chip->client->dev, "%s: device is not enabled\n",
__func__);
ret = -EBUSY;
@@ -366,7 +376,6 @@ static int tsl2x7x_get_lux(struct iio_dev *indio_dev)
if (ret < 0)
goto out_unlock;
- /* is data new & valid */
if (!(ret & TSL2X7X_STA_ADC_VALID)) {
dev_err(&chip->client->dev,
"%s: data not valid yet\n", __func__);
@@ -374,91 +383,61 @@ static int tsl2x7x_get_lux(struct iio_dev *indio_dev)
goto out_unlock;
}
- for (i = 0; i < 4; i++) {
- int reg = TSL2X7X_CMD_REG | (TSL2X7X_ALS_CHAN0LO + i);
-
- ret = i2c_smbus_read_byte_data(chip->client, reg);
- if (ret < 0) {
- dev_err(&chip->client->dev,
- "failed to read. err=%x\n", ret);
- goto out_unlock;
- }
-
- buf[i] = ret;
- }
-
- ret = tsl2x7x_clear_interrupts(chip, TSL2X7X_CMD_ALS_INT_CLR);
+ ret = tsl2x7x_read_autoinc_regs(chip, TSL2X7X_ALS_CHAN0LO,
+ TSL2X7X_ALS_CHAN0HI);
if (ret < 0)
goto out_unlock;
+ chip->als_cur_info.als_ch0 = ret;
- /* extract ALS/lux data */
- ch0 = le16_to_cpup((const __le16 *)&buf[0]);
- ch1 = le16_to_cpup((const __le16 *)&buf[2]);
-
- chip->als_cur_info.als_ch0 = ch0;
- chip->als_cur_info.als_ch1 = ch1;
+ ret = tsl2x7x_read_autoinc_regs(chip, TSL2X7X_ALS_CHAN1LO,
+ TSL2X7X_ALS_CHAN1HI);
+ if (ret < 0)
+ goto out_unlock;
+ chip->als_cur_info.als_ch1 = ret;
- if (ch0 >= chip->als_saturation || ch1 >= chip->als_saturation) {
- lux = TSL2X7X_LUX_CALC_OVER_FLOW;
- goto return_max;
+ if (chip->als_cur_info.als_ch0 >= chip->als_saturation) {
+ max_lux = TSL2X7X_LUX_CALC_OVER_FLOW;
+ goto update_struct_with_max_lux;
}
- if (!ch0) {
+ if (!chip->als_cur_info.als_ch0) {
/* have no data, so return LAST VALUE */
ret = chip->als_cur_info.lux;
goto out_unlock;
}
- /* calculate ratio */
- ratio = (ch1 << 15) / ch0;
- /* convert to unscaled lux using the pointer to the table */
- p = (struct tsl2x7x_lux *)chip->tsl2x7x_device_lux;
- while (p->ratio != 0 && p->ratio < ratio)
- p++;
-
- if (p->ratio == 0) {
- lux = 0;
- } else {
- lux = DIV_ROUND_UP(ch0 * p->ch0,
- tsl2x7x_als_gain[chip->settings.als_gain]) -
- DIV_ROUND_UP(ch1 * p->ch1,
- tsl2x7x_als_gain[chip->settings.als_gain]);
- }
-
- /* note: lux is 31 bit max at this point */
- if (ch1lux > ch0lux) {
- dev_dbg(&chip->client->dev, "ch1lux > ch0lux-return last value\n");
- ret = chip->als_cur_info.lux;
- goto out_unlock;
- }
- /* adjust for active time scale */
- if (chip->als_time_scale == 0)
- lux = 0;
- else
- lux = (lux + (chip->als_time_scale >> 1)) /
- chip->als_time_scale;
-
- /* adjust for active gain scale
- * The tsl2x7x_device_lux tables have a factor of 256 built-in.
- * User-specified gain provides a multiplier.
- * Apply user-specified gain before shifting right to retain precision.
- * Use 64 bits to avoid overflow on multiplication.
- * Then go back to 32 bits before division to avoid using div_u64().
- */
+ max_lux = 0;
+ overflow = false;
+ for (p = (struct tsl2x7x_lux *)chip->tsl2x7x_device_lux; p->ch0 != 0;
+ p++) {
+ int lux;
+
+ lux = ((chip->als_cur_info.als_ch0 * p->ch0) -
+ (chip->als_cur_info.als_ch1 * p->ch1)) /
+ chip->als_gain_time_scale;
+
+ /*
+ * The als_gain_trim can have a value within the range 250..4000
+ * and is a multiplier for the lux. A trim of 1000 makes no
+ * changes to the lux, less than 1000 scales it down, and
+ * greater than 1000 scales it up.
+ */
+ lux = (lux * chip->settings.als_gain_trim) / 1000;
+
+ if (lux > TSL2X7X_LUX_CALC_OVER_FLOW) {
+ overflow = true;
+ continue;
+ }
- lux64 = lux;
- lux64 = lux64 * chip->settings.als_gain_trim;
- lux64 >>= 8;
- lux = lux64;
- lux = (lux + 500) / 1000;
+ max_lux = max(max_lux, lux);
+ }
- if (lux > TSL2X7X_LUX_CALC_OVER_FLOW) /* check for overflow */
- lux = TSL2X7X_LUX_CALC_OVER_FLOW;
+ if (overflow && max_lux == 0)
+ max_lux = TSL2X7X_LUX_CALC_OVER_FLOW;
- /* Update the structure with the latest lux. */
-return_max:
- chip->als_cur_info.lux = lux;
- ret = lux;
+update_struct_with_max_lux:
+ chip->als_cur_info.lux = max_lux;
+ ret = max_lux;
out_unlock:
mutex_unlock(&chip->als_mutex);
@@ -474,10 +453,8 @@ out_unlock:
*/
static int tsl2x7x_get_prox(struct iio_dev *indio_dev)
{
- int i;
- int ret;
- u8 chdata[2];
struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+ int ret;
mutex_lock(&chip->prox_mutex);
@@ -508,18 +485,10 @@ static int tsl2x7x_get_prox(struct iio_dev *indio_dev)
break;
}
- for (i = 0; i < 2; i++) {
- int reg = TSL2X7X_CMD_REG | (TSL2X7X_PRX_LO + i);
-
- ret = i2c_smbus_read_byte_data(chip->client, reg);
- if (ret < 0)
- goto prox_poll_err;
-
- chdata[i] = ret;
- }
-
- chip->prox_data = le16_to_cpup((const __le16 *)&chdata[0]);
- ret = chip->prox_data;
+ ret = tsl2x7x_read_autoinc_regs(chip, TSL2X7X_PRX_LO, TSL2X7X_PRX_HI);
+ if (ret < 0)
+ goto prox_poll_err;
+ chip->prox_data = ret;
prox_poll_err:
mutex_unlock(&chip->prox_mutex);
@@ -545,7 +514,7 @@ static void tsl2x7x_defaults(struct tsl2X7X_chip *chip)
sizeof(tsl2x7x_default_settings));
/* Load up the proper lux table. */
- if (chip->pdata && chip->pdata->platform_lux_table[0].ratio != 0)
+ if (chip->pdata && chip->pdata->platform_lux_table[0].ch0 != 0)
memcpy(chip->tsl2x7x_device_lux,
chip->pdata->platform_lux_table,
sizeof(chip->pdata->platform_lux_table));
@@ -601,26 +570,22 @@ static int tsl2x7x_als_calibrate(struct iio_dev *indio_dev)
return -ERANGE;
chip->settings.als_gain_trim = ret;
- dev_info(&chip->client->dev,
- "%s als_calibrate completed\n", chip->client->name);
return ret;
}
static int tsl2x7x_chip_on(struct iio_dev *indio_dev)
{
- int i;
- int ret = 0;
- u8 *dev_reg;
- int als_count;
- int als_time;
struct tsl2X7X_chip *chip = iio_priv(indio_dev);
- u8 reg_val = 0;
+ int ret, i, als_count, als_time_us;
+ u8 *dev_reg, reg_val;
/* Non calculated parameters */
- chip->tsl2x7x_config[TSL2X7X_PRX_TIME] = chip->settings.prx_time;
+ chip->tsl2x7x_config[TSL2X7X_ALS_TIME] = chip->settings.als_time;
+ chip->tsl2x7x_config[TSL2X7X_PRX_TIME] = chip->settings.prox_time;
chip->tsl2x7x_config[TSL2X7X_WAIT_TIME] = chip->settings.wait_time;
- chip->tsl2x7x_config[TSL2X7X_PRX_CONFIG] = chip->settings.prox_config;
+ chip->tsl2x7x_config[TSL2X7X_ALS_PRX_CONFIG] =
+ chip->settings.als_prox_config;
chip->tsl2x7x_config[TSL2X7X_ALS_MINTHRESHLO] =
(chip->settings.als_thresh_low) & 0xFF;
@@ -630,7 +595,9 @@ static int tsl2x7x_chip_on(struct iio_dev *indio_dev)
(chip->settings.als_thresh_high) & 0xFF;
chip->tsl2x7x_config[TSL2X7X_ALS_MAXTHRESHHI] =
(chip->settings.als_thresh_high >> 8) & 0xFF;
- chip->tsl2x7x_config[TSL2X7X_PERSISTENCE] = chip->settings.persistence;
+ chip->tsl2x7x_config[TSL2X7X_PERSISTENCE] =
+ (chip->settings.prox_persistence & 0xFF) << 4 |
+ (chip->settings.als_persistence & 0xFF);
chip->tsl2x7x_config[TSL2X7X_PRX_COUNT] =
chip->settings.prox_pulse_count;
@@ -650,15 +617,6 @@ static int tsl2x7x_chip_on(struct iio_dev *indio_dev)
return -EINVAL;
}
- /* determine als integration register */
- als_count = (chip->settings.als_time * 100 + 135) / 270;
- if (!als_count)
- als_count = 1; /* ensure at least one cycle */
-
- /* convert back to time (encompasses overrides) */
- als_time = (als_count * 27 + 5) / 10;
- chip->tsl2x7x_config[TSL2X7X_ALS_TIME] = 256 - als_count;
-
/* Set the gain based on tsl2x7x_settings struct */
chip->tsl2x7x_config[TSL2X7X_GAIN] =
(chip->settings.als_gain & 0xFF) |
@@ -666,9 +624,12 @@ static int tsl2x7x_chip_on(struct iio_dev *indio_dev)
(chip->settings.prox_diode << 4) |
(chip->settings.prox_power << 6);
- /* set chip struct re scaling and saturation */
- chip->als_saturation = als_count * 922; /* 90% of full scale */
- chip->als_time_scale = (als_time + 25) / 50;
+ /* set chip time scaling and saturation */
+ als_count = 256 - chip->settings.als_time;
+ als_time_us = als_count * 2720;
+ chip->als_saturation = als_count * 768; /* 75% of full scale */
+ chip->als_gain_time_scale = als_time_us *
+ tsl2x7x_als_gain[chip->settings.als_gain];
/*
* TSL2X7X Specific power-on / adc enable sequence
@@ -684,12 +645,14 @@ static int tsl2x7x_chip_on(struct iio_dev *indio_dev)
*/
for (i = 0, dev_reg = chip->tsl2x7x_config;
i < TSL2X7X_MAX_CONFIG_REG; i++) {
- ret = i2c_smbus_write_byte_data(chip->client,
- TSL2X7X_CMD_REG + i,
+ int reg = TSL2X7X_CMD_REG + i;
+
+ ret = i2c_smbus_write_byte_data(chip->client, reg,
*dev_reg++);
if (ret < 0) {
dev_err(&chip->client->dev,
- "failed on write to reg %d.\n", i);
+ "%s: failed to write to register %x: %d\n",
+ __func__, reg, ret);
return ret;
}
}
@@ -697,38 +660,29 @@ static int tsl2x7x_chip_on(struct iio_dev *indio_dev)
/* Power-on settling time */
usleep_range(3000, 3500);
- /*
- * NOW enable the ADC
- * initialize the desired mode of operation
- */
- ret = tsl2x7x_write_control_reg(chip,
- TSL2X7X_CNTL_PWR_ON |
- TSL2X7X_CNTL_ADC_ENBL |
- TSL2X7X_CNTL_PROX_DET_ENBL);
+ reg_val = TSL2X7X_CNTL_PWR_ON | TSL2X7X_CNTL_ADC_ENBL |
+ TSL2X7X_CNTL_PROX_DET_ENBL;
+ if (chip->settings.als_interrupt_en)
+ reg_val |= TSL2X7X_CNTL_ALS_INT_ENBL;
+ if (chip->settings.prox_interrupt_en)
+ reg_val |= TSL2X7X_CNTL_PROX_INT_ENBL;
+
+ ret = tsl2x7x_write_control_reg(chip, reg_val);
if (ret < 0)
return ret;
- chip->tsl2x7x_chip_status = TSL2X7X_CHIP_WORKING;
-
- if (chip->settings.interrupts_en != 0) {
- dev_info(&chip->client->dev, "Setting Up Interrupt(s)\n");
-
- reg_val = TSL2X7X_CNTL_PWR_ON | TSL2X7X_CNTL_ADC_ENBL;
- if (chip->settings.interrupts_en == 0x20 ||
- chip->settings.interrupts_en == 0x30)
- reg_val |= TSL2X7X_CNTL_PROX_DET_ENBL;
-
- reg_val |= chip->settings.interrupts_en;
- ret = tsl2x7x_write_control_reg(chip, reg_val);
- if (ret < 0)
- return ret;
-
- ret = tsl2x7x_clear_interrupts(chip,
- TSL2X7X_CMD_PROXALS_INT_CLR);
- if (ret < 0)
- return ret;
+ ret = i2c_smbus_write_byte(chip->client,
+ TSL2X7X_CMD_REG | TSL2X7X_CMD_SPL_FN |
+ TSL2X7X_CMD_PROXALS_INT_CLR);
+ if (ret < 0) {
+ dev_err(&chip->client->dev,
+ "%s: failed to clear interrupt status: %d\n",
+ __func__, ret);
+ return ret;
}
+ chip->tsl2x7x_chip_status = TSL2X7X_CHIP_WORKING;
+
return ret;
}
@@ -742,14 +696,13 @@ static int tsl2x7x_chip_off(struct iio_dev *indio_dev)
}
/**
- * tsl2x7x_invoke_change
+ * tsl2x7x_invoke_change - power cycle the device to implement the user
+ * parameters
* @indio_dev: pointer to IIO device
*
- * Obtain and lock both ALS and PROX resources,
- * determine and save device state (On/Off),
- * cycle device to implement updated parameter,
- * put device back into proper state, and unlock
- * resource.
+ * Obtain and lock both ALS and PROX resources, determine and save device state
+ * (On/Off), cycle device to implement updated parameter, put device back into
+ * proper state, and unlock resource.
*/
static int tsl2x7x_invoke_change(struct iio_dev *indio_dev)
{
@@ -775,130 +728,43 @@ unlock:
return ret;
}
-static void tsl2x7x_prox_calculate(int *data, int length,
- struct tsl2x7x_prox_stat *stat)
-{
- int i;
- int sample_sum;
- int tmp;
-
- if (!length)
- length = 1;
-
- sample_sum = 0;
- stat->min = INT_MAX;
- stat->max = INT_MIN;
- for (i = 0; i < length; i++) {
- sample_sum += data[i];
- stat->min = min(stat->min, data[i]);
- stat->max = max(stat->max, data[i]);
- }
-
- stat->mean = sample_sum / length;
- sample_sum = 0;
- for (i = 0; i < length; i++) {
- tmp = data[i] - stat->mean;
- sample_sum += tmp * tmp;
- }
- stat->stddev = int_sqrt((long)sample_sum / length);
-}
-
-/**
- * tsl2x7x_prox_cal() - Calculates std. and sets thresholds.
- * @indio_dev: pointer to IIO device
- *
- * Calculates a standard deviation based on the samples,
- * and sets the threshold accordingly.
- */
static int tsl2x7x_prox_cal(struct iio_dev *indio_dev)
{
- int prox_history[MAX_SAMPLES_CAL + 1];
- int i, ret;
- struct tsl2x7x_prox_stat prox_stat_data[2];
- struct tsl2x7x_prox_stat *cal;
struct tsl2X7X_chip *chip = iio_priv(indio_dev);
- u8 tmp_irq_settings;
- u8 current_state = chip->tsl2x7x_chip_status;
-
- if (chip->settings.prox_max_samples_cal > MAX_SAMPLES_CAL) {
- dev_err(&chip->client->dev,
- "max prox samples cal is too big: %d\n",
- chip->settings.prox_max_samples_cal);
- chip->settings.prox_max_samples_cal = MAX_SAMPLES_CAL;
- }
-
- /* have to stop to change settings */
- ret = tsl2x7x_chip_off(indio_dev);
- if (ret < 0)
- return ret;
-
- /* Enable proximity detection save just in case prox not wanted yet*/
- tmp_irq_settings = chip->settings.interrupts_en;
- chip->settings.interrupts_en |= TSL2X7X_CNTL_PROX_INT_ENBL;
+ int prox_history[MAX_SAMPLES_CAL + 1];
+ int i, ret, mean, max, sample_sum;
- /*turn on device if not already on*/
- ret = tsl2x7x_chip_on(indio_dev);
- if (ret < 0)
- return ret;
+ if (chip->settings.prox_max_samples_cal < 1 ||
+ chip->settings.prox_max_samples_cal > MAX_SAMPLES_CAL)
+ return -EINVAL;
- /*gather the samples*/
for (i = 0; i < chip->settings.prox_max_samples_cal; i++) {
usleep_range(15000, 17500);
ret = tsl2x7x_get_prox(indio_dev);
if (ret < 0)
return ret;
+
prox_history[i] = chip->prox_data;
- dev_info(&chip->client->dev, "2 i=%d prox data= %d\n",
- i, chip->prox_data);
}
- ret = tsl2x7x_chip_off(indio_dev);
- if (ret < 0)
- return ret;
- cal = &prox_stat_data[PROX_STAT_CAL];
- tsl2x7x_prox_calculate(prox_history,
- chip->settings.prox_max_samples_cal, cal);
- chip->settings.prox_thres_high = (cal->max << 1) - cal->mean;
-
- dev_info(&chip->client->dev, " cal min=%d mean=%d max=%d\n",
- cal->min, cal->mean, cal->max);
- dev_info(&chip->client->dev,
- "%s proximity threshold set to %d\n",
- chip->client->name, chip->settings.prox_thres_high);
-
- /* back to the way they were */
- chip->settings.interrupts_en = tmp_irq_settings;
- if (current_state == TSL2X7X_CHIP_WORKING) {
- ret = tsl2x7x_chip_on(indio_dev);
- if (ret < 0)
- return ret;
+ sample_sum = 0;
+ max = INT_MIN;
+ for (i = 0; i < chip->settings.prox_max_samples_cal; i++) {
+ sample_sum += prox_history[i];
+ max = max(max, prox_history[i]);
}
+ mean = sample_sum / chip->settings.prox_max_samples_cal;
- return 0;
-}
-
-static ssize_t
-in_illuminance0_calibscale_available_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
-
- switch (chip->id) {
- case tsl2571:
- case tsl2671:
- case tmd2671:
- case tsl2771:
- case tmd2771:
- return snprintf(buf, PAGE_SIZE, "%s\n", "1 8 16 128");
- }
+ chip->settings.prox_thres_high = (max << 1) - mean;
- return snprintf(buf, PAGE_SIZE, "%s\n", "1 8 16 120");
+ return tsl2x7x_invoke_change(indio_dev);
}
+static IIO_CONST_ATTR(in_intensity0_calibscale_available, "1 8 16 120");
+
static IIO_CONST_ATTR(in_proximity0_calibscale_available, "1 2 4 8");
-static IIO_CONST_ATTR(in_illuminance0_integration_time_available,
+static IIO_CONST_ATTR(in_intensity0_integration_time_available,
".00272 - .696");
static ssize_t in_illuminance0_target_input_show(struct device *dev,
@@ -916,15 +782,13 @@ static ssize_t in_illuminance0_target_input_store(struct device *dev,
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct tsl2X7X_chip *chip = iio_priv(indio_dev);
- unsigned long value;
+ u16 value;
int ret;
- if (kstrtoul(buf, 0, &value))
+ if (kstrtou16(buf, 0, &value))
return -EINVAL;
- if (value)
- chip->settings.als_cal_target = value;
-
+ chip->settings.als_cal_target = value;
ret = tsl2x7x_invoke_change(indio_dev);
if (ret < 0)
return ret;
@@ -940,14 +804,12 @@ static ssize_t in_illuminance0_calibrate_store(struct device *dev,
bool value;
int ret;
- if (strtobool(buf, &value))
+ if (kstrtobool(buf, &value) || !value)
return -EINVAL;
- if (value) {
- ret = tsl2x7x_als_calibrate(indio_dev);
- if (ret < 0)
- return ret;
- }
+ ret = tsl2x7x_als_calibrate(indio_dev);
+ if (ret < 0)
+ return ret;
ret = tsl2x7x_invoke_change(indio_dev);
if (ret < 0)
@@ -965,11 +827,10 @@ static ssize_t in_illuminance0_lux_table_show(struct device *dev,
int offset = 0;
while (i < TSL2X7X_MAX_LUX_TABLE_SIZE) {
- offset += snprintf(buf + offset, PAGE_SIZE, "%u,%u,%u,",
- chip->tsl2x7x_device_lux[i].ratio,
+ offset += snprintf(buf + offset, PAGE_SIZE, "%u,%u,",
chip->tsl2x7x_device_lux[i].ch0,
chip->tsl2x7x_device_lux[i].ch1);
- if (chip->tsl2x7x_device_lux[i].ratio == 0) {
+ if (chip->tsl2x7x_device_lux[i].ch0 == 0) {
/*
* We just printed the first "0" entry.
* Now get rid of the extra "," and break.
@@ -990,27 +851,24 @@ static ssize_t in_illuminance0_lux_table_store(struct device *dev,
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct tsl2X7X_chip *chip = iio_priv(indio_dev);
- int value[ARRAY_SIZE(chip->tsl2x7x_device_lux) * 3 + 1];
+ int value[ARRAY_SIZE(chip->tsl2x7x_device_lux) * 2 + 1];
int n, ret;
get_options(buf, ARRAY_SIZE(value), value);
- /* We now have an array of ints starting at value[1], and
+ /*
+ * We now have an array of ints starting at value[1], and
* enumerated by value[0].
- * We expect each group of three ints is one table entry,
+ * We expect each group of two ints to be one table entry,
* and the last table entry is all 0.
*/
n = value[0];
- if ((n % 3) || n < 6 ||
- n > ((ARRAY_SIZE(chip->tsl2x7x_device_lux) - 1) * 3)) {
- dev_info(dev, "LUX TABLE INPUT ERROR 1 Value[0]=%d\n", n);
+ if ((n % 2) || n < 4 ||
+ n > ((ARRAY_SIZE(chip->tsl2x7x_device_lux) - 1) * 2))
return -EINVAL;
- }
- if ((value[(n - 2)] | value[(n - 1)] | value[n]) != 0) {
- dev_info(dev, "LUX TABLE INPUT ERROR 2 Value[0]=%d\n", n);
+ if ((value[(n - 1)] | value[n]) != 0)
return -EINVAL;
- }
if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING) {
ret = tsl2x7x_chip_off(indio_dev);
@@ -1037,14 +895,12 @@ static ssize_t in_proximity0_calibrate_store(struct device *dev,
bool value;
int ret;
- if (strtobool(buf, &value))
+ if (kstrtobool(buf, &value) || !value)
return -EINVAL;
- if (value) {
- ret = tsl2x7x_prox_cal(indio_dev);
- if (ret < 0)
- return ret;
- }
+ ret = tsl2x7x_prox_cal(indio_dev);
+ if (ret < 0)
+ return ret;
ret = tsl2x7x_invoke_change(indio_dev);
if (ret < 0)
@@ -1059,14 +915,11 @@ static int tsl2x7x_read_interrupt_config(struct iio_dev *indio_dev,
enum iio_event_direction dir)
{
struct tsl2X7X_chip *chip = iio_priv(indio_dev);
- int ret;
if (chan->type == IIO_INTENSITY)
- ret = !!(chip->settings.interrupts_en & 0x10);
+ return chip->settings.als_interrupt_en;
else
- ret = !!(chip->settings.interrupts_en & 0x20);
-
- return ret;
+ return chip->settings.prox_interrupt_en;
}
static int tsl2x7x_write_interrupt_config(struct iio_dev *indio_dev,
@@ -1076,25 +929,13 @@ static int tsl2x7x_write_interrupt_config(struct iio_dev *indio_dev,
int val)
{
struct tsl2X7X_chip *chip = iio_priv(indio_dev);
- int ret;
- if (chan->type == IIO_INTENSITY) {
- if (val)
- chip->settings.interrupts_en |= 0x10;
- else
- chip->settings.interrupts_en &= 0x20;
- } else {
- if (val)
- chip->settings.interrupts_en |= 0x20;
- else
- chip->settings.interrupts_en &= 0x10;
- }
-
- ret = tsl2x7x_invoke_change(indio_dev);
- if (ret < 0)
- return ret;
+ if (chan->type == IIO_INTENSITY)
+ chip->settings.als_interrupt_en = val ? true : false;
+ else
+ chip->settings.prox_interrupt_en = val ? true : false;
- return 0;
+ return tsl2x7x_invoke_change(indio_dev);
}
static int tsl2x7x_write_event_value(struct iio_dev *indio_dev,
@@ -1142,27 +983,17 @@ static int tsl2x7x_write_event_value(struct iio_dev *indio_dev,
if (chan->type == IIO_INTENSITY)
time = chip->settings.als_time;
else
- time = chip->settings.prx_time;
+ time = chip->settings.prox_time;
y = (TSL2X7X_MAX_TIMER_CNT - time) + 1;
z = y * TSL2X7X_MIN_ITIME;
filter_delay = DIV_ROUND_UP((val * 1000) + val2, z);
- if (chan->type == IIO_INTENSITY) {
- chip->settings.persistence &= 0xF0;
- chip->settings.persistence |=
- (filter_delay & 0x0F);
- dev_info(&chip->client->dev, "%s: ALS persistence = %d",
- __func__, filter_delay);
- } else {
- chip->settings.persistence &= 0x0F;
- chip->settings.persistence |=
- ((filter_delay << 4) & 0xF0);
- dev_info(&chip->client->dev,
- "%s: Proximity persistence = %d",
- __func__, filter_delay);
- }
+ if (chan->type == IIO_INTENSITY)
+ chip->settings.als_persistence = filter_delay;
+ else
+ chip->settings.prox_persistence = filter_delay;
ret = 0;
break;
default:
@@ -1219,10 +1050,10 @@ static int tsl2x7x_read_event_value(struct iio_dev *indio_dev,
case IIO_EV_INFO_PERIOD:
if (chan->type == IIO_INTENSITY) {
time = chip->settings.als_time;
- mult = chip->settings.persistence & 0x0F;
+ mult = chip->settings.als_persistence;
} else {
- time = chip->settings.prx_time;
- mult = (chip->settings.persistence & 0xF0) >> 4;
+ time = chip->settings.prox_time;
+ mult = chip->settings.prox_persistence;
}
/* Determine integration time */
@@ -1246,8 +1077,8 @@ static int tsl2x7x_read_raw(struct iio_dev *indio_dev,
int *val2,
long mask)
{
- int ret = -EINVAL;
struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+ int ret = -EINVAL;
switch (mask) {
case IIO_CHAN_INFO_PROCESSED:
@@ -1284,7 +1115,7 @@ static int tsl2x7x_read_raw(struct iio_dev *indio_dev,
if (chan->type == IIO_LIGHT)
*val = tsl2x7x_als_gain[chip->settings.als_gain];
else
- *val = tsl2x7x_prx_gain[chip->settings.prox_gain];
+ *val = tsl2x7x_prox_gain[chip->settings.prox_gain];
ret = IIO_VAL_INT;
break;
case IIO_CHAN_INFO_CALIBBIAS:
@@ -1292,8 +1123,8 @@ static int tsl2x7x_read_raw(struct iio_dev *indio_dev,
ret = IIO_VAL_INT;
break;
case IIO_CHAN_INFO_INT_TIME:
- *val = (TSL2X7X_MAX_TIMER_CNT - chip->settings.als_time) + 1;
- *val2 = ((*val * TSL2X7X_MIN_ITIME) % 1000) / 1000;
+ *val = 0;
+ *val2 = (256 - chip->settings.als_time) * 2720;
ret = IIO_VAL_INT_PLUS_MICRO;
break;
default:
@@ -1325,25 +1156,6 @@ static int tsl2x7x_write_raw(struct iio_dev *indio_dev,
chip->settings.als_gain = 2;
break;
case 120:
- switch (chip->id) {
- case tsl2572:
- case tsl2672:
- case tmd2672:
- case tsl2772:
- case tmd2772:
- return -EINVAL;
- }
- chip->settings.als_gain = 3;
- break;
- case 128:
- switch (chip->id) {
- case tsl2571:
- case tsl2671:
- case tmd2671:
- case tsl2771:
- case tmd2771:
- return -EINVAL;
- }
chip->settings.als_gain = 3;
break;
default:
@@ -1372,11 +1184,7 @@ static int tsl2x7x_write_raw(struct iio_dev *indio_dev,
chip->settings.als_gain_trim = val;
break;
case IIO_CHAN_INFO_INT_TIME:
- chip->settings.als_time =
- TSL2X7X_MAX_TIMER_CNT - (val2 / TSL2X7X_MIN_ITIME);
-
- dev_info(&chip->client->dev, "%s: als time = %d",
- __func__, chip->settings.als_time);
+ chip->settings.als_time = 256 - (val2 / 2720);
break;
default:
return -EINVAL;
@@ -1385,8 +1193,6 @@ static int tsl2x7x_write_raw(struct iio_dev *indio_dev,
return tsl2x7x_invoke_change(indio_dev);
}
-static DEVICE_ATTR_RO(in_illuminance0_calibscale_available);
-
static DEVICE_ATTR_RW(in_illuminance0_target_input);
static DEVICE_ATTR_WO(in_illuminance0_calibrate);
@@ -1396,22 +1202,22 @@ static DEVICE_ATTR_WO(in_proximity0_calibrate);
static DEVICE_ATTR_RW(in_illuminance0_lux_table);
/* Use the default register values to identify the Taos device */
-static int tsl2x7x_device_id(int *id, int target)
+static int tsl2x7x_device_id_verif(int id, int target)
{
switch (target) {
case tsl2571:
case tsl2671:
case tsl2771:
- return (*id & 0xf0) == TRITON_ID;
+ return (id & 0xf0) == TRITON_ID;
case tmd2671:
case tmd2771:
- return (*id & 0xf0) == HALIBUT_ID;
+ return (id & 0xf0) == HALIBUT_ID;
case tsl2572:
case tsl2672:
case tmd2672:
case tsl2772:
case tmd2772:
- return (*id & 0xf0) == SWORDFISH_ID;
+ return (id & 0xf0) == SWORDFISH_ID;
}
return -EINVAL;
@@ -1426,11 +1232,10 @@ static irqreturn_t tsl2x7x_event_handler(int irq, void *private)
ret = tsl2x7x_read_status(chip);
if (ret < 0)
- return ret;
+ return IRQ_HANDLED;
/* What type of interrupt do we need to process */
if (ret & TSL2X7X_STA_PRX_INTR) {
- tsl2x7x_get_prox(indio_dev); /* freshen data for ABI */
iio_push_event(indio_dev,
IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY,
0,
@@ -1440,7 +1245,6 @@ static irqreturn_t tsl2x7x_event_handler(int irq, void *private)
}
if (ret & TSL2X7X_STA_ALS_INTR) {
- tsl2x7x_get_lux(indio_dev); /* freshen data for ABI */
iio_push_event(indio_dev,
IIO_UNMOD_EVENT_CODE(IIO_LIGHT,
0,
@@ -1449,17 +1253,20 @@ static irqreturn_t tsl2x7x_event_handler(int irq, void *private)
timestamp);
}
- ret = tsl2x7x_clear_interrupts(chip, TSL2X7X_CMD_PROXALS_INT_CLR);
+ ret = i2c_smbus_write_byte(chip->client,
+ TSL2X7X_CMD_REG | TSL2X7X_CMD_SPL_FN |
+ TSL2X7X_CMD_PROXALS_INT_CLR);
if (ret < 0)
- return ret;
+ dev_err(&chip->client->dev,
+ "%s: failed to clear interrupt status: %d\n",
+ __func__, ret);
return IRQ_HANDLED;
}
static struct attribute *tsl2x7x_ALS_device_attrs[] = {
- &dev_attr_in_illuminance0_calibscale_available.attr,
- &iio_const_attr_in_illuminance0_integration_time_available
- .dev_attr.attr,
+ &iio_const_attr_in_intensity0_calibscale_available.dev_attr.attr,
+ &iio_const_attr_in_intensity0_integration_time_available.dev_attr.attr,
&dev_attr_in_illuminance0_target_input.attr,
&dev_attr_in_illuminance0_calibrate.attr,
&dev_attr_in_illuminance0_lux_table.attr,
@@ -1472,9 +1279,8 @@ static struct attribute *tsl2x7x_PRX_device_attrs[] = {
};
static struct attribute *tsl2x7x_ALSPRX_device_attrs[] = {
- &dev_attr_in_illuminance0_calibscale_available.attr,
- &iio_const_attr_in_illuminance0_integration_time_available
- .dev_attr.attr,
+ &iio_const_attr_in_intensity0_calibscale_available.dev_attr.attr,
+ &iio_const_attr_in_intensity0_integration_time_available.dev_attr.attr,
&dev_attr_in_illuminance0_target_input.attr,
&dev_attr_in_illuminance0_calibrate.attr,
&dev_attr_in_illuminance0_lux_table.attr,
@@ -1488,9 +1294,8 @@ static struct attribute *tsl2x7x_PRX2_device_attrs[] = {
};
static struct attribute *tsl2x7x_ALSPRX2_device_attrs[] = {
- &dev_attr_in_illuminance0_calibscale_available.attr,
- &iio_const_attr_in_illuminance0_integration_time_available
- .dev_attr.attr,
+ &iio_const_attr_in_intensity0_calibscale_available.dev_attr.attr,
+ &iio_const_attr_in_intensity0_integration_time_available.dev_attr.attr,
&dev_attr_in_illuminance0_target_input.attr,
&dev_attr_in_illuminance0_calibrate.attr,
&dev_attr_in_illuminance0_lux_table.attr,
@@ -1569,34 +1374,33 @@ static const struct iio_event_spec tsl2x7x_events[] = {
{
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_RISING,
- .mask_separate = BIT(IIO_EV_INFO_VALUE) |
- BIT(IIO_EV_INFO_ENABLE),
+ .mask_separate = BIT(IIO_EV_INFO_VALUE),
}, {
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_FALLING,
- .mask_separate = BIT(IIO_EV_INFO_VALUE) |
- BIT(IIO_EV_INFO_ENABLE),
+ .mask_separate = BIT(IIO_EV_INFO_VALUE),
}, {
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_EITHER,
- .mask_separate = BIT(IIO_EV_INFO_PERIOD),
+ .mask_separate = BIT(IIO_EV_INFO_PERIOD) |
+ BIT(IIO_EV_INFO_ENABLE),
},
};
static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = {
[ALS] = {
- .channel = {
+ .channel_with_events = {
{
.type = IIO_LIGHT,
.indexed = 1,
.channel = 0,
- .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
- BIT(IIO_CHAN_INFO_INT_TIME),
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
}, {
.type = IIO_INTENSITY,
.indexed = 1,
.channel = 0,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_INT_TIME) |
BIT(IIO_CHAN_INFO_CALIBSCALE) |
BIT(IIO_CHAN_INFO_CALIBBIAS),
.event_spec = tsl2x7x_events,
@@ -1607,11 +1411,31 @@ static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = {
.channel = 1,
},
},
- .chan_table_elements = 3,
- .info = &tsl2X7X_device_info[ALS],
+ .channel_without_events = {
+ {
+ .type = IIO_LIGHT,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+ }, {
+ .type = IIO_INTENSITY,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_INT_TIME) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE) |
+ BIT(IIO_CHAN_INFO_CALIBBIAS),
+ }, {
+ .type = IIO_INTENSITY,
+ .indexed = 1,
+ .channel = 1,
+ },
+ },
+ .chan_table_elements = 3,
+ .info = &tsl2X7X_device_info[ALS],
},
[PRX] = {
- .channel = {
+ .channel_with_events = {
{
.type = IIO_PROXIMITY,
.indexed = 1,
@@ -1621,22 +1445,30 @@ static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = {
.num_event_specs = ARRAY_SIZE(tsl2x7x_events),
},
},
- .chan_table_elements = 1,
- .info = &tsl2X7X_device_info[PRX],
+ .channel_without_events = {
+ {
+ .type = IIO_PROXIMITY,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ },
+ },
+ .chan_table_elements = 1,
+ .info = &tsl2X7X_device_info[PRX],
},
[ALSPRX] = {
- .channel = {
+ .channel_with_events = {
{
.type = IIO_LIGHT,
.indexed = 1,
.channel = 0,
- .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
- BIT(IIO_CHAN_INFO_INT_TIME),
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
}, {
.type = IIO_INTENSITY,
.indexed = 1,
.channel = 0,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_INT_TIME) |
BIT(IIO_CHAN_INFO_CALIBSCALE) |
BIT(IIO_CHAN_INFO_CALIBBIAS),
.event_spec = tsl2x7x_events,
@@ -1655,11 +1487,37 @@ static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = {
.num_event_specs = ARRAY_SIZE(tsl2x7x_events),
},
},
- .chan_table_elements = 4,
- .info = &tsl2X7X_device_info[ALSPRX],
+ .channel_without_events = {
+ {
+ .type = IIO_LIGHT,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+ }, {
+ .type = IIO_INTENSITY,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_INT_TIME) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE) |
+ BIT(IIO_CHAN_INFO_CALIBBIAS),
+ }, {
+ .type = IIO_INTENSITY,
+ .indexed = 1,
+ .channel = 1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ }, {
+ .type = IIO_PROXIMITY,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ },
+ },
+ .chan_table_elements = 4,
+ .info = &tsl2X7X_device_info[ALSPRX],
},
[PRX2] = {
- .channel = {
+ .channel_with_events = {
{
.type = IIO_PROXIMITY,
.indexed = 1,
@@ -1670,22 +1528,31 @@ static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = {
.num_event_specs = ARRAY_SIZE(tsl2x7x_events),
},
},
- .chan_table_elements = 1,
- .info = &tsl2X7X_device_info[PRX2],
+ .channel_without_events = {
+ {
+ .type = IIO_PROXIMITY,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE),
+ },
+ },
+ .chan_table_elements = 1,
+ .info = &tsl2X7X_device_info[PRX2],
},
[ALSPRX2] = {
- .channel = {
+ .channel_with_events = {
{
.type = IIO_LIGHT,
.indexed = 1,
.channel = 0,
- .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
- BIT(IIO_CHAN_INFO_INT_TIME),
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
}, {
.type = IIO_INTENSITY,
.indexed = 1,
.channel = 0,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_INT_TIME) |
BIT(IIO_CHAN_INFO_CALIBSCALE) |
BIT(IIO_CHAN_INFO_CALIBBIAS),
.event_spec = tsl2x7x_events,
@@ -1705,17 +1572,44 @@ static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = {
.num_event_specs = ARRAY_SIZE(tsl2x7x_events),
},
},
- .chan_table_elements = 4,
- .info = &tsl2X7X_device_info[ALSPRX2],
+ .channel_without_events = {
+ {
+ .type = IIO_LIGHT,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+ }, {
+ .type = IIO_INTENSITY,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_INT_TIME) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE) |
+ BIT(IIO_CHAN_INFO_CALIBBIAS),
+ }, {
+ .type = IIO_INTENSITY,
+ .indexed = 1,
+ .channel = 1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ }, {
+ .type = IIO_PROXIMITY,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE),
+ },
+ },
+ .chan_table_elements = 4,
+ .info = &tsl2X7X_device_info[ALSPRX2],
},
};
static int tsl2x7x_probe(struct i2c_client *clientp,
const struct i2c_device_id *id)
{
- int ret;
struct iio_dev *indio_dev;
struct tsl2X7X_chip *chip;
+ int ret;
indio_dev = devm_iio_device_alloc(&clientp->dev, sizeof(*chip));
if (!indio_dev)
@@ -1730,8 +1624,7 @@ static int tsl2x7x_probe(struct i2c_client *clientp,
if (ret < 0)
return ret;
- if ((!tsl2x7x_device_id(&ret, id->driver_data)) ||
- (tsl2x7x_device_id(&ret, id->driver_data) == -EINVAL)) {
+ if (tsl2x7x_device_id_verif(ret, id->driver_data) <= 0) {
dev_info(&chip->client->dev,
"%s: i2c device found does not match expected id\n",
__func__);
@@ -1740,15 +1633,12 @@ static int tsl2x7x_probe(struct i2c_client *clientp,
ret = i2c_smbus_write_byte(clientp, TSL2X7X_CMD_REG | TSL2X7X_CNTRL);
if (ret < 0) {
- dev_err(&clientp->dev, "write to cmd reg failed. err = %d\n",
- ret);
+ dev_err(&clientp->dev,
+ "%s: Failed to write to CMD register: %d\n",
+ __func__, ret);
return ret;
}
- /*
- * ALS and PROX functions can be invoked via user space poll
- * or H/W interrupt. If busy return last sample.
- */
mutex_init(&chip->als_mutex);
mutex_init(&chip->prox_mutex);
@@ -1762,27 +1652,28 @@ static int tsl2x7x_probe(struct i2c_client *clientp,
indio_dev->dev.parent = &clientp->dev;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->name = chip->client->name;
- indio_dev->channels = chip->chip_info->channel;
indio_dev->num_channels = chip->chip_info->chan_table_elements;
if (clientp->irq) {
+ indio_dev->channels = chip->chip_info->channel_with_events;
+
ret = devm_request_threaded_irq(&clientp->dev, clientp->irq,
NULL,
&tsl2x7x_event_handler,
- IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING |
IRQF_ONESHOT,
"TSL2X7X_event",
indio_dev);
if (ret) {
dev_err(&clientp->dev,
- "%s: irq request failed", __func__);
+ "%s: irq request failed\n", __func__);
return ret;
}
+ } else {
+ indio_dev->channels = chip->chip_info->channel_without_events;
}
- /* Load up the defaults */
tsl2x7x_defaults(chip);
- /* Make sure the chip is on */
tsl2x7x_chip_on(indio_dev);
ret = iio_device_register(indio_dev);
@@ -1792,35 +1683,21 @@ static int tsl2x7x_probe(struct i2c_client *clientp,
return ret;
}
- dev_info(&clientp->dev, "%s Light sensor found.\n", id->name);
-
return 0;
}
static int tsl2x7x_suspend(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
- struct tsl2X7X_chip *chip = iio_priv(indio_dev);
- int ret = 0;
-
- if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING) {
- ret = tsl2x7x_chip_off(indio_dev);
- chip->tsl2x7x_chip_status = TSL2X7X_CHIP_SUSPENDED;
- }
- return ret;
+ return tsl2x7x_chip_off(indio_dev);
}
static int tsl2x7x_resume(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
- struct tsl2X7X_chip *chip = iio_priv(indio_dev);
- int ret = 0;
- if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_SUSPENDED)
- ret = tsl2x7x_chip_on(indio_dev);
-
- return ret;
+ return tsl2x7x_chip_on(indio_dev);
}
static int tsl2x7x_remove(struct i2c_client *client)
@@ -1870,7 +1747,6 @@ static const struct dev_pm_ops tsl2x7x_pm_ops = {
.resume = tsl2x7x_resume,
};
-/* Driver definition */
static struct i2c_driver tsl2x7x_driver = {
.driver = {
.name = "tsl2x7x",
@@ -1884,6 +1760,7 @@ static struct i2c_driver tsl2x7x_driver = {
module_i2c_driver(tsl2x7x_driver);
-MODULE_AUTHOR("J. August Brenner<jbrenner@taosinc.com>");
+MODULE_AUTHOR("J. August Brenner <Jon.Brenner@ams.com>");
+MODULE_AUTHOR("Brian Masney <masneyb@onstation.org>");
MODULE_DESCRIPTION("TAOS tsl2x7x ambient and proximity light sensor driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/iio/light/tsl2x7x.h b/drivers/staging/iio/light/tsl2x7x.h
index 28b0e7fdc9b8..1097ee890ce2 100644
--- a/drivers/staging/iio/light/tsl2x7x.h
+++ b/drivers/staging/iio/light/tsl2x7x.h
@@ -1,79 +1,85 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Device driver for monitoring ambient light intensity (lux)
* and proximity (prox) within the TAOS TSL2X7X family of devices.
*
* Copyright (c) 2012, TAOS Corporation.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __TSL2X7X_H
#define __TSL2X7X_H
struct tsl2x7x_lux {
- unsigned int ratio;
unsigned int ch0;
unsigned int ch1;
};
/* Max number of segments allowable in LUX table */
-#define TSL2X7X_MAX_LUX_TABLE_SIZE 9
+#define TSL2X7X_MAX_LUX_TABLE_SIZE 6
/* The default LUX tables all have 3 elements. */
#define TSL2X7X_DEF_LUX_TABLE_SZ 3
#define TSL2X7X_DEFAULT_TABLE_BYTES (sizeof(struct tsl2x7x_lux) * \
TSL2X7X_DEF_LUX_TABLE_SZ)
+/* Proximity diode to use */
+#define TSL2X7X_DIODE0 0x01
+#define TSL2X7X_DIODE1 0x02
+#define TSL2X7X_DIODE_BOTH 0x03
+
+/* LED Power */
+#define TSL2X7X_100_mA 0x00
+#define TSL2X7X_50_mA 0x01
+#define TSL2X7X_25_mA 0x02
+#define TSL2X7X_13_mA 0x03
+#define TSL2X7X_MAX_TIMER_CNT 0xFF
+
/**
- * struct tsl2x7x_default_settings - power on defaults unless
- * overridden by platform data.
- * @als_time: ALS Integration time - multiple of 50mS
- * @als_gain: Index into the ALS gain table.
- * @als_gain_trim: default gain trim to account for
- * aperture effects.
- * @wait_time: Time between PRX and ALS cycles
- * in 2.7 periods
- * @prx_time: 5.2ms prox integration time -
- * decrease in 2.7ms periods
- * @prx_gain: Proximity gain index
- * @prox_config: Prox configuration filters.
- * @als_cal_target: Known external ALS reading for
- * calibration.
- * @interrupts_en: Enable/Disable - 0x00 = none, 0x10 = als,
- * 0x20 = prx, 0x30 = bth
- * @persistence: H/W Filters, Number of 'out of limits'
- * ADC readings PRX/ALS.
+ * struct tsl2x7x_settings - Settings for the tsl2x7x driver
+ * @als_time: Integration time of the ALS channel ADCs in 2.73 ms
+ * increments. Total integration time is
+ * (256 - als_time) * 2.73.
+ * @als_gain: Index into the tsl2x7x_als_gain array.
+ * @als_gain_trim: Default gain trim to account for aperture effects.
+ * @wait_time: Time between proximity and ALS cycles in 2.73
+ * periods.
+ * @prox_time: Integration time of the proximity ADC in 2.73 ms
+ * increments. Total integration time is
+ * (256 - prx_time) * 2.73.
+ * @prox_gain: Index into the tsl2x7x_prx_gain array.
+ * @als_prox_config: The value of the ALS / Proximity configuration
+ * register.
+ * @als_cal_target: Known external ALS reading for calibration.
+ * @als_persistence: H/W Filters, Number of 'out of limits' ALS readings.
+ * @als_interrupt_en: Enable/Disable ALS interrupts
* @als_thresh_low: CH0 'low' count to trigger interrupt.
* @als_thresh_high: CH0 'high' count to trigger interrupt.
+ * @prox_persistence: H/W Filters, Number of 'out of limits' proximity
+ * readings.
+ * @prox_interrupt_en: Enable/Disable proximity interrupts.
* @prox_thres_low: Low threshold proximity detection.
- * @prox_thres_high: High threshold proximity detection
- * @prox_pulse_count: Number if proximity emitter pulses
- * @prox_max_samples_cal: Used for prox cal.
+ * @prox_thres_high: High threshold proximity detection.
+ * @prox_pulse_count: Number if proximity emitter pulses.
+ * @prox_max_samples_cal: The number of samples that are taken when performing
+ * a proximity calibration.
+ * @prox_diode Which diode(s) to use for driving the external
+ * LED(s) for proximity sensing.
+ * @prox_power The amount of power to use for the external LED(s).
*/
struct tsl2x7x_settings {
int als_time;
int als_gain;
int als_gain_trim;
int wait_time;
- int prx_time;
+ int prox_time;
int prox_gain;
- int prox_config;
+ int als_prox_config;
int als_cal_target;
- u8 interrupts_en;
- u8 persistence;
+ u8 als_persistence;
+ bool als_interrupt_en;
int als_thresh_low;
int als_thresh_high;
+ u8 prox_persistence;
+ bool prox_interrupt_en;
int prox_thres_low;
int prox_thres_high;
int prox_pulse_count;
@@ -84,9 +90,6 @@ struct tsl2x7x_settings {
/**
* struct tsl2X7X_platform_data - Platform callback, glass and defaults
- * @platform_power: Suspend/resume platform callback
- * @power_on: Power on callback
- * @power_off: Power off callback
* @platform_lux_table: Device specific glass coefficents
* @platform_default_settings: Device specific power on defaults
*
diff --git a/drivers/staging/iio/meter/ade7854-i2c.c b/drivers/staging/iio/meter/ade7854-i2c.c
index 317e4f0d8176..c3aa6ea9d036 100644
--- a/drivers/staging/iio/meter/ade7854-i2c.c
+++ b/drivers/staging/iio/meter/ade7854-i2c.c
@@ -15,91 +15,60 @@
#include <linux/iio/iio.h>
#include "ade7854.h"
-static int ade7854_i2c_write_reg_8(struct device *dev,
- u16 reg_address,
- u8 val)
+static int ade7854_i2c_write_reg(struct device *dev,
+ u16 reg_address,
+ u32 val,
+ int bits)
{
int ret;
+ int count;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
st->tx[0] = (reg_address >> 8) & 0xFF;
st->tx[1] = reg_address & 0xFF;
- st->tx[2] = val;
- ret = i2c_master_send(st->i2c, st->tx, 3);
+ switch (bits) {
+ case 8:
+ st->tx[2] = val & 0xFF;
+ count = 3;
+ break;
+ case 16:
+ st->tx[2] = (val >> 8) & 0xFF;
+ st->tx[3] = val & 0xFF;
+ count = 4;
+ break;
+ case 24:
+ st->tx[2] = (val >> 16) & 0xFF;
+ st->tx[3] = (val >> 8) & 0xFF;
+ st->tx[4] = val & 0xFF;
+ count = 5;
+ break;
+ case 32:
+ st->tx[2] = (val >> 24) & 0xFF;
+ st->tx[3] = (val >> 16) & 0xFF;
+ st->tx[4] = (val >> 8) & 0xFF;
+ st->tx[5] = val & 0xFF;
+ count = 6;
+ break;
+ default:
+ ret = -EINVAL;
+ goto unlock;
+ }
+
+ ret = i2c_master_send(st->i2c, st->tx, count);
+
+unlock:
mutex_unlock(&st->buf_lock);
- return ret;
+ return ret < 0 ? ret : 0;
}
-static int ade7854_i2c_write_reg_16(struct device *dev,
- u16 reg_address,
- u16 val)
-{
- int ret;
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct ade7854_state *st = iio_priv(indio_dev);
-
- mutex_lock(&st->buf_lock);
- st->tx[0] = (reg_address >> 8) & 0xFF;
- st->tx[1] = reg_address & 0xFF;
- st->tx[2] = (val >> 8) & 0xFF;
- st->tx[3] = val & 0xFF;
-
- ret = i2c_master_send(st->i2c, st->tx, 4);
- mutex_unlock(&st->buf_lock);
-
- return ret;
-}
-
-static int ade7854_i2c_write_reg_24(struct device *dev,
- u16 reg_address,
- u32 val)
-{
- int ret;
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct ade7854_state *st = iio_priv(indio_dev);
-
- mutex_lock(&st->buf_lock);
- st->tx[0] = (reg_address >> 8) & 0xFF;
- st->tx[1] = reg_address & 0xFF;
- st->tx[2] = (val >> 16) & 0xFF;
- st->tx[3] = (val >> 8) & 0xFF;
- st->tx[4] = val & 0xFF;
-
- ret = i2c_master_send(st->i2c, st->tx, 5);
- mutex_unlock(&st->buf_lock);
-
- return ret;
-}
-
-static int ade7854_i2c_write_reg_32(struct device *dev,
- u16 reg_address,
- u32 val)
-{
- int ret;
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct ade7854_state *st = iio_priv(indio_dev);
-
- mutex_lock(&st->buf_lock);
- st->tx[0] = (reg_address >> 8) & 0xFF;
- st->tx[1] = reg_address & 0xFF;
- st->tx[2] = (val >> 24) & 0xFF;
- st->tx[3] = (val >> 16) & 0xFF;
- st->tx[4] = (val >> 8) & 0xFF;
- st->tx[5] = val & 0xFF;
-
- ret = i2c_master_send(st->i2c, st->tx, 6);
- mutex_unlock(&st->buf_lock);
-
- return ret;
-}
-
-static int ade7854_i2c_read_reg_8(struct device *dev,
- u16 reg_address,
- u8 *val)
+static int ade7854_i2c_read_reg(struct device *dev,
+ u16 reg_address,
+ u32 *val,
+ int bits)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
@@ -110,94 +79,33 @@ static int ade7854_i2c_read_reg_8(struct device *dev,
st->tx[1] = reg_address & 0xFF;
ret = i2c_master_send(st->i2c, st->tx, 2);
- if (ret)
- goto out;
-
- ret = i2c_master_recv(st->i2c, st->rx, 1);
- if (ret)
- goto out;
-
- *val = st->rx[0];
-out:
- mutex_unlock(&st->buf_lock);
- return ret;
-}
-
-static int ade7854_i2c_read_reg_16(struct device *dev,
- u16 reg_address,
- u16 *val)
-{
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct ade7854_state *st = iio_priv(indio_dev);
- int ret;
-
- mutex_lock(&st->buf_lock);
- st->tx[0] = (reg_address >> 8) & 0xFF;
- st->tx[1] = reg_address & 0xFF;
-
- ret = i2c_master_send(st->i2c, st->tx, 2);
- if (ret)
- goto out;
-
- ret = i2c_master_recv(st->i2c, st->rx, 2);
- if (ret)
- goto out;
-
- *val = (st->rx[0] << 8) | st->rx[1];
-out:
- mutex_unlock(&st->buf_lock);
- return ret;
-}
-
-static int ade7854_i2c_read_reg_24(struct device *dev,
- u16 reg_address,
- u32 *val)
-{
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct ade7854_state *st = iio_priv(indio_dev);
- int ret;
-
- mutex_lock(&st->buf_lock);
- st->tx[0] = (reg_address >> 8) & 0xFF;
- st->tx[1] = reg_address & 0xFF;
-
- ret = i2c_master_send(st->i2c, st->tx, 2);
- if (ret)
- goto out;
-
- ret = i2c_master_recv(st->i2c, st->rx, 3);
- if (ret)
- goto out;
-
- *val = (st->rx[0] << 16) | (st->rx[1] << 8) | st->rx[2];
-out:
- mutex_unlock(&st->buf_lock);
- return ret;
-}
-
-static int ade7854_i2c_read_reg_32(struct device *dev,
- u16 reg_address,
- u32 *val)
-{
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct ade7854_state *st = iio_priv(indio_dev);
- int ret;
-
- mutex_lock(&st->buf_lock);
- st->tx[0] = (reg_address >> 8) & 0xFF;
- st->tx[1] = reg_address & 0xFF;
-
- ret = i2c_master_send(st->i2c, st->tx, 2);
- if (ret)
- goto out;
-
- ret = i2c_master_recv(st->i2c, st->rx, 3);
- if (ret)
- goto out;
-
- *val = (st->rx[0] << 24) | (st->rx[1] << 16) |
- (st->rx[2] << 8) | st->rx[3];
-out:
+ if (ret < 0)
+ goto unlock;
+
+ ret = i2c_master_recv(st->i2c, st->rx, bits);
+ if (ret < 0)
+ goto unlock;
+
+ switch (bits) {
+ case 8:
+ *val = st->rx[0];
+ break;
+ case 16:
+ *val = (st->rx[0] << 8) | st->rx[1];
+ break;
+ case 24:
+ *val = (st->rx[0] << 16) | (st->rx[1] << 8) | st->rx[2];
+ break;
+ case 32:
+ *val = (st->rx[0] << 24) | (st->rx[1] << 16) |
+ (st->rx[2] << 8) | st->rx[3];
+ break;
+ default:
+ ret = -EINVAL;
+ goto unlock;
+ }
+
+unlock:
mutex_unlock(&st->buf_lock);
return ret;
}
@@ -213,14 +121,8 @@ static int ade7854_i2c_probe(struct i2c_client *client,
return -ENOMEM;
st = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
- st->read_reg_8 = ade7854_i2c_read_reg_8;
- st->read_reg_16 = ade7854_i2c_read_reg_16;
- st->read_reg_24 = ade7854_i2c_read_reg_24;
- st->read_reg_32 = ade7854_i2c_read_reg_32;
- st->write_reg_8 = ade7854_i2c_write_reg_8;
- st->write_reg_16 = ade7854_i2c_write_reg_16;
- st->write_reg_24 = ade7854_i2c_write_reg_24;
- st->write_reg_32 = ade7854_i2c_write_reg_32;
+ st->read_reg = ade7854_i2c_read_reg;
+ st->write_reg = ade7854_i2c_write_reg;
st->i2c = client;
st->irq = client->irq;
diff --git a/drivers/staging/iio/meter/ade7854-spi.c b/drivers/staging/iio/meter/ade7854-spi.c
index 4419b8f06197..fc9146757283 100644
--- a/drivers/staging/iio/meter/ade7854-spi.c
+++ b/drivers/staging/iio/meter/ade7854-spi.c
@@ -15,9 +15,10 @@
#include <linux/iio/iio.h>
#include "ade7854.h"
-static int ade7854_spi_write_reg_8(struct device *dev,
- u16 reg_address,
- u8 val)
+static int ade7854_spi_write_reg(struct device *dev,
+ u16 reg_address,
+ u32 val,
+ int bits)
{
int ret;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
@@ -32,173 +33,44 @@ static int ade7854_spi_write_reg_8(struct device *dev,
st->tx[0] = ADE7854_WRITE_REG;
st->tx[1] = (reg_address >> 8) & 0xFF;
st->tx[2] = reg_address & 0xFF;
- st->tx[3] = val & 0xFF;
-
- ret = spi_sync_transfer(st->spi, &xfer, 1);
- mutex_unlock(&st->buf_lock);
-
- return ret;
-}
-
-static int ade7854_spi_write_reg_16(struct device *dev,
- u16 reg_address,
- u16 val)
-{
- int ret;
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct ade7854_state *st = iio_priv(indio_dev);
- struct spi_transfer xfer = {
- .tx_buf = st->tx,
- .bits_per_word = 8,
- .len = 5,
- };
-
- mutex_lock(&st->buf_lock);
- st->tx[0] = ADE7854_WRITE_REG;
- st->tx[1] = (reg_address >> 8) & 0xFF;
- st->tx[2] = reg_address & 0xFF;
- st->tx[3] = (val >> 8) & 0xFF;
- st->tx[4] = val & 0xFF;
-
- ret = spi_sync_transfer(st->spi, &xfer, 1);
- mutex_unlock(&st->buf_lock);
-
- return ret;
-}
-
-static int ade7854_spi_write_reg_24(struct device *dev,
- u16 reg_address,
- u32 val)
-{
- int ret;
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct ade7854_state *st = iio_priv(indio_dev);
- struct spi_transfer xfer = {
- .tx_buf = st->tx,
- .bits_per_word = 8,
- .len = 6,
- };
-
- mutex_lock(&st->buf_lock);
- st->tx[0] = ADE7854_WRITE_REG;
- st->tx[1] = (reg_address >> 8) & 0xFF;
- st->tx[2] = reg_address & 0xFF;
- st->tx[3] = (val >> 16) & 0xFF;
- st->tx[4] = (val >> 8) & 0xFF;
- st->tx[5] = val & 0xFF;
-
- ret = spi_sync_transfer(st->spi, &xfer, 1);
- mutex_unlock(&st->buf_lock);
-
- return ret;
-}
-
-static int ade7854_spi_write_reg_32(struct device *dev,
- u16 reg_address,
- u32 val)
-{
- int ret;
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct ade7854_state *st = iio_priv(indio_dev);
- struct spi_transfer xfer = {
- .tx_buf = st->tx,
- .bits_per_word = 8,
- .len = 7,
- };
-
- mutex_lock(&st->buf_lock);
- st->tx[0] = ADE7854_WRITE_REG;
- st->tx[1] = (reg_address >> 8) & 0xFF;
- st->tx[2] = reg_address & 0xFF;
- st->tx[3] = (val >> 24) & 0xFF;
- st->tx[4] = (val >> 16) & 0xFF;
- st->tx[5] = (val >> 8) & 0xFF;
- st->tx[6] = val & 0xFF;
-
- ret = spi_sync_transfer(st->spi, &xfer, 1);
- mutex_unlock(&st->buf_lock);
-
- return ret;
-}
-
-static int ade7854_spi_read_reg_8(struct device *dev,
- u16 reg_address,
- u8 *val)
-{
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct ade7854_state *st = iio_priv(indio_dev);
- int ret;
- struct spi_transfer xfers[] = {
- {
- .tx_buf = st->tx,
- .bits_per_word = 8,
- .len = 3,
- }, {
- .rx_buf = st->rx,
- .bits_per_word = 8,
- .len = 1,
- }
- };
-
- mutex_lock(&st->buf_lock);
-
- st->tx[0] = ADE7854_READ_REG;
- st->tx[1] = (reg_address >> 8) & 0xFF;
- st->tx[2] = reg_address & 0xFF;
-
- ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers));
- if (ret) {
- dev_err(&st->spi->dev, "problem when reading 8 bit register 0x%02X",
- reg_address);
- goto error_ret;
+ switch (bits) {
+ case 8:
+ st->tx[3] = val & 0xFF;
+ break;
+ case 16:
+ xfer.len = 5;
+ st->tx[3] = (val >> 8) & 0xFF;
+ st->tx[4] = val & 0xFF;
+ break;
+ case 24:
+ xfer.len = 6;
+ st->tx[3] = (val >> 16) & 0xFF;
+ st->tx[4] = (val >> 8) & 0xFF;
+ st->tx[5] = val & 0xFF;
+ break;
+ case 32:
+ xfer.len = 7;
+ st->tx[3] = (val >> 24) & 0xFF;
+ st->tx[4] = (val >> 16) & 0xFF;
+ st->tx[5] = (val >> 8) & 0xFF;
+ st->tx[6] = val & 0xFF;
+ break;
+ default:
+ ret = -EINVAL;
+ goto unlock;
}
- *val = st->rx[0];
-error_ret:
+ ret = spi_sync_transfer(st->spi, &xfer, 1);
+unlock:
mutex_unlock(&st->buf_lock);
- return ret;
-}
-
-static int ade7854_spi_read_reg_16(struct device *dev,
- u16 reg_address,
- u16 *val)
-{
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct ade7854_state *st = iio_priv(indio_dev);
- int ret;
- struct spi_transfer xfers[] = {
- {
- .tx_buf = st->tx,
- .bits_per_word = 8,
- .len = 3,
- }, {
- .rx_buf = st->rx,
- .bits_per_word = 8,
- .len = 2,
- }
- };
- mutex_lock(&st->buf_lock);
- st->tx[0] = ADE7854_READ_REG;
- st->tx[1] = (reg_address >> 8) & 0xFF;
- st->tx[2] = reg_address & 0xFF;
-
- ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers));
- if (ret) {
- dev_err(&st->spi->dev, "problem when reading 16 bit register 0x%02X",
- reg_address);
- goto error_ret;
- }
- *val = be16_to_cpup((const __be16 *)st->rx);
-
-error_ret:
- mutex_unlock(&st->buf_lock);
return ret;
}
-static int ade7854_spi_read_reg_24(struct device *dev,
- u16 reg_address,
- u32 *val)
+static int ade7854_spi_read_reg(struct device *dev,
+ u16 reg_address,
+ u32 *val,
+ int bits)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
@@ -211,7 +83,7 @@ static int ade7854_spi_read_reg_24(struct device *dev,
}, {
.rx_buf = st->rx,
.bits_per_word = 8,
- .len = 3,
+ .len = bits,
}
};
@@ -222,52 +94,28 @@ static int ade7854_spi_read_reg_24(struct device *dev,
st->tx[2] = reg_address & 0xFF;
ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers));
- if (ret) {
- dev_err(&st->spi->dev, "problem when reading 24 bit register 0x%02X",
+ if (ret < 0) {
+ dev_err(&st->spi->dev, "problem when reading register 0x%02X",
reg_address);
- goto error_ret;
+ goto unlock;
}
- *val = (st->rx[0] << 16) | (st->rx[1] << 8) | st->rx[2];
-
-error_ret:
- mutex_unlock(&st->buf_lock);
- return ret;
-}
-
-static int ade7854_spi_read_reg_32(struct device *dev,
- u16 reg_address,
- u32 *val)
-{
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct ade7854_state *st = iio_priv(indio_dev);
- int ret;
- struct spi_transfer xfers[] = {
- {
- .tx_buf = st->tx,
- .bits_per_word = 8,
- .len = 3,
- }, {
- .rx_buf = st->rx,
- .bits_per_word = 8,
- .len = 4,
- }
- };
-
- mutex_lock(&st->buf_lock);
- st->tx[0] = ADE7854_READ_REG;
- st->tx[1] = (reg_address >> 8) & 0xFF;
- st->tx[2] = reg_address & 0xFF;
-
- ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers));
- if (ret) {
- dev_err(&st->spi->dev, "problem when reading 32 bit register 0x%02X",
- reg_address);
- goto error_ret;
+ switch (bits) {
+ case 8:
+ *val = st->rx[0];
+ break;
+ case 16:
+ *val = be16_to_cpup((const __be16 *)st->rx);
+ break;
+ case 24:
+ *val = (st->rx[0] << 16) | (st->rx[1] << 8) | st->rx[2];
+ break;
+ case 32:
+ *val = be32_to_cpup((const __be32 *)st->rx);
+ break;
}
- *val = be32_to_cpup((const __be32 *)st->rx);
-error_ret:
+unlock:
mutex_unlock(&st->buf_lock);
return ret;
}
@@ -282,14 +130,8 @@ static int ade7854_spi_probe(struct spi_device *spi)
return -ENOMEM;
st = iio_priv(indio_dev);
spi_set_drvdata(spi, indio_dev);
- st->read_reg_8 = ade7854_spi_read_reg_8;
- st->read_reg_16 = ade7854_spi_read_reg_16;
- st->read_reg_24 = ade7854_spi_read_reg_24;
- st->read_reg_32 = ade7854_spi_read_reg_32;
- st->write_reg_8 = ade7854_spi_write_reg_8;
- st->write_reg_16 = ade7854_spi_write_reg_16;
- st->write_reg_24 = ade7854_spi_write_reg_24;
- st->write_reg_32 = ade7854_spi_write_reg_32;
+ st->read_reg = ade7854_spi_read_reg;
+ st->write_reg = ade7854_spi_write_reg;
st->irq = spi->irq;
st->spi = spi;
diff --git a/drivers/staging/iio/meter/ade7854.c b/drivers/staging/iio/meter/ade7854.c
index 90d07cdca4b8..029c3bf42d4d 100644
--- a/drivers/staging/iio/meter/ade7854.c
+++ b/drivers/staging/iio/meter/ade7854.c
@@ -27,13 +27,13 @@ static ssize_t ade7854_read_8bit(struct device *dev,
char *buf)
{
int ret;
- u8 val = 0;
+ u32 val = 0;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
- ret = st->read_reg_8(dev, this_attr->address, &val);
- if (ret)
+ ret = st->read_reg(dev, this_attr->address, &val, 8);
+ if (ret < 0)
return ret;
return sprintf(buf, "%u\n", val);
@@ -44,13 +44,13 @@ static ssize_t ade7854_read_16bit(struct device *dev,
char *buf)
{
int ret;
- u16 val = 0;
+ u32 val = 0;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
- ret = st->read_reg_16(dev, this_attr->address, &val);
- if (ret)
+ ret = st->read_reg(dev, this_attr->address, &val, 16);
+ if (ret < 0)
return ret;
return sprintf(buf, "%u\n", val);
@@ -66,8 +66,8 @@ static ssize_t ade7854_read_24bit(struct device *dev,
struct ade7854_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
- ret = st->read_reg_24(dev, this_attr->address, &val);
- if (ret)
+ ret = st->read_reg(dev, this_attr->address, &val, 24);
+ if (ret < 0)
return ret;
return sprintf(buf, "%u\n", val);
@@ -83,8 +83,8 @@ static ssize_t ade7854_read_32bit(struct device *dev,
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
- ret = st->read_reg_32(dev, this_attr->address, &val);
- if (ret)
+ ret = st->read_reg(dev, this_attr->address, &val, 32);
+ if (ret < 0)
return ret;
return sprintf(buf, "%u\n", val);
@@ -105,7 +105,7 @@ static ssize_t ade7854_write_8bit(struct device *dev,
ret = kstrtou8(buf, 10, &val);
if (ret)
goto error_ret;
- ret = st->write_reg_8(dev, this_attr->address, val);
+ ret = st->write_reg(dev, this_attr->address, val, 8);
error_ret:
return ret ? ret : len;
@@ -126,7 +126,7 @@ static ssize_t ade7854_write_16bit(struct device *dev,
ret = kstrtou16(buf, 10, &val);
if (ret)
goto error_ret;
- ret = st->write_reg_16(dev, this_attr->address, val);
+ ret = st->write_reg(dev, this_attr->address, val, 16);
error_ret:
return ret ? ret : len;
@@ -147,7 +147,7 @@ static ssize_t ade7854_write_24bit(struct device *dev,
ret = kstrtou32(buf, 10, &val);
if (ret)
goto error_ret;
- ret = st->write_reg_24(dev, this_attr->address, val);
+ ret = st->write_reg(dev, this_attr->address, val, 24);
error_ret:
return ret ? ret : len;
@@ -168,7 +168,7 @@ static ssize_t ade7854_write_32bit(struct device *dev,
ret = kstrtou32(buf, 10, &val);
if (ret)
goto error_ret;
- ret = st->write_reg_32(dev, this_attr->address, val);
+ ret = st->write_reg(dev, this_attr->address, val, 32);
error_ret:
return ret ? ret : len;
@@ -178,12 +178,12 @@ static int ade7854_reset(struct device *dev)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
- u16 val;
+ u32 val;
- st->read_reg_16(dev, ADE7854_CONFIG, &val);
+ st->read_reg(dev, ADE7854_CONFIG, &val, 16);
val |= BIT(7); /* Software Chip Reset */
- return st->write_reg_16(dev, ADE7854_CONFIG, val);
+ return st->write_reg(dev, ADE7854_CONFIG, val, 16);
}
static IIO_DEV_ATTR_AIGAIN(0644,
@@ -415,8 +415,8 @@ static int ade7854_set_irq(struct device *dev, bool enable)
int ret;
u32 irqen;
- ret = st->read_reg_32(dev, ADE7854_MASK0, &irqen);
- if (ret)
+ ret = st->read_reg(dev, ADE7854_MASK0, &irqen, 32);
+ if (ret < 0)
return ret;
if (enable)
@@ -426,7 +426,7 @@ static int ade7854_set_irq(struct device *dev, bool enable)
else
irqen &= ~BIT(17);
- return st->write_reg_32(dev, ADE7854_MASK0, irqen);
+ return st->write_reg(dev, ADE7854_MASK0, irqen, 32);
}
static int ade7854_initial_setup(struct iio_dev *indio_dev)
diff --git a/drivers/staging/iio/meter/ade7854.h b/drivers/staging/iio/meter/ade7854.h
index a82d38224cbd..a51e6e3183d3 100644
--- a/drivers/staging/iio/meter/ade7854.h
+++ b/drivers/staging/iio/meter/ade7854.h
@@ -145,7 +145,9 @@
/**
* struct ade7854_state - device instance specific data
- * @spi: actual spi_device
+ * @spi: actual spi_device
+ * @read_reg Wrapper function for I2C and SPI read
+ * @write_reg Wrapper function for I2C and SPI write
* @indio_dev: industrial I/O device structure
* @buf_lock: mutex to protect tx and rx
* @tx: transmit buffer
@@ -154,14 +156,10 @@
struct ade7854_state {
struct spi_device *spi;
struct i2c_client *i2c;
- int (*read_reg_8)(struct device *dev, u16 reg_address, u8 *val);
- int (*read_reg_16)(struct device *dev, u16 reg_address, u16 *val);
- int (*read_reg_24)(struct device *dev, u16 reg_address, u32 *val);
- int (*read_reg_32)(struct device *dev, u16 reg_address, u32 *val);
- int (*write_reg_8)(struct device *dev, u16 reg_address, u8 val);
- int (*write_reg_16)(struct device *dev, u16 reg_address, u16 val);
- int (*write_reg_24)(struct device *dev, u16 reg_address, u32 val);
- int (*write_reg_32)(struct device *dev, u16 reg_address, u32 val);
+ int (*read_reg)(struct device *dev, u16 reg_address, u32 *val,
+ int bits);
+ int (*write_reg)(struct device *dev, u16 reg_address, u32 val,
+ int bits);
int irq;
struct mutex buf_lock;
u8 tx[ADE7854_MAX_TX] ____cacheline_aligned;
diff --git a/drivers/staging/iio/resolver/ad2s1200.c b/drivers/staging/iio/resolver/ad2s1200.c
index aa62c64e9bc4..ea7336645116 100644
--- a/drivers/staging/iio/resolver/ad2s1200.c
+++ b/drivers/staging/iio/resolver/ad2s1200.c
@@ -9,16 +9,16 @@
* published by the Free Software Foundation.
*
*/
-#include <linux/types.h>
-#include <linux/mutex.h>
-#include <linux/device.h>
-#include <linux/spi/spi.h>
-#include <linux/slab.h>
-#include <linux/sysfs.h>
+
+#include <linux/bitops.h>
#include <linux/delay.h>
+#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/module.h>
-#include <linux/bitops.h>
+#include <linux/mutex.h>
+#include <linux/spi/spi.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@@ -38,7 +38,7 @@ struct ad2s1200_state {
struct spi_device *sdev;
int sample;
int rdvel;
- u8 rx[2] ____cacheline_aligned;
+ __be16 rx ____cacheline_aligned;
};
static int ad2s1200_read_raw(struct iio_dev *indio_dev,
@@ -47,17 +47,18 @@ static int ad2s1200_read_raw(struct iio_dev *indio_dev,
int *val2,
long m)
{
- int ret = 0;
- s16 vel;
struct ad2s1200_state *st = iio_priv(indio_dev);
+ int ret = 0;
mutex_lock(&st->lock);
gpio_set_value(st->sample, 0);
+
/* delay (6 * AD2S1200_TSCLK + 20) nano seconds */
udelay(1);
gpio_set_value(st->sample, 1);
gpio_set_value(st->rdvel, !!(chan->type == IIO_ANGL));
- ret = spi_read(st->sdev, st->rx, 2);
+
+ ret = spi_read(st->sdev, &st->rx, 2);
if (ret < 0) {
mutex_unlock(&st->lock);
return ret;
@@ -65,20 +66,20 @@ static int ad2s1200_read_raw(struct iio_dev *indio_dev,
switch (chan->type) {
case IIO_ANGL:
- *val = (((u16)(st->rx[0])) << 4) | ((st->rx[1] & 0xF0) >> 4);
+ *val = be16_to_cpup(&st->rx) >> 4;
break;
case IIO_ANGL_VEL:
- vel = (((s16)(st->rx[0])) << 4) | ((st->rx[1] & 0xF0) >> 4);
- vel = sign_extend32(vel, 11);
- *val = vel;
+ *val = sign_extend32(be16_to_cpup(&st->rx) >> 4, 11);
break;
default:
mutex_unlock(&st->lock);
return -EINVAL;
}
+
/* delay (2 * AD2S1200_TSCLK + 20) ns for sample pulse */
udelay(1);
mutex_unlock(&st->lock);
+
return IIO_VAL_INT;
}
@@ -102,10 +103,10 @@ static const struct iio_info ad2s1200_info = {
static int ad2s1200_probe(struct spi_device *spi)
{
+ unsigned short *pins = spi->dev.platform_data;
struct ad2s1200_state *st;
struct iio_dev *indio_dev;
int pn, ret = 0;
- unsigned short *pins = spi->dev.platform_data;
for (pn = 0; pn < AD2S1200_PN; pn++) {
ret = devm_gpio_request_one(&spi->dev, pins[pn], GPIOF_DIR_OUT,
@@ -116,9 +117,11 @@ static int ad2s1200_probe(struct spi_device *spi)
return ret;
}
}
+
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
+
spi_set_drvdata(spi, indio_dev);
st = iio_priv(indio_dev);
mutex_init(&st->lock);
diff --git a/include/linux/iio/adc/ad_sigma_delta.h b/include/linux/iio/adc/ad_sigma_delta.h
index 1fc7abd28b0b..730ead1a46df 100644
--- a/include/linux/iio/adc/ad_sigma_delta.h
+++ b/include/linux/iio/adc/ad_sigma_delta.h
@@ -127,7 +127,7 @@ void ad_sd_cleanup_buffer_and_trigger(struct iio_dev *indio_dev);
int ad_sd_validate_trigger(struct iio_dev *indio_dev, struct iio_trigger *trig);
#define __AD_SD_CHANNEL(_si, _channel1, _channel2, _address, _bits, \
- _storagebits, _shift, _extend_name, _type) \
+ _storagebits, _shift, _extend_name, _type, _mask_all) \
{ \
.type = (_type), \
.differential = (_channel2 == -1 ? 0 : 1), \
@@ -139,7 +139,7 @@ int ad_sd_validate_trigger(struct iio_dev *indio_dev, struct iio_trigger *trig);
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_OFFSET), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
- .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .info_mask_shared_by_all = _mask_all, \
.scan_index = (_si), \
.scan_type = { \
.sign = 'u', \
@@ -153,25 +153,35 @@ int ad_sd_validate_trigger(struct iio_dev *indio_dev, struct iio_trigger *trig);
#define AD_SD_DIFF_CHANNEL(_si, _channel1, _channel2, _address, _bits, \
_storagebits, _shift) \
__AD_SD_CHANNEL(_si, _channel1, _channel2, _address, _bits, \
- _storagebits, _shift, NULL, IIO_VOLTAGE)
+ _storagebits, _shift, NULL, IIO_VOLTAGE, \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ))
#define AD_SD_SHORTED_CHANNEL(_si, _channel, _address, _bits, \
_storagebits, _shift) \
__AD_SD_CHANNEL(_si, _channel, _channel, _address, _bits, \
- _storagebits, _shift, "shorted", IIO_VOLTAGE)
+ _storagebits, _shift, "shorted", IIO_VOLTAGE, \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ))
#define AD_SD_CHANNEL(_si, _channel, _address, _bits, \
_storagebits, _shift) \
__AD_SD_CHANNEL(_si, _channel, -1, _address, _bits, \
- _storagebits, _shift, NULL, IIO_VOLTAGE)
+ _storagebits, _shift, NULL, IIO_VOLTAGE, \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ))
+
+#define AD_SD_CHANNEL_NO_SAMP_FREQ(_si, _channel, _address, _bits, \
+ _storagebits, _shift) \
+ __AD_SD_CHANNEL(_si, _channel, -1, _address, _bits, \
+ _storagebits, _shift, NULL, IIO_VOLTAGE, 0)
#define AD_SD_TEMP_CHANNEL(_si, _address, _bits, _storagebits, _shift) \
__AD_SD_CHANNEL(_si, 0, -1, _address, _bits, \
- _storagebits, _shift, NULL, IIO_TEMP)
+ _storagebits, _shift, NULL, IIO_TEMP, \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ))
#define AD_SD_SUPPLY_CHANNEL(_si, _channel, _address, _bits, _storagebits, \
_shift) \
__AD_SD_CHANNEL(_si, _channel, -1, _address, _bits, \
- _storagebits, _shift, "supply", IIO_VOLTAGE)
+ _storagebits, _shift, "supply", IIO_VOLTAGE, \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ))
#endif
diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.h b/include/linux/iio/common/cros_ec_sensors_core.h
index 2edf68dc7336..ce16445411ac 100644
--- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.h
+++ b/include/linux/iio/common/cros_ec_sensors_core.h
@@ -16,7 +16,9 @@
#ifndef __CROS_EC_SENSORS_CORE_H
#define __CROS_EC_SENSORS_CORE_H
+#include <linux/iio/iio.h>
#include <linux/irqreturn.h>
+#include <linux/mfd/cros_ec.h>
enum {
CROS_EC_SENSOR_X,
@@ -103,6 +105,7 @@ int cros_ec_sensors_read_lpc(struct iio_dev *indio_dev, unsigned long scan_mask,
int cros_ec_sensors_read_cmd(struct iio_dev *indio_dev, unsigned long scan_mask,
s16 *data);
+struct platform_device;
/**
* cros_ec_sensors_core_init() - basic initialization of the core structure
* @pdev: platform device created for the sensors
diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
index 11579fd4126e..a74cb177dc6f 100644
--- a/include/linux/iio/iio.h
+++ b/include/linux/iio/iio.h
@@ -183,18 +183,18 @@ struct iio_event_spec {
* @address: Driver specific identifier.
* @scan_index: Monotonic index to give ordering in scans when read
* from a buffer.
- * @scan_type: sign: 's' or 'u' to specify signed or unsigned
- * realbits: Number of valid bits of data
- * storagebits: Realbits + padding
- * shift: Shift right by this before masking out
- * realbits.
- * repeat: Number of times real/storage bits
- * repeats. When the repeat element is
- * more than 1, then the type element in
- * sysfs will show a repeat value.
- * Otherwise, the number of repetitions is
- * omitted.
- * endianness: little or big endian
+ * @scan_type: struct describing the scan type
+ * @scan_type.sign: 's' or 'u' to specify signed or unsigned
+ * @scan_type.realbits: Number of valid bits of data
+ * @scan_type.storagebits: Realbits + padding
+ * @scan_type.shift: Shift right by this before masking out
+ * realbits.
+ * @scan_type.repeat: Number of times real/storage bits repeats.
+ * When the repeat element is more than 1, then
+ * the type element in sysfs will show a repeat
+ * value. Otherwise, the number of repetitions
+ * is omitted.
+ * @scan_type.endianness: little or big endian
* @info_mask_separate: What information is to be exported that is specific to
* this channel.
* @info_mask_separate_available: What availability information is to be