summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/sysfs-bus-iio-inv_icm4260018
-rw-r--r--Documentation/devicetree/bindings/iio/adc/adc.yaml19
-rw-r--r--Documentation/devicetree/bindings/iio/adc/adi,ad7192.yaml95
-rw-r--r--Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml148
-rw-r--r--Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.yaml3
-rw-r--r--Documentation/devicetree/bindings/iio/adc/ti,ads1015.yaml1
-rw-r--r--Documentation/devicetree/bindings/iio/chemical/sciosense,ens160.yaml70
-rw-r--r--Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml43
-rw-r--r--Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml31
-rw-r--r--Documentation/devicetree/bindings/iio/imu/adi,adis16480.yaml6
-rw-r--r--Documentation/devicetree/bindings/iio/imu/bosch,bmi160.yaml6
-rw-r--r--Documentation/devicetree/bindings/iio/light/vishay,veml6075.yaml9
-rw-r--r--Documentation/devicetree/bindings/vendor-prefixes.yaml2
-rw-r--r--Documentation/iio/adis16475.rst23
-rw-r--r--Documentation/iio/adis16480.rst443
-rw-r--r--Documentation/iio/iio_tools.rst27
-rw-r--r--Documentation/iio/index.rst2
-rw-r--r--MAINTAINERS19
-rw-r--r--drivers/char/lp.c1
-rw-r--r--drivers/char/nvram.c1
-rw-r--r--drivers/char/ppdev.c1
-rw-r--r--drivers/char/tlclk.c1
-rw-r--r--drivers/char/ttyprintk.c1
-rw-r--r--drivers/iio/accel/adxl313_spi.c8
-rw-r--r--drivers/iio/accel/adxl355_spi.c10
-rw-r--r--drivers/iio/accel/adxl367_i2c.c4
-rw-r--r--drivers/iio/accel/adxl372_i2c.c2
-rw-r--r--drivers/iio/accel/bma400_i2c.c2
-rw-r--r--drivers/iio/accel/bmi088-accel-core.c5
-rw-r--r--drivers/iio/accel/da311.c2
-rw-r--r--drivers/iio/accel/dmard06.c6
-rw-r--r--drivers/iio/accel/dmard09.c4
-rw-r--r--drivers/iio/accel/dmard10.c2
-rw-r--r--drivers/iio/accel/kxsd9-i2c.c4
-rw-r--r--drivers/iio/accel/mc3230.c2
-rw-r--r--drivers/iio/accel/mma7455_i2c.c4
-rw-r--r--drivers/iio/accel/mma7660.c52
-rw-r--r--drivers/iio/accel/mma9551.c2
-rw-r--r--drivers/iio/accel/mma9553.c4
-rw-r--r--drivers/iio/accel/mxc4005.c6
-rw-r--r--drivers/iio/accel/mxc6255.c4
-rw-r--r--drivers/iio/accel/stk8312.c4
-rw-r--r--drivers/iio/accel/stk8ba50.c2
-rw-r--r--drivers/iio/adc/Kconfig28
-rw-r--r--drivers/iio/adc/Makefile25
-rw-r--r--drivers/iio/adc/ad7192.c273
-rw-r--r--drivers/iio/adc/ad7291.c2
-rw-r--r--drivers/iio/adc/ad7380.c833
-rw-r--r--drivers/iio/adc/ad7606.c19
-rw-r--r--drivers/iio/adc/ad7944.c8
-rw-r--r--drivers/iio/adc/ad9467.c103
-rw-r--r--drivers/iio/adc/adi-axi-adc.c18
-rw-r--r--drivers/iio/adc/axp20x_adc.c279
-rw-r--r--drivers/iio/adc/ingenic-adc.c1
-rw-r--r--drivers/iio/adc/ltc2485.c2
-rw-r--r--drivers/iio/adc/max11205.c5
-rw-r--r--drivers/iio/adc/mcp3564.c6
-rw-r--r--drivers/iio/adc/nau7802.c2
-rw-r--r--drivers/iio/adc/pac1934.c5
-rw-r--r--drivers/iio/adc/ti-adc161s626.c18
-rw-r--r--drivers/iio/adc/ti-ads131e08.c4
-rw-r--r--drivers/iio/adc/ti-ads7924.c2
-rw-r--r--drivers/iio/adc/ti-tsc2046.c7
-rw-r--r--drivers/iio/adc/xilinx-ams.c1
-rw-r--r--drivers/iio/addac/ad74413r.c13
-rw-r--r--drivers/iio/buffer/kfifo_buf.c1
-rw-r--r--drivers/iio/chemical/Kconfig20
-rw-r--r--drivers/iio/chemical/Makefile3
-rw-r--r--drivers/iio/chemical/ams-iaq-core.c4
-rw-r--r--drivers/iio/chemical/bme680_i2c.c4
-rw-r--r--drivers/iio/chemical/ccs811.c2
-rw-r--r--drivers/iio/chemical/ens160.h10
-rw-r--r--drivers/iio/chemical/ens160_core.c367
-rw-r--r--drivers/iio/chemical/ens160_i2c.c62
-rw-r--r--drivers/iio/chemical/ens160_spi.c61
-rw-r--r--drivers/iio/dac/Kconfig1
-rw-r--r--drivers/iio/dac/ad3552r.c140
-rw-r--r--drivers/iio/dac/max5522.c11
-rw-r--r--drivers/iio/dac/mcp4728.c2
-rw-r--r--drivers/iio/frequency/adrf6780.c1
-rw-r--r--drivers/iio/gyro/bmg160_i2c.c6
-rw-r--r--drivers/iio/gyro/fxas21002c_i2c.c2
-rw-r--r--drivers/iio/gyro/itg3200_core.c2
-rw-r--r--drivers/iio/health/afe4404.c2
-rw-r--r--drivers/iio/health/max30100.c2
-rw-r--r--drivers/iio/humidity/am2315.c2
-rw-r--r--drivers/iio/humidity/hdc100x.c12
-rw-r--r--drivers/iio/humidity/si7005.c4
-rw-r--r--drivers/iio/humidity/si7020.c141
-rw-r--r--drivers/iio/imu/Kconfig4
-rw-r--r--drivers/iio/imu/adis16475.c807
-rw-r--r--drivers/iio/imu/adis16480.c393
-rw-r--r--drivers/iio/imu/adis_buffer.c32
-rw-r--r--drivers/iio/imu/adis_trigger.c37
-rw-r--r--drivers/iio/imu/bmi160/bmi160_core.c26
-rw-r--r--drivers/iio/imu/bmi160/bmi160_i2c.c5
-rw-r--r--drivers/iio/imu/bmi160/bmi160_spi.c3
-rw-r--r--drivers/iio/imu/bmi323/bmi323_core.c8
-rw-r--r--drivers/iio/imu/bno055/bno055_i2c.c2
-rw-r--r--drivers/iio/imu/fxos8700_i2c.c2
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600.h4
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c124
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_core.c71
-rw-r--r--drivers/iio/imu/kmx61.c2
-rw-r--r--drivers/iio/industrialio-buffer.c129
-rw-r--r--drivers/iio/industrialio-core.c7
-rw-r--r--drivers/iio/industrialio-event.c13
-rw-r--r--drivers/iio/industrialio-gts-helper.c7
-rw-r--r--drivers/iio/inkern.c32
-rw-r--r--drivers/iio/light/Kconfig11
-rw-r--r--drivers/iio/light/Makefile1
-rw-r--r--drivers/iio/light/adjd_s311.c2
-rw-r--r--drivers/iio/light/adux1020.c2
-rw-r--r--drivers/iio/light/al3320a.c2
-rw-r--r--drivers/iio/light/apds9300.c2
-rw-r--r--drivers/iio/light/apds9960.c2
-rw-r--r--drivers/iio/light/bh1780.c4
-rw-r--r--drivers/iio/light/cm3232.c2
-rw-r--r--drivers/iio/light/cm3323.c2
-rw-r--r--drivers/iio/light/cm36651.c2
-rw-r--r--drivers/iio/light/gp2ap002.c4
-rw-r--r--drivers/iio/light/gp2ap020a00f.c3
-rw-r--r--drivers/iio/light/isl29028.c4
-rw-r--r--drivers/iio/light/isl29125.c2
-rw-r--r--drivers/iio/light/jsa1212.c2
-rw-r--r--drivers/iio/light/lv0104cs.c2
-rw-r--r--drivers/iio/light/max44000.c2
-rw-r--r--drivers/iio/light/max44009.c2
-rw-r--r--drivers/iio/light/noa1305.c2
-rw-r--r--drivers/iio/light/opt3001.c2
-rw-r--r--drivers/iio/light/pa12203001.c2
-rw-r--r--drivers/iio/light/rohm-bu27034.c6
-rw-r--r--drivers/iio/light/rpr0521.c2
-rw-r--r--drivers/iio/light/si1133.c2
-rw-r--r--drivers/iio/light/stk3310.c37
-rw-r--r--drivers/iio/light/tcs3414.c2
-rw-r--r--drivers/iio/light/tcs3472.c2
-rw-r--r--drivers/iio/light/tsl4531.c2
-rw-r--r--drivers/iio/light/us5182d.c2
-rw-r--r--drivers/iio/light/vcnl4035.c2
-rw-r--r--drivers/iio/light/veml6030.c2
-rw-r--r--drivers/iio/light/veml6040.c281
-rw-r--r--drivers/iio/light/veml6070.c2
-rw-r--r--drivers/iio/light/vl6180.c2
-rw-r--r--drivers/iio/light/zopt2201.c2
-rw-r--r--drivers/iio/magnetometer/af8133j.c2
-rw-r--r--drivers/iio/magnetometer/ak8974.c8
-rw-r--r--drivers/iio/magnetometer/bmc150_magn_i2c.c6
-rw-r--r--drivers/iio/magnetometer/mag3110.c2
-rw-r--r--drivers/iio/magnetometer/mmc35240.c2
-rw-r--r--drivers/iio/magnetometer/tmag5273.c2
-rw-r--r--drivers/iio/multiplexer/iio-mux.c1
-rw-r--r--drivers/iio/potentiostat/lmp91000.c4
-rw-r--r--drivers/iio/pressure/bmp280-core.c783
-rw-r--r--drivers/iio/pressure/bmp280-regmap.c8
-rw-r--r--drivers/iio/pressure/bmp280-spi.c4
-rw-r--r--drivers/iio/pressure/bmp280.h65
-rw-r--r--drivers/iio/pressure/dps310.c2
-rw-r--r--drivers/iio/pressure/hp03.c4
-rw-r--r--drivers/iio/pressure/icp10100.c2
-rw-r--r--drivers/iio/pressure/mpl115_i2c.c2
-rw-r--r--drivers/iio/pressure/mpl3115.c2
-rw-r--r--drivers/iio/pressure/t5403.c2
-rw-r--r--drivers/iio/pressure/zpa2326_i2c.c4
-rw-r--r--drivers/iio/proximity/isl29501.c2
-rw-r--r--drivers/iio/proximity/pulsedlight-lidar-lite-v2.c6
-rw-r--r--drivers/iio/proximity/rfd77402.c2
-rw-r--r--drivers/iio/proximity/sx9500.c4
-rw-r--r--drivers/iio/proximity/vl53l0x-i2c.c2
-rw-r--r--drivers/iio/temperature/max30208.c1
-rw-r--r--drivers/iio/temperature/mcp9600.c363
-rw-r--r--drivers/iio/temperature/mlx90632.c2
-rw-r--r--drivers/iio/temperature/tmp006.c2
-rw-r--r--drivers/iio/temperature/tmp007.c2
-rw-r--r--drivers/iio/temperature/tsys01.c2
-rw-r--r--drivers/iio/temperature/tsys02d.c2
-rw-r--r--drivers/iio/test/iio-test-gts.c8
-rw-r--r--drivers/mcb/mcb-pci.c16
-rw-r--r--drivers/misc/eeprom/digsy_mtc_eeprom.c46
-rw-r--r--drivers/misc/eeprom/ee1004.c2
-rw-r--r--drivers/misc/eeprom/eeprom_93xx46.c178
-rw-r--r--drivers/misc/eeprom/idt_89hpesx.c104
-rw-r--r--drivers/misc/eeprom/max6875.c2
-rw-r--r--drivers/misc/open-dice.c1
-rw-r--r--drivers/parport/share.c1
-rw-r--r--drivers/siox/siox-bus-gpio.c1
-rw-r--r--drivers/staging/iio/addac/adt7316-i2c.c12
-rw-r--r--drivers/staging/iio/addac/adt7316.c9
-rw-r--r--drivers/staging/iio/impedance-analyzer/ad5933.c4
-rw-r--r--drivers/uio/uio.c1
-rw-r--r--drivers/uio/uio_aec.c1
-rw-r--r--drivers/uio/uio_cif.c1
-rw-r--r--drivers/uio/uio_mf624.c3
-rw-r--r--drivers/uio/uio_netx.c1
-rw-r--r--include/linux/eeprom_93xx46.h32
-rw-r--r--include/linux/iio/iio.h94
-rw-r--r--include/linux/iio/imu/adis.h21
-rw-r--r--lib/math/prime_numbers.c1
-rw-r--r--lib/math/rational-test.c1
-rw-r--r--lib/test_dynamic_debug.c1
200 files changed, 6222 insertions, 1342 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-iio-inv_icm42600 b/Documentation/ABI/testing/sysfs-bus-iio-inv_icm42600
new file mode 100644
index 000000000000..7eeacfb7650d
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-iio-inv_icm42600
@@ -0,0 +1,18 @@
+What: /sys/bus/iio/devices/iio:deviceX/in_accel_power_mode
+KernelVersion: 6.11
+Contact: linux-iio@vger.kernel.org
+Description:
+ Accelerometer power mode. Setting this attribute will set the
+ requested power mode to use if the ODR support it. If ODR
+ support only 1 mode, power mode will be enforced.
+ Reading this attribute will return the current accelerometer
+ power mode if the sensor is on, or the requested value if the
+ sensor is off. The value between real and requested value can
+ be different for ODR supporting only 1 mode.
+
+What: /sys/bus/iio/devices/iio:deviceX/in_accel_power_mode_available
+KernelVersion: 6.11
+Contact: linux-iio@vger.kernel.org
+Description:
+ List of available accelerometer power modes that can be set in
+ in_accel_power_mode attribute.
diff --git a/Documentation/devicetree/bindings/iio/adc/adc.yaml b/Documentation/devicetree/bindings/iio/adc/adc.yaml
index 36775f8f71df..0a77592f7388 100644
--- a/Documentation/devicetree/bindings/iio/adc/adc.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/adc.yaml
@@ -38,6 +38,14 @@ properties:
The first value specifies the positive input pin, the second
specifies the negative input pin.
+ single-channel:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ When devices combine single-ended and differential channels, allow the
+ channel for a single element to be specified, independent of reg (as for
+ differential channels). If this and diff-channels are not present reg
+ shall be used instead.
+
settling-time-us:
description:
Time between enabling the channel and first stable readings.
@@ -50,4 +58,15 @@ properties:
device design and can interact with other characteristics such as
settling time.
+anyOf:
+ - oneOf:
+ - required:
+ - reg
+ - diff-channels
+ - required:
+ - reg
+ - single-channel
+ - required:
+ - reg
+
additionalProperties: true
diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7192.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7192.yaml
index 16def2985ab4..a03da9489ed9 100644
--- a/Documentation/devicetree/bindings/iio/adc/adi,ad7192.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7192.yaml
@@ -21,8 +21,15 @@ properties:
- adi,ad7190
- adi,ad7192
- adi,ad7193
+ - adi,ad7194
- adi,ad7195
+ "#address-cells":
+ const: 1
+
+ "#size-cells":
+ const: 0
+
reg:
maxItems: 1
@@ -41,6 +48,11 @@ properties:
interrupts:
maxItems: 1
+ aincom-supply:
+ description: |
+ AINCOM voltage supply. Analog inputs AINx are referenced to this input
+ when configured for pseudo-differential operation.
+
dvdd-supply:
description: DVdd voltage supply
@@ -84,6 +96,42 @@ properties:
description: see Documentation/devicetree/bindings/iio/adc/adc.yaml
type: boolean
+patternProperties:
+ "^channel@[0-9a-f]+$":
+ type: object
+ $ref: adc.yaml
+ unevaluatedProperties: false
+
+ properties:
+ reg:
+ description: The channel index.
+ minimum: 0
+ maximum: 271
+
+ diff-channels:
+ description:
+ Both inputs can be connected to pins AIN1 to AIN16 by choosing the
+ appropriate value from 1 to 16.
+ items:
+ minimum: 1
+ maximum: 16
+
+ single-channel:
+ description:
+ Positive input can be connected to pins AIN1 to AIN16 by choosing the
+ appropriate value from 1 to 16. Negative input is connected to AINCOM.
+ items:
+ minimum: 1
+ maximum: 16
+
+ oneOf:
+ - required:
+ - reg
+ - diff-channels
+ - required:
+ - reg
+ - single-channel
+
required:
- compatible
- reg
@@ -98,6 +146,17 @@ required:
allOf:
- $ref: /schemas/spi/spi-peripheral-props.yaml#
+ - if:
+ properties:
+ compatible:
+ enum:
+ - adi,ad7190
+ - adi,ad7192
+ - adi,ad7193
+ - adi,ad7195
+ then:
+ patternProperties:
+ "^channel@[0-9a-f]+$": false
unevaluatedProperties: false
@@ -117,6 +176,7 @@ examples:
clock-names = "mclk";
interrupts = <25 0x2>;
interrupt-parent = <&gpio>;
+ aincom-supply = <&aincom>;
dvdd-supply = <&dvdd>;
avdd-supply = <&avdd>;
vref-supply = <&vref>;
@@ -127,3 +187,38 @@ examples:
adi,burnout-currents-enable;
};
};
+ - |
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ adc@0 {
+ compatible = "adi,ad7194";
+ reg = <0>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ spi-max-frequency = <1000000>;
+ spi-cpol;
+ spi-cpha;
+ clocks = <&ad7192_mclk>;
+ clock-names = "mclk";
+ interrupts = <25 0x2>;
+ interrupt-parent = <&gpio>;
+ aincom-supply = <&aincom>;
+ dvdd-supply = <&dvdd>;
+ avdd-supply = <&avdd>;
+ vref-supply = <&vref>;
+
+ channel@0 {
+ reg = <0>;
+ diff-channels = <1 6>;
+ };
+
+ channel@1 {
+ reg = <1>;
+ single-channel = <1>;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml
new file mode 100644
index 000000000000..899b777017ce
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml
@@ -0,0 +1,148 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/adc/adi,ad7380.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices Simultaneous Sampling Analog to Digital Converters
+
+maintainers:
+ - Michael Hennerich <Michael.Hennerich@analog.com>
+ - Nuno Sá <nuno.sa@analog.com>
+
+description: |
+ * https://www.analog.com/en/products/ad7380.html
+ * https://www.analog.com/en/products/ad7381.html
+ * https://www.analog.com/en/products/ad7383.html
+ * https://www.analog.com/en/products/ad7384.html
+ * https://www.analog.com/en/products/ad7380-4.html
+ * https://www.analog.com/en/products/ad7381-4.html
+ * https://www.analog.com/en/products/ad7383-4.html
+ * https://www.analog.com/en/products/ad7384-4.html
+
+$ref: /schemas/spi/spi-peripheral-props.yaml#
+
+properties:
+ compatible:
+ enum:
+ - adi,ad7380
+ - adi,ad7381
+ - adi,ad7383
+ - adi,ad7384
+ - adi,ad7380-4
+ - adi,ad7381-4
+ - adi,ad7383-4
+ - adi,ad7384-4
+
+ reg:
+ maxItems: 1
+
+ spi-max-frequency:
+ maximum: 80000000
+ spi-cpol: true
+ spi-cpha: true
+
+ vcc-supply:
+ description: A 3V to 3.6V supply that powers the chip.
+
+ vlogic-supply:
+ description:
+ A 1.65V to 3.6V supply for the logic pins.
+
+ refio-supply:
+ description:
+ A 2.5V to 3.3V supply for the external reference voltage. When omitted,
+ the internal 2.5V reference is used.
+
+ aina-supply:
+ description:
+ The common mode voltage supply for the AINA- pin on pseudo-differential
+ chips.
+
+ ainb-supply:
+ description:
+ The common mode voltage supply for the AINB- pin on pseudo-differential
+ chips.
+
+ ainc-supply:
+ description:
+ The common mode voltage supply for the AINC- pin on pseudo-differential
+ chips.
+
+ aind-supply:
+ description:
+ The common mode voltage supply for the AIND- pin on pseudo-differential
+ chips.
+
+ interrupts:
+ description:
+ When the device is using 1-wire mode, this property is used to optionally
+ specify the ALERT interrupt.
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - vcc-supply
+ - vlogic-supply
+
+unevaluatedProperties: false
+
+allOf:
+ # pseudo-differential chips require common mode voltage supplies,
+ # true differential chips don't use them
+ - if:
+ properties:
+ compatible:
+ enum:
+ - adi,ad7383
+ - adi,ad7384
+ - adi,ad7383-4
+ - adi,ad7384-4
+ then:
+ required:
+ - aina-supply
+ - ainb-supply
+ else:
+ properties:
+ aina-supply: false
+ ainb-supply: false
+ - if:
+ properties:
+ compatible:
+ enum:
+ - adi,ad7383-4
+ - adi,ad7384-4
+ then:
+ required:
+ - ainc-supply
+ - aind-supply
+ else:
+ properties:
+ ainc-supply: false
+ aind-supply: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ adc@0 {
+ compatible = "adi,ad7380";
+ reg = <0>;
+
+ spi-cpol;
+ spi-cpha;
+ spi-max-frequency = <80000000>;
+
+ interrupts = <27 IRQ_TYPE_EDGE_FALLING>;
+ interrupt-parent = <&gpio0>;
+
+ vcc-supply = <&supply_3_3V>;
+ vlogic-supply = <&supply_3_3V>;
+ refio-supply = <&supply_2_5V>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.yaml b/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.yaml
index 7e8328e9ce13..f748f3a60b35 100644
--- a/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.yaml
@@ -66,6 +66,9 @@ properties:
nvmem-cell-names:
const: temperature_calib
+ power-domains:
+ maxItems: 1
+
allOf:
- if:
properties:
diff --git a/Documentation/devicetree/bindings/iio/adc/ti,ads1015.yaml b/Documentation/devicetree/bindings/iio/adc/ti,ads1015.yaml
index d605999ffe28..718f633c6e04 100644
--- a/Documentation/devicetree/bindings/iio/adc/ti,ads1015.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/ti,ads1015.yaml
@@ -18,6 +18,7 @@ properties:
enum:
- ti,ads1015
- ti,ads1115
+ - ti,tla2021
- ti,tla2024
reg:
diff --git a/Documentation/devicetree/bindings/iio/chemical/sciosense,ens160.yaml b/Documentation/devicetree/bindings/iio/chemical/sciosense,ens160.yaml
new file mode 100644
index 000000000000..267033a68abb
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/chemical/sciosense,ens160.yaml
@@ -0,0 +1,70 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/chemical/sciosense,ens160.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ScioSense ENS160 multi-gas sensor
+
+maintainers:
+ - Gustavo Silva <gustavograzs@gmail.com>
+
+description: |
+ Digital Multi-Gas Sensor for Monitoring Indoor Air Quality.
+
+ Datasheet:
+ https://www.sciosense.com/wp-content/uploads/2023/12/ENS160-Datasheet.pdf
+
+properties:
+ compatible:
+ enum:
+ - sciosense,ens160
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ vdd-supply: true
+ vddio-supply: true
+
+required:
+ - compatible
+ - reg
+
+allOf:
+ - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ gas-sensor@52 {
+ compatible = "sciosense,ens160";
+ reg = <0x52>;
+ interrupt-parent = <&gpio0>;
+ interrupts = <19 IRQ_TYPE_EDGE_FALLING>;
+ };
+ };
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ gas-sensor@0 {
+ compatible = "sciosense,ens160";
+ reg = <0>;
+ spi-max-frequency = <10000000>;
+ interrupt-parent = <&gpio>;
+ interrupts = <19 IRQ_TYPE_EDGE_FALLING>;
+ };
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
index 8265d709094d..fc8b97f82077 100644
--- a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
+++ b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml
@@ -13,13 +13,17 @@ maintainers:
description: |
Bindings for the Analog Devices AD3552R DAC device and similar.
Datasheet can be found here:
+ https://www.analog.com/media/en/technical-documentation/data-sheets/ad3541r.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/ad3542r.pdf
+ https://www.analog.com/media/en/technical-documentation/data-sheets/ad3551r.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/ad3552r.pdf
properties:
compatible:
enum:
+ - adi,ad3541r
- adi,ad3542r
+ - adi,ad3551r
- adi,ad3552r
reg:
@@ -92,13 +96,13 @@ patternProperties:
maximum: 511
minimum: -511
- adi,gain-scaling-p-inv-log2:
- description: GainP = 1 / ( 2 ^ adi,gain-scaling-p-inv-log2)
+ adi,gain-scaling-p:
+ description: GainP = 1 / ( 2 ^ adi,gain-scaling-p)
$ref: /schemas/types.yaml#/definitions/uint32
enum: [0, 1, 2, 3]
- adi,gain-scaling-n-inv-log2:
- description: GainN = 1 / ( 2 ^ adi,gain-scaling-n-inv-log2)
+ adi,gain-scaling-n:
+ description: GainN = 1 / ( 2 ^ adi,gain-scaling-n)
$ref: /schemas/types.yaml#/definitions/uint32
enum: [0, 1, 2, 3]
@@ -107,8 +111,8 @@ patternProperties:
required:
- adi,gain-offset
- - adi,gain-scaling-p-inv-log2
- - adi,gain-scaling-n-inv-log2
+ - adi,gain-scaling-p
+ - adi,gain-scaling-n
- adi,rfb-ohms
required:
@@ -128,7 +132,9 @@ allOf:
properties:
compatible:
contains:
- const: adi,ad3542r
+ enum:
+ - adi,ad3541r
+ - adi,ad3542r
then:
patternProperties:
"^channel@([0-1])$":
@@ -158,7 +164,9 @@ allOf:
properties:
compatible:
contains:
- const: adi,ad3552r
+ enum:
+ - adi,ad3551r
+ - adi,ad3552r
then:
patternProperties:
"^channel@([0-1])$":
@@ -182,6 +190,21 @@ allOf:
- const: -10000000
- const: 10000000
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - adi,ad3541r
+ - adi,ad3551r
+ then:
+ properties:
+ channel@1: false
+ channel@0:
+ properties:
+ reg:
+ const: 0
+
required:
- compatible
- reg
@@ -208,8 +231,8 @@ examples:
reg = <1>;
custom-output-range-config {
adi,gain-offset = <5>;
- adi,gain-scaling-p-inv-log2 = <1>;
- adi,gain-scaling-n-inv-log2 = <2>;
+ adi,gain-scaling-p = <1>;
+ adi,gain-scaling-n = <2>;
adi,rfb-ohms = <1>;
};
};
diff --git a/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml b/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
index 9b7ad609f7db..9d185f7bfdcb 100644
--- a/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
+++ b/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
@@ -30,12 +30,19 @@ properties:
- adi,adis16467-2
- adi,adis16467-3
- adi,adis16500
+ - adi,adis16501
- adi,adis16505-1
- adi,adis16505-2
- adi,adis16505-3
- adi,adis16507-1
- adi,adis16507-2
- adi,adis16507-3
+ - adi,adis16575-2
+ - adi,adis16575-3
+ - adi,adis16576-2
+ - adi,adis16576-3
+ - adi,adis16577-2
+ - adi,adis16577-3
reg:
maxItems: 1
@@ -90,12 +97,19 @@ allOf:
contains:
enum:
- adi,adis16500
+ - adi,adis16501
- adi,adis16505-1
- adi,adis16505-2
- adi,adis16505-3
- adi,adis16507-1
- adi,adis16507-2
- adi,adis16507-3
+ - adi,adis16575-2
+ - adi,adis16575-3
+ - adi,adis16576-2
+ - adi,adis16576-3
+ - adi,adis16577-2
+ - adi,adis16577-3
then:
properties:
@@ -112,6 +126,23 @@ allOf:
dependencies:
adi,sync-mode: [ clocks ]
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - adi,adis16575-2
+ - adi,adis16575-3
+ - adi,adis16576-2
+ - adi,adis16576-3
+ - adi,adis16577-2
+ - adi,adis16577-3
+
+ then:
+ properties:
+ spi-max-frequency:
+ maximum: 15000000
+
unevaluatedProperties: false
examples:
diff --git a/Documentation/devicetree/bindings/iio/imu/adi,adis16480.yaml b/Documentation/devicetree/bindings/iio/imu/adi,adis16480.yaml
index 56e0dc20f5e4..e3eec38897bf 100644
--- a/Documentation/devicetree/bindings/iio/imu/adi,adis16480.yaml
+++ b/Documentation/devicetree/bindings/iio/imu/adi,adis16480.yaml
@@ -23,6 +23,12 @@ properties:
- adi,adis16497-1
- adi,adis16497-2
- adi,adis16497-3
+ - adi,adis16545-1
+ - adi,adis16545-2
+ - adi,adis16545-3
+ - adi,adis16547-1
+ - adi,adis16547-2
+ - adi,adis16547-3
reg:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/iio/imu/bosch,bmi160.yaml b/Documentation/devicetree/bindings/iio/imu/bosch,bmi160.yaml
index 47cfba939ca6..3b0a2d8b2e91 100644
--- a/Documentation/devicetree/bindings/iio/imu/bosch,bmi160.yaml
+++ b/Documentation/devicetree/bindings/iio/imu/bosch,bmi160.yaml
@@ -16,7 +16,11 @@ description: |
properties:
compatible:
- const: bosch,bmi160
+ oneOf:
+ - const: bosch,bmi160
+ - items:
+ - const: bosch,bmi120
+ - const: bosch,bmi160
reg:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/iio/light/vishay,veml6075.yaml b/Documentation/devicetree/bindings/iio/light/vishay,veml6075.yaml
index 91c318746bf3..ecf2339e02f6 100644
--- a/Documentation/devicetree/bindings/iio/light/vishay,veml6075.yaml
+++ b/Documentation/devicetree/bindings/iio/light/vishay,veml6075.yaml
@@ -4,14 +4,19 @@
$id: http://devicetree.org/schemas/iio/light/vishay,veml6075.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
-title: Vishay VEML6075 UVA and UVB sensor
+title: Vishay VEML6075 UVA/B and VEML6040 RGBW sensors
maintainers:
- Javier Carrasco <javier.carrasco.cruz@gmail.com>
+description:
+ VEML6040 datasheet at https://www.vishay.com/docs/84276/veml6040.pdf
+
properties:
compatible:
- const: vishay,veml6075
+ enum:
+ - vishay,veml6040
+ - vishay,veml6075
reg:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index fbf47f0bacf1..044e2001f4e3 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -1254,6 +1254,8 @@ patternProperties:
description: Smart Battery System
"^schindler,.*":
description: Schindler
+ "^sciosense,.*":
+ description: ScioSense B.V.
"^seagate,.*":
description: Seagate Technology PLC
"^seeed,.*":
diff --git a/Documentation/iio/adis16475.rst b/Documentation/iio/adis16475.rst
index 130f9e97cc17..4bf0998be36e 100644
--- a/Documentation/iio/adis16475.rst
+++ b/Documentation/iio/adis16475.rst
@@ -380,24 +380,5 @@ data is structured.
4. IIO Interfacing Tools
========================
-Linux Kernel Tools
-------------------
-
-Linux Kernel provides some userspace tools that can be used to retrieve data
-from IIO sysfs:
-
-* lsiio: example application that provides a list of IIO devices and triggers
-* iio_event_monitor: example application that reads events from an IIO device
- and prints them
-* iio_generic_buffer: example application that reads data from buffer
-* iio_utils: set of APIs, typically used to access sysfs files.
-
-LibIIO
-------
-
-LibIIO is a C/C++ library that provides generic access to IIO devices. The
-library abstracts the low-level details of the hardware, and provides a simple
-yet complete programming interface that can be used for advanced projects.
-
-For more information about LibIIO, please see:
-https://github.com/analogdevicesinc/libiio
+See ``Documentation/iio/iio_tools.rst`` for the description of the available IIO
+interfacing tools.
diff --git a/Documentation/iio/adis16480.rst b/Documentation/iio/adis16480.rst
new file mode 100644
index 000000000000..bc78fa04d958
--- /dev/null
+++ b/Documentation/iio/adis16480.rst
@@ -0,0 +1,443 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+================
+ADIS16480 driver
+================
+
+This driver supports Analog Device's IMUs on SPI bus.
+
+1. Supported devices
+====================
+
+* `ADIS16375 <https://www.analog.com/ADIS16375>`_
+* `ADIS16480 <https://www.analog.com/ADIS16480>`_
+* `ADIS16485 <https://www.analog.com/ADIS16485>`_
+* `ADIS16488 <https://www.analog.com/ADIS16488>`_
+* `ADIS16490 <https://www.analog.com/ADIS16490>`_
+* `ADIS16495 <https://www.analog.com/ADIS16495>`_
+* `ADIS16497 <https://www.analog.com/ADIS16497>`_
+* `ADIS16545 <https://www.analog.com/ADIS16545>`_
+* `ADIS16547 <https://www.analog.com/ADIS16547>`_
+
+Each supported device is a complete inertial system that includes a triaxial
+gyroscope and a triaxial accelerometer. Each inertial sensor in device combines
+with signal conditioning that optimizes dynamic performance. The factory
+calibration characterizes each sensor for sensitivity, bias, and alignment. As
+a result, each sensor has its own dynamic compensation formulas that provide
+accurate sensor measurements.
+
+2. Device attributes
+====================
+
+Accelerometer, gyroscope measurements are always provided. Furthermore, the
+driver offers the capability to retrieve the delta angle and the delta velocity
+measurements computed by the device.
+
+The delta angle measurements represent a calculation of angular displacement
+between each sample update, while the delta velocity measurements represent a
+calculation of linear velocity change between each sample update.
+
+Finally, temperature data are provided which show a coarse measurement of
+the temperature inside of the IMU device. This data is most useful for
+monitoring relative changes in the thermal environment.
+
+ADIS16480 and ADIS16488 also provide access to barometric pressure data and
+triaxial magnetometer measurements.
+
+Each IIO device, has a device folder under ``/sys/bus/iio/devices/iio:deviceX``,
+where X is the IIO index of the device. Under these folders reside a set of
+device files, depending on the characteristics and features of the hardware
+device in questions. These files are consistently generalized and documented in
+the IIO ABI documentation.
+
+The following tables show the adis16480 related device files, found in the
+specific device folder path ``/sys/bus/iio/devices/iio:deviceX``.
+
+**Available only for ADIS16480 and ADIS16488:**
+
++------------------------------------------+---------------------------------------------------------+
+| 3-Axis Magnetometer related device files | Description |
++------------------------------------------+---------------------------------------------------------+
+| in_magn_scale | Scale for the magnetometer channels. |
++------------------------------------------+---------------------------------------------------------+
+| in_magn_x_calibbias | Calibration offset for the X-axis magnetometer channel. |
++------------------------------------------+---------------------------------------------------------+
+| in_magn_x_filter_low_pass_3db_frequency | Bandwidth for the X-axis magnetometer channel. |
++------------------------------------------+---------------------------------------------------------+
+| in_magn_x_raw | Raw X-axis magnetometer channel value. |
++------------------------------------------+---------------------------------------------------------+
+| in_magn_y_calibbias | Calibration offset for the Y-axis magnetometer channel. |
++------------------------------------------+---------------------------------------------------------+
+| in_magn_y_filter_low_pass_3db_frequency | Bandwidth for the Y-axis magnetometer channel. |
++------------------------------------------+---------------------------------------------------------+
+| in_magn_y_raw | Raw Y-axis magnetometer channel value. |
++------------------------------------------+---------------------------------------------------------+
+| in_magn_z_calibbias | Calibration offset for the Z-axis magnetometer channel. |
++------------------------------------------+---------------------------------------------------------+
+| in_magn_z_filter_low_pass_3db_frequency | Bandwidth for the Z-axis magnetometer channel. |
++------------------------------------------+---------------------------------------------------------+
+| in_magn_z_raw | Raw Z-axis magnetometer channel value. |
++------------------------------------------+---------------------------------------------------------+
+
++------------------------------------------+-----------------------------------------------------+
+| Barometric pressure sensor related files | Description |
++------------------------------------------+-----------------------------------------------------+
+| in_pressure0_calibbias | Calibration offset for barometric pressure channel. |
++------------------------------------------+-----------------------------------------------------+
+| in_pressure0_raw | Raw barometric pressure channel value. |
++------------------------------------------+-----------------------------------------------------+
+| in_pressure0_scale | Scale for the barometric pressure sensor channel. |
++------------------------------------------+-----------------------------------------------------+
+
+**Available for all supported devices:**
+
++-------------------------------------------+----------------------------------------------------------+
+| 3-Axis Accelerometer related device files | Description |
++-------------------------------------------+----------------------------------------------------------+
+| in_accel_scale | Scale for the accelerometer channels. |
++-------------------------------------------+----------------------------------------------------------+
+| in_accel_x_calibbias | Calibration offset for the X-axis accelerometer channel. |
++-------------------------------------------+----------------------------------------------------------+
+| in_accel_x_calibscale | Calibration scale for the X-axis accelerometer channel. |
++-------------------------------------------+----------------------------------------------------------+
+| in_accel_x_filter_low_pass_3db_frequency | Bandwidth for the X-axis accelerometer channel. |
++-------------------------------------------+----------------------------------------------------------+
+| in_accel_x_raw | Raw X-axis accelerometer channel value. |
++-------------------------------------------+----------------------------------------------------------+
+| in_accel_y_calibbias | Calibration offset for the Y-axis accelerometer channel. |
++-------------------------------------------+----------------------------------------------------------+
+| in_accel_y_calibscale | Calibration scale for the Y-axis accelerometer channel. |
++-------------------------------------------+----------------------------------------------------------+
+| in_accel_y_filter_low_pass_3db_frequency | Bandwidth for the Y-axis accelerometer channel. |
++-------------------------------------------+----------------------------------------------------------+
+| in_accel_y_raw | Raw Y-axis accelerometer channel value. |
++-------------------------------------------+----------------------------------------------------------+
+| in_accel_z_calibbias | Calibration offset for the Z-axis accelerometer channel. |
++-------------------------------------------+----------------------------------------------------------+
+| in_accel_z_calibscale | Calibration scale for the Z-axis accelerometer channel. |
++-------------------------------------------+----------------------------------------------------------+
+| in_accel_z_filter_low_pass_3db_frequency | Bandwidth for the Z-axis accelerometer channel. |
++-------------------------------------------+----------------------------------------------------------+
+| in_accel_z_raw | Raw Z-axis accelerometer channel value. |
++-------------------------------------------+----------------------------------------------------------+
+| in_deltavelocity_scale | Scale for delta velocity channels. |
++-------------------------------------------+----------------------------------------------------------+
+| in_deltavelocity_x_raw | Raw X-axis delta velocity channel value. |
++-------------------------------------------+----------------------------------------------------------+
+| in_deltavelocity_y_raw | Raw Y-axis delta velocity channel value. |
++-------------------------------------------+----------------------------------------------------------+
+| in_deltavelocity_z_raw | Raw Z-axis delta velocity channel value. |
++-------------------------------------------+----------------------------------------------------------+
+
++--------------------------------------------+------------------------------------------------------+
+| 3-Axis Gyroscope related device files | Description |
++--------------------------------------------+------------------------------------------------------+
+| in_anglvel_scale | Scale for the gyroscope channels. |
++--------------------------------------------+------------------------------------------------------+
+| in_anglvel_x_calibbias | Calibration offset for the X-axis gyroscope channel. |
++--------------------------------------------+------------------------------------------------------+
+| in_anglvel_x_calibscale | Calibration scale for the X-axis gyroscope channel. |
++--------------------------------------------+------------------------------------------------------+
+| in_anglvel_x_filter_low_pass_3db_frequency | Bandwidth for the X-axis gyroscope channel. |
++--------------------------------------------+------------------------------------------------------+
+| in_anglvel_x_raw | Raw X-axis gyroscope channel value. |
++--------------------------------------------+------------------------------------------------------+
+| in_anglvel_y_calibbias | Calibration offset for the Y-axis gyroscope channel. |
++--------------------------------------------+------------------------------------------------------+
+| in_anglvel_y_calibscale | Calibration scale for the Y-axis gyroscope channel. |
++--------------------------------------------+------------------------------------------------------+
+| in_anglvel_y_filter_low_pass_3db_frequency | Bandwidth for the Y-axis gyroscope channel. |
++--------------------------------------------+------------------------------------------------------+
+| in_anglvel_y_raw | Raw Y-axis gyroscope channel value. |
++--------------------------------------------+------------------------------------------------------+
+| in_anglvel_z_calibbias | Calibration offset for the Z-axis gyroscope channel. |
++--------------------------------------------+------------------------------------------------------+
+| in_anglvel_z_calibscale | Calibration scale for the Z-axis gyroscope channel. |
++--------------------------------------------+------------------------------------------------------+
+| in_anglvel_z_filter_low_pass_3db_frequency | Bandwidth for the Z-axis gyroscope channel. |
++--------------------------------------------+------------------------------------------------------+
+| in_anglvel_z_raw | Raw Z-axis gyroscope channel value. |
++--------------------------------------------+------------------------------------------------------+
+| in_deltaangl_scale | Scale for delta angle channels. |
++--------------------------------------------+------------------------------------------------------+
+| in_deltaangl_x_raw | Raw X-axis delta angle channel value. |
++--------------------------------------------+------------------------------------------------------+
+| in_deltaangl_y_raw | Raw Y-axis delta angle channel value. |
++--------------------------------------------+------------------------------------------------------+
+| in_deltaangl_z_raw | Raw Z-axis delta angle channel value. |
++--------------------------------------------+------------------------------------------------------+
+
++----------------------------------+-------------------------------------------+
+| Temperature sensor related files | Description |
++----------------------------------+-------------------------------------------+
+| in_temp0_raw | Raw temperature channel value. |
++----------------------------------+-------------------------------------------+
+| in_temp0_offset | Offset for the temperature sensor channel.|
++----------------------------------+-------------------------------------------+
+| in_temp0_scale | Scale for the temperature sensor channel. |
++----------------------------------+-------------------------------------------+
+
++-------------------------------+---------------------------------------------------------+
+| Miscellaneous device files | Description |
++-------------------------------+---------------------------------------------------------+
+| name | Name of the IIO device. |
++-------------------------------+---------------------------------------------------------+
+| sampling_frequency | Currently selected sample rate. |
++-------------------------------+---------------------------------------------------------+
+
+The following table shows the adis16480 related device debug files, found in the
+specific device debug folder path ``/sys/kernel/debug/iio/iio:deviceX``.
+
++----------------------+-------------------------------------------------------------------------+
+| Debugfs device files | Description |
++----------------------+-------------------------------------------------------------------------+
+| serial_number | The serial number of the chip in hexadecimal format. |
++----------------------+-------------------------------------------------------------------------+
+| product_id | Chip specific product id (e.g. 16480, 16488, 16545, etc.). |
++----------------------+-------------------------------------------------------------------------+
+| flash_count | The number of flash writes performed on the device. |
++----------------------+-------------------------------------------------------------------------+
+| firmware_revision | String containing the firmware revision in the following format ##.##. |
++----------------------+-------------------------------------------------------------------------+
+| firmware_date | String containing the firmware date in the following format mm-dd-yyyy. |
++----------------------+-------------------------------------------------------------------------+
+
+Channels processed values
+-------------------------
+
+A channel value can be read from its _raw attribute. The value returned is the
+raw value as reported by the devices. To get the processed value of the channel,
+apply the following formula:
+
+.. code-block:: bash
+
+ processed value = (_raw + _offset) * _scale
+
+Where _offset and _scale are device attributes. If no _offset attribute is
+present, simply assume its value is 0.
+
+The adis16480 driver offers data for 7 types of channels, the table below shows
+the measurement units for the processed value, which are defined by the IIO
+framework:
+
++--------------------------------------+---------------------------+
+| Channel type | Measurement unit |
++--------------------------------------+---------------------------+
+| Acceleration on X, Y, and Z axis | Meters per Second squared |
++--------------------------------------+---------------------------+
+| Angular velocity on X, Y and Z axis | Radians per second |
++--------------------------------------+---------------------------+
+| Delta velocity on X. Y, and Z axis | Meters per Second |
++--------------------------------------+---------------------------+
+| Delta angle on X, Y, and Z axis | Radians |
++--------------------------------------+---------------------------+
+| Temperature | Millidegrees Celsius |
++--------------------------------------+---------------------------+
+| Magnetic field along X, Y and Z axis | Gauss |
++--------------------------------------+---------------------------+
+| Barometric pressure | kilo Pascal |
++--------------------------------------+---------------------------+
+
+Usage examples
+--------------
+
+Show device name:
+
+.. code-block:: bash
+
+ root:/sys/bus/iio/devices/iio:device0> cat name
+ adis16545-1
+
+Show accelerometer channels value:
+
+.. code-block:: bash
+
+ root:/sys/bus/iio/devices/iio:device0> cat in_accel_x_raw
+ 1376728
+ root:/sys/bus/iio/devices/iio:device0> cat in_accel_y_raw
+ 4487621
+ root:/sys/bus/iio/devices/iio:device0> cat in_accel_z_raw
+ 262773792
+ root:/sys/bus/iio/devices/iio:device0> cat in_accel_scale
+ 0.000000037
+
+- X-axis acceleration = in_accel_x_raw * in_accel_scale = 0.050938936 m/s^2
+- Y-axis acceleration = in_accel_y_raw * in_accel_scale = 0.166041977 m/s^2
+- Z-axis acceleration = in_accel_z_raw * in_accel_scale = 9.722630304 m/s^2
+
+Show gyroscope channels value:
+
+.. code-block:: bash
+
+ root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_x_raw
+ -1041702
+ root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_y_raw
+ -273013
+ root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_z_raw
+ 2745116
+ root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_scale
+ 0.000000001
+
+- X-axis angular velocity = in_anglvel_x_raw * in_anglvel_scale = −0.001041702 rad/s
+- Y-axis angular velocity = in_anglvel_y_raw * in_anglvel_scale = −0.000273013 rad/s
+- Z-axis angular velocity = in_anglvel_z_raw * in_anglvel_scale = 0.002745116 rad/s
+
+Set calibration offset for accelerometer channels:
+
+.. code-block:: bash
+
+ root:/sys/bus/iio/devices/iio:device0> cat in_accel_x_calibbias
+ 0
+
+ root:/sys/bus/iio/devices/iio:device0> echo 5000 > in_accel_x_calibbias
+ root:/sys/bus/iio/devices/iio:device0> cat in_accel_x_calibbias
+ 5000
+
+Set calibration offset for gyroscope channels:
+
+.. code-block:: bash
+
+ root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_y_calibbias
+ 0
+
+ root:/sys/bus/iio/devices/iio:device0> echo -5000 > in_anglvel_y_calibbias
+ root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_y_calibbias
+ -5000
+
+Set sampling frequency:
+
+.. code-block:: bash
+
+ root:/sys/bus/iio/devices/iio:device0> cat sampling_frequency
+ 4250.000000
+
+ root:/sys/bus/iio/devices/iio:device0> echo 1000 > sampling_frequency
+ 1062.500000
+
+Set bandwidth for accelerometer channels:
+
+.. code-block:: bash
+
+ root:/sys/bus/iio/devices/iio:device0> cat in_accel_x_filter_low_pass_3db_frequency
+ 0
+
+ root:/sys/bus/iio/devices/iio:device0> echo 300 > in_accel_x_filter_low_pass_3db_frequency
+ root:/sys/bus/iio/devices/iio:device0> cat in_accel_x_filter_low_pass_3db_frequency
+ 300
+
+Show serial number:
+
+.. code-block:: bash
+
+ root:/sys/kernel/debug/iio/iio:device0> cat serial_number
+ 0x000c
+
+Show product id:
+
+.. code-block:: bash
+
+ root:/sys/kernel/debug/iio/iio:device0> cat product_id
+ 16545
+
+Show flash count:
+
+.. code-block:: bash
+
+ root:/sys/kernel/debug/iio/iio:device0> cat flash_count
+ 88
+
+Show firmware revision:
+
+.. code-block:: bash
+
+ root:/sys/kernel/debug/iio/iio:device0> cat firmware_revision
+ 1.4
+
+Show firmware date:
+
+.. code-block:: bash
+
+ root:/sys/kernel/debug/iio/iio:device0> cat firmware_date
+ 09-23-2023
+
+3. Device buffers
+=================
+
+This driver supports IIO buffers.
+
+All devices support retrieving the raw acceleration, gyroscope and temperature
+measurements using buffers.
+
+The following device families also support retrieving the delta velocity, delta
+angle and temperature measurements using buffers:
+
+- ADIS16545
+- ADIS16547
+
+However, when retrieving acceleration or gyroscope data using buffers, delta
+readings will not be available and vice versa. This is because the device only
+allows to read either acceleration and gyroscope data or delta velocity and
+delta angle data at a time and switching between these two burst data selection
+modes is time consuming.
+
+Usage examples
+--------------
+
+Set device trigger in current_trigger, if not already set:
+
+.. code-block:: bash
+
+ root:/sys/bus/iio/devices/iio:device0> cat trigger/current_trigger
+
+ root:/sys/bus/iio/devices/iio:device0> echo adis16545-1-dev0 > trigger/current_trigger
+ root:/sys/bus/iio/devices/iio:device0> cat trigger/current_trigger
+ adis16545-1-dev0
+
+Select channels for buffer read:
+
+.. code-block:: bash
+
+ root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_deltavelocity_x_en
+ root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_deltavelocity_y_en
+ root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_deltavelocity_z_en
+ root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_temp0_en
+
+Set the number of samples to be stored in the buffer:
+
+.. code-block:: bash
+
+ root:/sys/bus/iio/devices/iio:device0> echo 10 > buffer/length
+
+Enable buffer readings:
+
+.. code-block:: bash
+
+ root:/sys/bus/iio/devices/iio:device0> echo 1 > buffer/enable
+
+Obtain buffered data::
+
+ root:/sys/bus/iio/devices/iio:device0> hexdump -C /dev/iio\:device0
+ ...
+ 00006aa0 09 62 00 00 ff ff fc a4 00 00 01 69 00 03 3c 08 |.b.........i..<.|
+ 00006ab0 09 61 00 00 00 00 02 96 00 00 02 8f 00 03 37 50 |.a............7P|
+ 00006ac0 09 61 00 00 00 00 12 3d 00 00 0b 89 00 03 2c 0b |.a.....=......,.|
+ 00006ad0 09 61 00 00 00 00 1e dc 00 00 16 dd 00 03 25 bf |.a............%.|
+ 00006ae0 09 61 00 00 00 00 1e e3 00 00 1b bf 00 03 27 0b |.a............'.|
+ 00006af0 09 61 00 00 00 00 15 50 00 00 19 44 00 03 30 fd |.a.....P...D..0.|
+ 00006b00 09 61 00 00 00 00 09 0e 00 00 14 41 00 03 3d 7f |.a.........A..=.|
+ 00006b10 09 61 00 00 ff ff ff f0 00 00 0e bc 00 03 48 d0 |.a............H.|
+ 00006b20 09 63 00 00 00 00 00 9f 00 00 0f 37 00 03 4c fe |.c.........7..L.|
+ 00006b30 09 64 00 00 00 00 0b f6 00 00 18 92 00 03 43 22 |.d............C"|
+ 00006b40 09 64 00 00 00 00 18 df 00 00 22 33 00 03 33 ab |.d........"3..3.|
+ 00006b50 09 63 00 00 00 00 1e 81 00 00 26 be 00 03 29 60 |.c........&...)`|
+ 00006b60 09 63 00 00 00 00 1b 13 00 00 22 2f 00 03 23 91 |.c........"/..#.|
+ ...
+
+See ``Documentation/iio/iio_devbuf.rst`` for more information about how buffered
+data is structured.
+
+4. IIO Interfacing Tools
+========================
+
+See ``Documentation/iio/iio_tools.rst`` for the description of the available IIO
+interfacing tools.
diff --git a/Documentation/iio/iio_tools.rst b/Documentation/iio/iio_tools.rst
new file mode 100644
index 000000000000..cc691c7f6365
--- /dev/null
+++ b/Documentation/iio/iio_tools.rst
@@ -0,0 +1,27 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=====================
+IIO Interfacing Tools
+=====================
+
+1. Linux Kernel Tools
+=====================
+
+Linux Kernel provides some userspace tools that can be used to retrieve data
+from IIO sysfs:
+
+* lsiio: example application that provides a list of IIO devices and triggers
+* iio_event_monitor: example application that reads events from an IIO device
+ and prints them
+* iio_generic_buffer: example application that reads data from buffer
+* iio_utils: set of APIs, typically used to access sysfs files.
+
+2. LibIIO
+=========
+
+LibIIO is a C/C++ library that provides generic access to IIO devices. The
+library abstracts the low-level details of the hardware, and provides a simple
+yet complete programming interface that can be used for advanced projects.
+
+For more information about LibIIO, please see:
+https://github.com/analogdevicesinc/libiio
diff --git a/Documentation/iio/index.rst b/Documentation/iio/index.rst
index fb6f9d743211..4c13bfa2865c 100644
--- a/Documentation/iio/index.rst
+++ b/Documentation/iio/index.rst
@@ -9,6 +9,7 @@ Industrial I/O
iio_configfs
iio_devbuf
+ iio_tools
Industrial I/O Kernel Drivers
=============================
@@ -18,5 +19,6 @@ Industrial I/O Kernel Drivers
ad7944
adis16475
+ adis16480
bno055
ep93xx_adc
diff --git a/MAINTAINERS b/MAINTAINERS
index cf9c9221c388..24d372f7653e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -439,6 +439,16 @@ W: http://wiki.analog.com/AD7142
W: https://ez.analog.com/linux-software-drivers
F: drivers/input/misc/ad714x.c
+AD738X ADC DRIVER (AD7380/1/2/4)
+M: Michael Hennerich <michael.hennerich@analog.com>
+M: Nuno Sá <nuno.sa@analog.com>
+R: David Lechner <dlechner@baylibre.com>
+S: Supported
+W: https://wiki.analog.com/resources/tools-software/linux-drivers/iio-adc/ad738x
+W: https://ez.analog.com/linux-software-drivers
+F: Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml
+F: drivers/iio/adc/ad7380.c
+
AD7877 TOUCHSCREEN DRIVER
M: Michael Hennerich <michael.hennerich@analog.com>
S: Supported
@@ -11509,6 +11519,7 @@ M: Jean-Baptiste Maneyrol <jmaneyrol@invensense.com>
L: linux-iio@vger.kernel.org
S: Maintained
W: https://invensense.tdk.com/
+F: Documentation/ABI/testing/sysfs-bus-iio-inv_icm42600
F: Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
F: drivers/iio/imu/inv_icm42600/
@@ -19936,6 +19947,14 @@ F: include/linux/wait.h
F: include/uapi/linux/sched.h
F: kernel/sched/
+SCIOSENSE ENS160 MULTI-GAS SENSOR DRIVER
+M: Gustavo Silva <gustavograzs@gmail.com>
+S: Maintained
+F: drivers/iio/chemical/ens160_core.c
+F: drivers/iio/chemical/ens160_i2c.c
+F: drivers/iio/chemical/ens160_spi.c
+F: drivers/iio/chemical/ens160.h
+
SCSI LIBSAS SUBSYSTEM
R: John Garry <john.g.garry@oracle.com>
R: Jason Yan <yanaijie@huawei.com>
diff --git a/drivers/char/lp.c b/drivers/char/lp.c
index 2f171d14b9b5..5faebe0365c5 100644
--- a/drivers/char/lp.c
+++ b/drivers/char/lp.c
@@ -1123,4 +1123,5 @@ module_init(lp_init_module);
module_exit(lp_cleanup_module);
MODULE_ALIAS_CHARDEV_MAJOR(LP_MAJOR);
+MODULE_DESCRIPTION("Generic parallel printer driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c
index e9f694b36871..9eff426a9286 100644
--- a/drivers/char/nvram.c
+++ b/drivers/char/nvram.c
@@ -540,6 +540,7 @@ static void __exit nvram_module_exit(void)
module_init(nvram_module_init);
module_exit(nvram_module_exit);
+MODULE_DESCRIPTION("CMOS/NV-RAM driver for Linux");
MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(NVRAM_MINOR);
MODULE_ALIAS("devname:nvram");
diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c
index 58e9dcc2a308..3655aa859185 100644
--- a/drivers/char/ppdev.c
+++ b/drivers/char/ppdev.c
@@ -882,5 +882,6 @@ static void __exit ppdev_cleanup(void)
module_init(ppdev_init);
module_exit(ppdev_cleanup);
+MODULE_DESCRIPTION("Support for user-space parallel port device drivers");
MODULE_LICENSE("GPL");
MODULE_ALIAS_CHARDEV_MAJOR(PP_MAJOR);
diff --git a/drivers/char/tlclk.c b/drivers/char/tlclk.c
index 896a3550fba9..377bebf6c925 100644
--- a/drivers/char/tlclk.c
+++ b/drivers/char/tlclk.c
@@ -47,6 +47,7 @@
#include <linux/uaccess.h>
MODULE_AUTHOR("Sebastien Bouchard <sebastien.bouchard@ca.kontron.com>");
+MODULE_DESCRIPTION("Telecom Clock driver for Intel NetStructure(tm) MPCBL0010");
MODULE_LICENSE("GPL");
/*Hardware Reset of the PLL */
diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c
index 4c806a189ee5..d7f841ab4323 100644
--- a/drivers/char/ttyprintk.c
+++ b/drivers/char/ttyprintk.c
@@ -228,4 +228,5 @@ static void __exit ttyprintk_exit(void)
device_initcall(ttyprintk_init);
module_exit(ttyprintk_exit);
+MODULE_DESCRIPTION("TTY driver to output user messages via printk");
MODULE_LICENSE("GPL");
diff --git a/drivers/iio/accel/adxl313_spi.c b/drivers/iio/accel/adxl313_spi.c
index b7cc15678a2b..6f8d73f6e5a9 100644
--- a/drivers/iio/accel/adxl313_spi.c
+++ b/drivers/iio/accel/adxl313_spi.c
@@ -72,13 +72,7 @@ static int adxl313_spi_probe(struct spi_device *spi)
if (ret)
return ret;
- /*
- * Retrieves device specific data as a pointer to a
- * adxl313_chip_info structure
- */
- chip_data = device_get_match_data(&spi->dev);
- if (!chip_data)
- chip_data = (const struct adxl313_chip_info *)spi_get_device_id(spi)->driver_data;
+ chip_data = spi_get_device_match_data(spi);
regmap = devm_regmap_init_spi(spi,
&adxl31x_spi_regmap_config[chip_data->type]);
diff --git a/drivers/iio/accel/adxl355_spi.c b/drivers/iio/accel/adxl355_spi.c
index fc99534d91ff..5153ac815e4b 100644
--- a/drivers/iio/accel/adxl355_spi.c
+++ b/drivers/iio/accel/adxl355_spi.c
@@ -28,13 +28,9 @@ static int adxl355_spi_probe(struct spi_device *spi)
const struct adxl355_chip_info *chip_data;
struct regmap *regmap;
- chip_data = device_get_match_data(&spi->dev);
- if (!chip_data) {
- chip_data = (void *)spi_get_device_id(spi)->driver_data;
-
- if (!chip_data)
- return -EINVAL;
- }
+ chip_data = spi_get_device_match_data(spi);
+ if (!chip_data)
+ return -EINVAL;
regmap = devm_regmap_init_spi(spi, &adxl355_spi_regmap_config);
if (IS_ERR(regmap)) {
diff --git a/drivers/iio/accel/adxl367_i2c.c b/drivers/iio/accel/adxl367_i2c.c
index 62c74bdc0d77..deb82a43ec36 100644
--- a/drivers/iio/accel/adxl367_i2c.c
+++ b/drivers/iio/accel/adxl367_i2c.c
@@ -61,8 +61,8 @@ static int adxl367_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id adxl367_i2c_id[] = {
- { "adxl367", 0 },
- { },
+ { "adxl367" },
+ { }
};
MODULE_DEVICE_TABLE(i2c, adxl367_i2c_id);
diff --git a/drivers/iio/accel/adxl372_i2c.c b/drivers/iio/accel/adxl372_i2c.c
index d0690417fd36..3571cfde1c0e 100644
--- a/drivers/iio/accel/adxl372_i2c.c
+++ b/drivers/iio/accel/adxl372_i2c.c
@@ -42,7 +42,7 @@ static int adxl372_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id adxl372_i2c_id[] = {
- { "adxl372", 0 },
+ { "adxl372" },
{}
};
MODULE_DEVICE_TABLE(i2c, adxl372_i2c_id);
diff --git a/drivers/iio/accel/bma400_i2c.c b/drivers/iio/accel/bma400_i2c.c
index adf4e3fd2e1d..c1c72f577295 100644
--- a/drivers/iio/accel/bma400_i2c.c
+++ b/drivers/iio/accel/bma400_i2c.c
@@ -28,7 +28,7 @@ static int bma400_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id bma400_i2c_ids[] = {
- { "bma400", 0 },
+ { "bma400" },
{ }
};
MODULE_DEVICE_TABLE(i2c, bma400_i2c_ids);
diff --git a/drivers/iio/accel/bmi088-accel-core.c b/drivers/iio/accel/bmi088-accel-core.c
index 4d989708e6c3..469a1255d93c 100644
--- a/drivers/iio/accel/bmi088-accel-core.c
+++ b/drivers/iio/accel/bmi088-accel-core.c
@@ -114,11 +114,6 @@ enum bmi088_odr_modes {
BMI088_ACCEL_MODE_ODR_1600 = 0xc,
};
-struct bmi088_scale_info {
- int scale;
- u8 reg_range;
-};
-
struct bmi088_accel_chip_info {
const char *name;
u8 chip_id;
diff --git a/drivers/iio/accel/da311.c b/drivers/iio/accel/da311.c
index 8f919920ced5..94f827acdd1c 100644
--- a/drivers/iio/accel/da311.c
+++ b/drivers/iio/accel/da311.c
@@ -268,7 +268,7 @@ static int da311_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(da311_pm_ops, da311_suspend, da311_resume);
static const struct i2c_device_id da311_i2c_id[] = {
- {"da311", 0},
+ { "da311" },
{}
};
MODULE_DEVICE_TABLE(i2c, da311_i2c_id);
diff --git a/drivers/iio/accel/dmard06.c b/drivers/iio/accel/dmard06.c
index 2e719d60fff8..fb14894c66f9 100644
--- a/drivers/iio/accel/dmard06.c
+++ b/drivers/iio/accel/dmard06.c
@@ -201,9 +201,9 @@ static DEFINE_SIMPLE_DEV_PM_OPS(dmard06_pm_ops, dmard06_suspend,
dmard06_resume);
static const struct i2c_device_id dmard06_id[] = {
- { "dmard05", 0 },
- { "dmard06", 0 },
- { "dmard07", 0 },
+ { "dmard05" },
+ { "dmard06" },
+ { "dmard07" },
{ }
};
MODULE_DEVICE_TABLE(i2c, dmard06_id);
diff --git a/drivers/iio/accel/dmard09.c b/drivers/iio/accel/dmard09.c
index fa98623de579..6644c1fec3e6 100644
--- a/drivers/iio/accel/dmard09.c
+++ b/drivers/iio/accel/dmard09.c
@@ -125,8 +125,8 @@ static int dmard09_probe(struct i2c_client *client)
}
static const struct i2c_device_id dmard09_id[] = {
- { "dmard09", 0 },
- { },
+ { "dmard09" },
+ { }
};
MODULE_DEVICE_TABLE(i2c, dmard09_id);
diff --git a/drivers/iio/accel/dmard10.c b/drivers/iio/accel/dmard10.c
index 7745b6ffd1ad..35c0eefb741e 100644
--- a/drivers/iio/accel/dmard10.c
+++ b/drivers/iio/accel/dmard10.c
@@ -231,7 +231,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(dmard10_pm_ops, dmard10_suspend,
dmard10_resume);
static const struct i2c_device_id dmard10_i2c_id[] = {
- {"dmard10", 0},
+ { "dmard10" },
{}
};
MODULE_DEVICE_TABLE(i2c, dmard10_i2c_id);
diff --git a/drivers/iio/accel/kxsd9-i2c.c b/drivers/iio/accel/kxsd9-i2c.c
index 3bc9ee1f9db3..c4c7e2d4e98a 100644
--- a/drivers/iio/accel/kxsd9-i2c.c
+++ b/drivers/iio/accel/kxsd9-i2c.c
@@ -43,8 +43,8 @@ static const struct of_device_id kxsd9_of_match[] = {
MODULE_DEVICE_TABLE(of, kxsd9_of_match);
static const struct i2c_device_id kxsd9_i2c_id[] = {
- {"kxsd9", 0},
- { },
+ { "kxsd9" },
+ { }
};
MODULE_DEVICE_TABLE(i2c, kxsd9_i2c_id);
diff --git a/drivers/iio/accel/mc3230.c b/drivers/iio/accel/mc3230.c
index 6b87c2c9945c..caa40a14a631 100644
--- a/drivers/iio/accel/mc3230.c
+++ b/drivers/iio/accel/mc3230.c
@@ -180,7 +180,7 @@ static int mc3230_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(mc3230_pm_ops, mc3230_suspend, mc3230_resume);
static const struct i2c_device_id mc3230_i2c_id[] = {
- {"mc3230", 0},
+ { "mc3230" },
{}
};
MODULE_DEVICE_TABLE(i2c, mc3230_i2c_id);
diff --git a/drivers/iio/accel/mma7455_i2c.c b/drivers/iio/accel/mma7455_i2c.c
index 14f7850a22f0..36a357c8e9ed 100644
--- a/drivers/iio/accel/mma7455_i2c.c
+++ b/drivers/iio/accel/mma7455_i2c.c
@@ -32,8 +32,8 @@ static void mma7455_i2c_remove(struct i2c_client *i2c)
}
static const struct i2c_device_id mma7455_i2c_ids[] = {
- { "mma7455", 0 },
- { "mma7456", 0 },
+ { "mma7455" },
+ { "mma7456" },
{ }
};
MODULE_DEVICE_TABLE(i2c, mma7455_i2c_ids);
diff --git a/drivers/iio/accel/mma7660.c b/drivers/iio/accel/mma7660.c
index 260cbceaa151..2894aff80161 100644
--- a/drivers/iio/accel/mma7660.c
+++ b/drivers/iio/accel/mma7660.c
@@ -38,21 +38,6 @@
static const int mma7660_nscale = 467142857;
-#define MMA7660_CHANNEL(reg, axis) { \
- .type = IIO_ACCEL, \
- .address = reg, \
- .modified = 1, \
- .channel2 = IIO_MOD_##axis, \
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
- .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
-}
-
-static const struct iio_chan_spec mma7660_channels[] = {
- MMA7660_CHANNEL(MMA7660_REG_XOUT, X),
- MMA7660_CHANNEL(MMA7660_REG_YOUT, Y),
- MMA7660_CHANNEL(MMA7660_REG_ZOUT, Z),
-};
-
enum mma7660_mode {
MMA7660_MODE_STANDBY,
MMA7660_MODE_ACTIVE
@@ -62,6 +47,21 @@ struct mma7660_data {
struct i2c_client *client;
struct mutex lock;
enum mma7660_mode mode;
+ struct iio_mount_matrix orientation;
+};
+
+static const struct iio_mount_matrix *
+mma7660_get_mount_matrix(const struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan)
+{
+ struct mma7660_data *data = iio_priv(indio_dev);
+
+ return &data->orientation;
+}
+
+static const struct iio_chan_spec_ext_info mma7660_ext_info[] = {
+ IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, mma7660_get_mount_matrix),
+ { }
};
static IIO_CONST_ATTR(in_accel_scale_available, MMA7660_SCALE_AVAIL);
@@ -75,6 +75,22 @@ static const struct attribute_group mma7660_attribute_group = {
.attrs = mma7660_attributes
};
+#define MMA7660_CHANNEL(reg, axis) { \
+ .type = IIO_ACCEL, \
+ .address = reg, \
+ .modified = 1, \
+ .channel2 = IIO_MOD_##axis, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .ext_info = mma7660_ext_info, \
+}
+
+static const struct iio_chan_spec mma7660_channels[] = {
+ MMA7660_CHANNEL(MMA7660_REG_XOUT, X),
+ MMA7660_CHANNEL(MMA7660_REG_YOUT, Y),
+ MMA7660_CHANNEL(MMA7660_REG_ZOUT, Z),
+};
+
static int mma7660_set_mode(struct mma7660_data *data,
enum mma7660_mode mode)
{
@@ -187,6 +203,10 @@ static int mma7660_probe(struct i2c_client *client)
mutex_init(&data->lock);
data->mode = MMA7660_MODE_STANDBY;
+ ret = iio_read_mount_matrix(&client->dev, &data->orientation);
+ if (ret)
+ return ret;
+
indio_dev->info = &mma7660_info;
indio_dev->name = MMA7660_DRIVER_NAME;
indio_dev->modes = INDIO_DIRECT_MODE;
@@ -241,7 +261,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(mma7660_pm_ops, mma7660_suspend,
mma7660_resume);
static const struct i2c_device_id mma7660_i2c_id[] = {
- {"mma7660", 0},
+ { "mma7660" },
{}
};
MODULE_DEVICE_TABLE(i2c, mma7660_i2c_id);
diff --git a/drivers/iio/accel/mma9551.c b/drivers/iio/accel/mma9551.c
index 083c08f65baf..fa1799b0b0df 100644
--- a/drivers/iio/accel/mma9551.c
+++ b/drivers/iio/accel/mma9551.c
@@ -595,7 +595,7 @@ static const struct acpi_device_id mma9551_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, mma9551_acpi_match);
static const struct i2c_device_id mma9551_id[] = {
- {"mma9551", 0},
+ { "mma9551" },
{}
};
diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c
index 3cbd0fd4e624..86543f34ef17 100644
--- a/drivers/iio/accel/mma9553.c
+++ b/drivers/iio/accel/mma9553.c
@@ -1234,8 +1234,8 @@ static const struct acpi_device_id mma9553_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, mma9553_acpi_match);
static const struct i2c_device_id mma9553_id[] = {
- {"mma9553", 0},
- {},
+ { "mma9553" },
+ {}
};
MODULE_DEVICE_TABLE(i2c, mma9553_id);
diff --git a/drivers/iio/accel/mxc4005.c b/drivers/iio/accel/mxc4005.c
index e56407b6f204..fc54a2a4693c 100644
--- a/drivers/iio/accel/mxc4005.c
+++ b/drivers/iio/accel/mxc4005.c
@@ -584,9 +584,9 @@ static const struct of_device_id mxc4005_of_match[] = {
MODULE_DEVICE_TABLE(of, mxc4005_of_match);
static const struct i2c_device_id mxc4005_id[] = {
- {"mxc4005", 0},
- {"mxc6655", 0},
- { },
+ { "mxc4005" },
+ { "mxc6655" },
+ { }
};
MODULE_DEVICE_TABLE(i2c, mxc4005_id);
diff --git a/drivers/iio/accel/mxc6255.c b/drivers/iio/accel/mxc6255.c
index ac228128c4f9..a8abda7b2a63 100644
--- a/drivers/iio/accel/mxc6255.c
+++ b/drivers/iio/accel/mxc6255.c
@@ -172,8 +172,8 @@ static const struct acpi_device_id mxc6255_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, mxc6255_acpi_match);
static const struct i2c_device_id mxc6255_id[] = {
- {"mxc6225", 0},
- {"mxc6255", 0},
+ { "mxc6225" },
+ { "mxc6255" },
{ }
};
MODULE_DEVICE_TABLE(i2c, mxc6255_id);
diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c
index ef0ae7672253..b3534d5751b9 100644
--- a/drivers/iio/accel/stk8312.c
+++ b/drivers/iio/accel/stk8312.c
@@ -633,8 +633,8 @@ static DEFINE_SIMPLE_DEV_PM_OPS(stk8312_pm_ops, stk8312_suspend,
static const struct i2c_device_id stk8312_i2c_id[] = {
/* Deprecated in favour of lowercase form */
- { "STK8312", 0 },
- { "stk8312", 0 },
+ { "STK8312" },
+ { "stk8312" },
{}
};
MODULE_DEVICE_TABLE(i2c, stk8312_i2c_id);
diff --git a/drivers/iio/accel/stk8ba50.c b/drivers/iio/accel/stk8ba50.c
index 668edc88c89d..6d3c7f444d21 100644
--- a/drivers/iio/accel/stk8ba50.c
+++ b/drivers/iio/accel/stk8ba50.c
@@ -525,7 +525,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(stk8ba50_pm_ops, stk8ba50_suspend,
stk8ba50_resume);
static const struct i2c_device_id stk8ba50_i2c_id[] = {
- {"stk8ba50", 0},
+ { "stk8ba50" },
{}
};
MODULE_DEVICE_TABLE(i2c, stk8ba50_i2c_id);
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 8db68b80b391..3d91015af6ea 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -88,12 +88,17 @@ config AD7173
called ad7173.
config AD7192
- tristate "Analog Devices AD7190 AD7192 AD7193 AD7195 ADC driver"
+ tristate "Analog Devices AD7192 and similar ADC driver"
depends on SPI
select AD_SIGMA_DELTA
help
- Say yes here to build support for Analog Devices AD7190,
- AD7192, AD7193 or AD7195 SPI analog to digital converters (ADC).
+ Say yes here to build support for Analog Devices SPI analog to digital
+ converters (ADC):
+ - AD7190
+ - AD7192
+ - AD7193
+ - AD7194
+ - AD7195
If unsure, say N (but it's safe to say "Y").
To compile this driver as a module, choose M here: the
@@ -155,6 +160,22 @@ config AD7298
To compile this driver as a module, choose M here: the
module will be called ad7298.
+config AD7380
+ tristate "Analog Devices AD7380 ADC driver"
+ depends on SPI_MASTER
+ select IIO_BUFFER
+ select IIO_TRIGGER
+ select IIO_TRIGGERED_BUFFER
+ help
+ AD7380 is a family of simultaneous sampling ADCs that share the same
+ SPI register map and have similar pinouts.
+
+ Say yes here to build support for Analog Devices AD7380 ADC and
+ similar chips.
+
+ To compile this driver as a module, choose M here: the module will be
+ called ad7380.
+
config AD7476
tristate "Analog Devices AD7476 1-channel ADCs driver and other similar devices from AD and TI"
depends on SPI
@@ -332,6 +353,7 @@ config AD9467
config ADI_AXI_ADC
tristate "Analog Devices Generic AXI ADC IP core driver"
+ depends on MICROBLAZE || NIOS2 || ARCH_ZYNQ || ARCH_ZYNQMP || ARCH_INTEL_SOCFPGA || COMPILE_TEST
select IIO_BUFFER
select IIO_BUFFER_HW_CONSUMER
select IIO_BUFFER_DMAENGINE
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index edb32ce2af02..37ac689a0209 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -18,7 +18,7 @@ obj-$(CONFIG_AD7280) += ad7280a.o
obj-$(CONFIG_AD7291) += ad7291.o
obj-$(CONFIG_AD7292) += ad7292.o
obj-$(CONFIG_AD7298) += ad7298.o
-obj-$(CONFIG_AD7923) += ad7923.o
+obj-$(CONFIG_AD7380) += ad7380.o
obj-$(CONFIG_AD7476) += ad7476.o
obj-$(CONFIG_AD7606_IFACE_PARALLEL) += ad7606_par.o
obj-$(CONFIG_AD7606_IFACE_SPI) += ad7606_spi.o
@@ -29,6 +29,7 @@ obj-$(CONFIG_AD7780) += ad7780.o
obj-$(CONFIG_AD7791) += ad7791.o
obj-$(CONFIG_AD7793) += ad7793.o
obj-$(CONFIG_AD7887) += ad7887.o
+obj-$(CONFIG_AD7923) += ad7923.o
obj-$(CONFIG_AD7944) += ad7944.o
obj-$(CONFIG_AD7949) += ad7949.o
obj-$(CONFIG_AD799X) += ad799x.o
@@ -90,42 +91,43 @@ obj-$(CONFIG_NAU7802) += nau7802.o
obj-$(CONFIG_NPCM_ADC) += npcm_adc.o
obj-$(CONFIG_PAC1934) += pac1934.o
obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o
+obj-$(CONFIG_QCOM_PM8XXX_XOADC) += qcom-pm8xxx-xoadc.o
obj-$(CONFIG_QCOM_SPMI_ADC5) += qcom-spmi-adc5.o
obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o
obj-$(CONFIG_QCOM_SPMI_RRADC) += qcom-spmi-rradc.o
-obj-$(CONFIG_QCOM_VADC_COMMON) += qcom-vadc-common.o
obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o
-obj-$(CONFIG_QCOM_PM8XXX_XOADC) += qcom-pm8xxx-xoadc.o
+obj-$(CONFIG_QCOM_VADC_COMMON) += qcom-vadc-common.o
obj-$(CONFIG_RCAR_GYRO_ADC) += rcar-gyroadc.o
+obj-$(CONFIG_RICHTEK_RTQ6056) += rtq6056.o
obj-$(CONFIG_RN5T618_ADC) += rn5t618-adc.o
obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o
-obj-$(CONFIG_RICHTEK_RTQ6056) += rtq6056.o
obj-$(CONFIG_RZG2L_ADC) += rzg2l_adc.o
obj-$(CONFIG_SC27XX_ADC) += sc27xx_adc.o
+obj-$(CONFIG_SD_ADC_MODULATOR) += sd_adc_modulator.o
obj-$(CONFIG_SPEAR_ADC) += spear_adc.o
-obj-$(CONFIG_SUN4I_GPADC) += sun4i-gpadc-iio.o
-obj-$(CONFIG_SUN20I_GPADC) += sun20i-gpadc-iio.o
obj-$(CONFIG_STM32_ADC_CORE) += stm32-adc-core.o
obj-$(CONFIG_STM32_ADC) += stm32-adc.o
-obj-$(CONFIG_STM32_DFSDM_CORE) += stm32-dfsdm-core.o
obj-$(CONFIG_STM32_DFSDM_ADC) += stm32-dfsdm-adc.o
+obj-$(CONFIG_STM32_DFSDM_CORE) += stm32-dfsdm-core.o
obj-$(CONFIG_STMPE_ADC) += stmpe-adc.o
+obj-$(CONFIG_SUN20I_GPADC) += sun20i-gpadc-iio.o
+obj-$(CONFIG_SUN4I_GPADC) += sun4i-gpadc-iio.o
obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o
obj-$(CONFIG_TI_ADC0832) += ti-adc0832.o
obj-$(CONFIG_TI_ADC084S021) += ti-adc084s021.o
-obj-$(CONFIG_TI_ADC12138) += ti-adc12138.o
obj-$(CONFIG_TI_ADC108S102) += ti-adc108s102.o
+obj-$(CONFIG_TI_ADC12138) += ti-adc12138.o
obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o
obj-$(CONFIG_TI_ADC161S626) += ti-adc161s626.o
obj-$(CONFIG_TI_ADS1015) += ti-ads1015.o
obj-$(CONFIG_TI_ADS1100) += ti-ads1100.o
+obj-$(CONFIG_TI_ADS124S08) += ti-ads124s08.o
obj-$(CONFIG_TI_ADS1298) += ti-ads1298.o
+obj-$(CONFIG_TI_ADS131E08) += ti-ads131e08.o
obj-$(CONFIG_TI_ADS7924) += ti-ads7924.o
obj-$(CONFIG_TI_ADS7950) += ti-ads7950.o
obj-$(CONFIG_TI_ADS8344) += ti-ads8344.o
obj-$(CONFIG_TI_ADS8688) += ti-ads8688.o
-obj-$(CONFIG_TI_ADS124S08) += ti-ads124s08.o
-obj-$(CONFIG_TI_ADS131E08) += ti-ads131e08.o
obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o
obj-$(CONFIG_TI_LMP92064) += ti-lmp92064.o
obj-$(CONFIG_TI_TLC4541) += ti-tlc4541.o
@@ -134,7 +136,6 @@ obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o
obj-$(CONFIG_TWL6030_GPADC) += twl6030-gpadc.o
obj-$(CONFIG_VF610_ADC) += vf610_adc.o
obj-$(CONFIG_VIPERBOARD_ADC) += viperboard_adc.o
+obj-$(CONFIG_XILINX_AMS) += xilinx-ams.o
xilinx-xadc-y := xilinx-xadc-core.o xilinx-xadc-events.o
obj-$(CONFIG_XILINX_XADC) += xilinx-xadc.o
-obj-$(CONFIG_XILINX_AMS) += xilinx-ams.o
-obj-$(CONFIG_SD_ADC_MODULATOR) += sd_adc_modulator.o
diff --git a/drivers/iio/adc/ad7192.c b/drivers/iio/adc/ad7192.c
index 7bcc7e2aa2a2..0789121236d6 100644
--- a/drivers/iio/adc/ad7192.c
+++ b/drivers/iio/adc/ad7192.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * AD7190 AD7192 AD7193 AD7195 SPI ADC driver
+ * AD7192 and similar SPI ADC driver
*
* Copyright 2011-2015 Analog Devices Inc.
*/
@@ -20,6 +20,7 @@
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/property.h>
+#include <linux/units.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@@ -128,10 +129,24 @@
#define AD7193_CH_AIN8 0x480 /* AIN7 - AINCOM */
#define AD7193_CH_AINCOM 0x600 /* AINCOM - AINCOM */
+#define AD7194_CH_POS(x) (((x) - 1) << 4)
+#define AD7194_CH_NEG(x) ((x) - 1)
+
+/* 10th bit corresponds to CON18(Pseudo) */
+#define AD7194_CH(p) (BIT(10) | AD7194_CH_POS(p))
+
+#define AD7194_DIFF_CH(p, n) (AD7194_CH_POS(p) | AD7194_CH_NEG(n))
+#define AD7194_CH_TEMP 0x100
+#define AD7194_CH_BASE_NR 2
+#define AD7194_CH_AIN_START 1
+#define AD7194_CH_AIN_NR 16
+#define AD7194_CH_MAX_NR 272
+
/* ID Register Bit Designations (AD7192_REG_ID) */
#define CHIPID_AD7190 0x4
#define CHIPID_AD7192 0x0
#define CHIPID_AD7193 0x2
+#define CHIPID_AD7194 0x3
#define CHIPID_AD7195 0x6
#define AD7192_ID_MASK GENMASK(3, 0)
@@ -169,6 +184,7 @@ enum {
ID_AD7190,
ID_AD7192,
ID_AD7193,
+ ID_AD7194,
ID_AD7195,
};
@@ -177,7 +193,9 @@ struct ad7192_chip_info {
const char *name;
const struct iio_chan_spec *channels;
u8 num_channels;
+ const struct ad_sigma_delta_info *sigma_delta_info;
const struct iio_info *info;
+ int (*parse_channels)(struct iio_dev *indio_dev);
};
struct ad7192_state {
@@ -186,10 +204,12 @@ struct ad7192_state {
struct regulator *vref;
struct clk *mclk;
u16 int_vref_mv;
+ u32 aincom_mv;
u32 fclk;
u32 mode;
u32 conf;
u32 scale_avail[8][2];
+ u32 filter_freq_avail[4][2];
u32 oversampling_ratio_avail[4];
u8 gpocon;
u8 clock_sel;
@@ -343,6 +363,18 @@ static const struct ad_sigma_delta_info ad7192_sigma_delta_info = {
.irq_flags = IRQF_TRIGGER_FALLING,
};
+static const struct ad_sigma_delta_info ad7194_sigma_delta_info = {
+ .set_channel = ad7192_set_channel,
+ .append_status = ad7192_append_status,
+ .disable_all = ad7192_disable_all,
+ .set_mode = ad7192_set_mode,
+ .has_registers = true,
+ .addr_shift = 3,
+ .read_mask = BIT(6),
+ .status_ch_mask = GENMASK(3, 0),
+ .irq_flags = IRQF_TRIGGER_FALLING,
+};
+
static const struct ad_sd_calib_data ad7192_calib_arr[8] = {
{AD7192_MODE_CAL_INT_ZERO, AD7192_CH_AIN1},
{AD7192_MODE_CAL_INT_FULL, AD7192_CH_AIN1},
@@ -473,6 +505,16 @@ static int ad7192_setup(struct iio_dev *indio_dev, struct device *dev)
st->oversampling_ratio_avail[2] = 8;
st->oversampling_ratio_avail[3] = 16;
+ st->filter_freq_avail[0][0] = 600;
+ st->filter_freq_avail[1][0] = 800;
+ st->filter_freq_avail[2][0] = 2300;
+ st->filter_freq_avail[3][0] = 2720;
+
+ st->filter_freq_avail[0][1] = 1000;
+ st->filter_freq_avail[1][1] = 1000;
+ st->filter_freq_avail[2][1] = 1000;
+ st->filter_freq_avail[3][1] = 1000;
+
return 0;
}
@@ -586,48 +628,24 @@ static int ad7192_get_f_adc(struct ad7192_state *st)
f_order * FIELD_GET(AD7192_MODE_RATE_MASK, st->mode));
}
-static void ad7192_get_available_filter_freq(struct ad7192_state *st,
- int *freq)
+static void ad7192_update_filter_freq_avail(struct ad7192_state *st)
{
unsigned int fadc;
/* Formulas for filter at page 25 of the datasheet */
fadc = ad7192_compute_f_adc(st, false, true);
- freq[0] = DIV_ROUND_CLOSEST(fadc * 240, 1024);
+ st->filter_freq_avail[0][0] = DIV_ROUND_CLOSEST(fadc * 240, 1024);
fadc = ad7192_compute_f_adc(st, true, true);
- freq[1] = DIV_ROUND_CLOSEST(fadc * 240, 1024);
+ st->filter_freq_avail[1][0] = DIV_ROUND_CLOSEST(fadc * 240, 1024);
fadc = ad7192_compute_f_adc(st, false, false);
- freq[2] = DIV_ROUND_CLOSEST(fadc * 230, 1024);
+ st->filter_freq_avail[2][0] = DIV_ROUND_CLOSEST(fadc * 230, 1024);
fadc = ad7192_compute_f_adc(st, true, false);
- freq[3] = DIV_ROUND_CLOSEST(fadc * 272, 1024);
+ st->filter_freq_avail[3][0] = DIV_ROUND_CLOSEST(fadc * 272, 1024);
}
-static ssize_t ad7192_show_filter_avail(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct ad7192_state *st = iio_priv(indio_dev);
- unsigned int freq_avail[4], i;
- size_t len = 0;
-
- ad7192_get_available_filter_freq(st, freq_avail);
-
- for (i = 0; i < ARRAY_SIZE(freq_avail); i++)
- len += sysfs_emit_at(buf, len, "%d.%03d ", freq_avail[i] / 1000,
- freq_avail[i] % 1000);
-
- buf[len - 1] = '\n';
-
- return len;
-}
-
-static IIO_DEVICE_ATTR(filter_low_pass_3db_frequency_available,
- 0444, ad7192_show_filter_avail, NULL, 0);
-
static IIO_DEVICE_ATTR(bridge_switch_en, 0644,
ad7192_show_bridge_switch, ad7192_set,
AD7192_REG_GPOCON);
@@ -637,7 +655,6 @@ static IIO_DEVICE_ATTR(ac_excitation_en, 0644,
AD7192_REG_CONF);
static struct attribute *ad7192_attributes[] = {
- &iio_dev_attr_filter_low_pass_3db_frequency_available.dev_attr.attr,
&iio_dev_attr_bridge_switch_en.dev_attr.attr,
NULL
};
@@ -647,7 +664,6 @@ static const struct attribute_group ad7192_attribute_group = {
};
static struct attribute *ad7195_attributes[] = {
- &iio_dev_attr_filter_low_pass_3db_frequency_available.dev_attr.attr,
&iio_dev_attr_bridge_switch_en.dev_attr.attr,
&iio_dev_attr_ac_excitation_en.dev_attr.attr,
NULL
@@ -665,17 +681,15 @@ static unsigned int ad7192_get_temp_scale(bool unipolar)
static int ad7192_set_3db_filter_freq(struct ad7192_state *st,
int val, int val2)
{
- int freq_avail[4], i, ret, freq;
+ int i, ret, freq;
unsigned int diff_new, diff_old;
int idx = 0;
diff_old = U32_MAX;
freq = val * 1000 + val2;
- ad7192_get_available_filter_freq(st, freq_avail);
-
- for (i = 0; i < ARRAY_SIZE(freq_avail); i++) {
- diff_new = abs(freq - freq_avail[i]);
+ for (i = 0; i < ARRAY_SIZE(st->filter_freq_avail); i++) {
+ diff_new = abs(freq - st->filter_freq_avail[i][0]);
if (diff_new < diff_old) {
diff_old = diff_new;
idx = i;
@@ -759,10 +773,24 @@ static int ad7192_read_raw(struct iio_dev *indio_dev,
*val = -(1 << (chan->scan_type.realbits - 1));
else
*val = 0;
+
+ switch (chan->type) {
+ case IIO_VOLTAGE:
+ /*
+ * Only applies to pseudo-differential inputs.
+ * AINCOM voltage has to be converted to "raw" units.
+ */
+ if (st->aincom_mv && !chan->differential)
+ *val += DIV_ROUND_CLOSEST_ULL((u64)st->aincom_mv * NANO,
+ st->scale_avail[gain][1]);
+ return IIO_VAL_INT;
/* Kelvin to Celsius */
- if (chan->type == IIO_TEMP)
+ case IIO_TEMP:
*val -= 273 * ad7192_get_temp_scale(unipolar);
- return IIO_VAL_INT;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
case IIO_CHAN_INFO_SAMP_FREQ:
*val = DIV_ROUND_CLOSEST(ad7192_get_f_adc(st), 1024);
return IIO_VAL_INT;
@@ -792,10 +820,11 @@ static int ad7192_write_raw(struct iio_dev *indio_dev,
if (ret)
return ret;
+ mutex_lock(&st->lock);
+
switch (mask) {
case IIO_CHAN_INFO_SCALE:
ret = -EINVAL;
- mutex_lock(&st->lock);
for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++)
if (val2 == st->scale_avail[i][1]) {
ret = 0;
@@ -809,7 +838,6 @@ static int ad7192_write_raw(struct iio_dev *indio_dev,
ad7192_calibrate_all(st);
break;
}
- mutex_unlock(&st->lock);
break;
case IIO_CHAN_INFO_SAMP_FREQ:
if (!val) {
@@ -826,13 +854,13 @@ static int ad7192_write_raw(struct iio_dev *indio_dev,
st->mode &= ~AD7192_MODE_RATE_MASK;
st->mode |= FIELD_PREP(AD7192_MODE_RATE_MASK, div);
ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode);
+ ad7192_update_filter_freq_avail(st);
break;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
ret = ad7192_set_3db_filter_freq(st, val, val2 / 1000);
break;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
ret = -EINVAL;
- mutex_lock(&st->lock);
for (i = 0; i < ARRAY_SIZE(st->oversampling_ratio_avail); i++)
if (val == st->oversampling_ratio_avail[i]) {
ret = 0;
@@ -845,12 +873,14 @@ static int ad7192_write_raw(struct iio_dev *indio_dev,
3, st->mode);
break;
}
- mutex_unlock(&st->lock);
+ ad7192_update_filter_freq_avail(st);
break;
default:
ret = -EINVAL;
}
+ mutex_unlock(&st->lock);
+
iio_device_release_direct_mode(indio_dev);
return ret;
@@ -889,6 +919,12 @@ static int ad7192_read_avail(struct iio_dev *indio_dev,
*length = ARRAY_SIZE(st->scale_avail) * 2;
return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+ *vals = (int *)st->filter_freq_avail;
+ *type = IIO_VAL_FRACTIONAL;
+ *length = ARRAY_SIZE(st->filter_freq_avail) * 2;
+
+ return IIO_AVAIL_LIST;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
*vals = (int *)st->oversampling_ratio_avail;
*type = IIO_VAL_INT;
@@ -930,6 +966,14 @@ static const struct iio_info ad7192_info = {
.update_scan_mode = ad7192_update_scan_mode,
};
+static const struct iio_info ad7194_info = {
+ .read_raw = ad7192_read_raw,
+ .write_raw = ad7192_write_raw,
+ .write_raw_get_fmt = ad7192_write_raw_get_fmt,
+ .read_avail = ad7192_read_avail,
+ .validate_trigger = ad_sd_validate_trigger,
+};
+
static const struct iio_info ad7195_info = {
.read_raw = ad7192_read_raw,
.write_raw = ad7192_write_raw,
@@ -956,7 +1000,9 @@ static const struct iio_info ad7195_info = {
BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \
(_mask_all), \
.info_mask_shared_by_type_available = (_mask_type_av), \
- .info_mask_shared_by_all_available = (_mask_all_av), \
+ .info_mask_shared_by_all_available = \
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \
+ (_mask_all_av), \
.ext_info = (_ext_info), \
.scan_index = (_si), \
.scan_type = { \
@@ -1019,12 +1065,95 @@ static const struct iio_chan_spec ad7193_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(14),
};
+static bool ad7194_validate_ain_channel(struct device *dev, u32 ain)
+{
+ return in_range(ain, AD7194_CH_AIN_START, AD7194_CH_AIN_NR);
+}
+
+static int ad7194_parse_channels(struct iio_dev *indio_dev)
+{
+ struct device *dev = indio_dev->dev.parent;
+ struct iio_chan_spec *ad7194_channels;
+ const struct iio_chan_spec ad7194_chan = AD7193_CHANNEL(0, 0, 0);
+ const struct iio_chan_spec ad7194_chan_diff = AD7193_DIFF_CHANNEL(0, 0, 0, 0);
+ const struct iio_chan_spec ad7194_chan_temp = AD719x_TEMP_CHANNEL(0, 0);
+ const struct iio_chan_spec ad7194_chan_timestamp = IIO_CHAN_SOFT_TIMESTAMP(0);
+ unsigned int num_channels, index = 0;
+ u32 ain[2];
+ int ret;
+
+ num_channels = device_get_child_node_count(dev);
+ if (num_channels > AD7194_CH_MAX_NR)
+ return dev_err_probe(dev, -EINVAL, "Too many channels: %u\n",
+ num_channels);
+
+ num_channels += AD7194_CH_BASE_NR;
+
+ ad7194_channels = devm_kcalloc(dev, num_channels,
+ sizeof(*ad7194_channels), GFP_KERNEL);
+ if (!ad7194_channels)
+ return -ENOMEM;
+
+ indio_dev->channels = ad7194_channels;
+ indio_dev->num_channels = num_channels;
+
+ device_for_each_child_node_scoped(dev, child) {
+ ret = fwnode_property_read_u32_array(child, "diff-channels",
+ ain, ARRAY_SIZE(ain));
+ if (ret == 0) {
+ if (!ad7194_validate_ain_channel(dev, ain[0]))
+ return dev_err_probe(dev, -EINVAL,
+ "Invalid AIN channel: %u\n",
+ ain[0]);
+
+ if (!ad7194_validate_ain_channel(dev, ain[1]))
+ return dev_err_probe(dev, -EINVAL,
+ "Invalid AIN channel: %u\n",
+ ain[1]);
+
+ *ad7194_channels = ad7194_chan_diff;
+ ad7194_channels->scan_index = index++;
+ ad7194_channels->channel = ain[0];
+ ad7194_channels->channel2 = ain[1];
+ ad7194_channels->address = AD7194_DIFF_CH(ain[0], ain[1]);
+ } else {
+ ret = fwnode_property_read_u32(child, "single-channel",
+ &ain[0]);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Missing channel property\n");
+
+ if (!ad7194_validate_ain_channel(dev, ain[0]))
+ return dev_err_probe(dev, -EINVAL,
+ "Invalid AIN channel: %u\n",
+ ain[0]);
+
+ *ad7194_channels = ad7194_chan;
+ ad7194_channels->scan_index = index++;
+ ad7194_channels->channel = ain[0];
+ ad7194_channels->address = AD7194_CH(ain[0]);
+ }
+ ad7194_channels++;
+ }
+
+ *ad7194_channels = ad7194_chan_temp;
+ ad7194_channels->scan_index = index++;
+ ad7194_channels->address = AD7194_CH_TEMP;
+ ad7194_channels++;
+
+ *ad7194_channels = ad7194_chan_timestamp;
+ ad7194_channels->scan_index = index;
+
+ return 0;
+}
+
static const struct ad7192_chip_info ad7192_chip_info_tbl[] = {
[ID_AD7190] = {
.chip_id = CHIPID_AD7190,
.name = "ad7190",
.channels = ad7192_channels,
.num_channels = ARRAY_SIZE(ad7192_channels),
+ .sigma_delta_info = &ad7192_sigma_delta_info,
.info = &ad7192_info,
},
[ID_AD7192] = {
@@ -1032,6 +1161,7 @@ static const struct ad7192_chip_info ad7192_chip_info_tbl[] = {
.name = "ad7192",
.channels = ad7192_channels,
.num_channels = ARRAY_SIZE(ad7192_channels),
+ .sigma_delta_info = &ad7192_sigma_delta_info,
.info = &ad7192_info,
},
[ID_AD7193] = {
@@ -1039,13 +1169,22 @@ static const struct ad7192_chip_info ad7192_chip_info_tbl[] = {
.name = "ad7193",
.channels = ad7193_channels,
.num_channels = ARRAY_SIZE(ad7193_channels),
+ .sigma_delta_info = &ad7192_sigma_delta_info,
.info = &ad7192_info,
},
+ [ID_AD7194] = {
+ .chip_id = CHIPID_AD7194,
+ .name = "ad7194",
+ .info = &ad7194_info,
+ .sigma_delta_info = &ad7194_sigma_delta_info,
+ .parse_channels = ad7194_parse_channels,
+ },
[ID_AD7195] = {
.chip_id = CHIPID_AD7195,
.name = "ad7195",
.channels = ad7192_channels,
.num_channels = ARRAY_SIZE(ad7192_channels),
+ .sigma_delta_info = &ad7192_sigma_delta_info,
.info = &ad7195_info,
},
};
@@ -1059,6 +1198,7 @@ static int ad7192_probe(struct spi_device *spi)
{
struct ad7192_state *st;
struct iio_dev *indio_dev;
+ struct regulator *aincom;
int ret;
if (!spi->irq) {
@@ -1074,6 +1214,35 @@ static int ad7192_probe(struct spi_device *spi)
mutex_init(&st->lock);
+ /*
+ * Regulator aincom is optional to maintain compatibility with older DT.
+ * Newer firmware should provide a zero volt fixed supply if wired to
+ * ground.
+ */
+ aincom = devm_regulator_get_optional(&spi->dev, "aincom");
+ if (IS_ERR(aincom)) {
+ if (PTR_ERR(aincom) != -ENODEV)
+ return dev_err_probe(&spi->dev, PTR_ERR(aincom),
+ "Failed to get AINCOM supply\n");
+
+ st->aincom_mv = 0;
+ } else {
+ ret = regulator_enable(aincom);
+ if (ret)
+ return dev_err_probe(&spi->dev, ret,
+ "Failed to enable specified AINCOM supply\n");
+
+ ret = devm_add_action_or_reset(&spi->dev, ad7192_reg_disable, aincom);
+ if (ret)
+ return ret;
+
+ ret = regulator_get_voltage(aincom);
+ if (ret < 0)
+ return dev_err_probe(&spi->dev, ret,
+ "Device tree error, AINCOM voltage undefined\n");
+ st->aincom_mv = ret / MILLI;
+ }
+
st->avdd = devm_regulator_get(&spi->dev, "avdd");
if (IS_ERR(st->avdd))
return PTR_ERR(st->avdd);
@@ -1122,11 +1291,17 @@ static int ad7192_probe(struct spi_device *spi)
st->chip_info = spi_get_device_match_data(spi);
indio_dev->name = st->chip_info->name;
indio_dev->modes = INDIO_DIRECT_MODE;
- indio_dev->channels = st->chip_info->channels;
- indio_dev->num_channels = st->chip_info->num_channels;
indio_dev->info = st->chip_info->info;
+ if (st->chip_info->parse_channels) {
+ ret = st->chip_info->parse_channels(indio_dev);
+ if (ret)
+ return ret;
+ } else {
+ indio_dev->channels = st->chip_info->channels;
+ indio_dev->num_channels = st->chip_info->num_channels;
+ }
- ret = ad_sd_init(&st->sd, indio_dev, spi, &ad7192_sigma_delta_info);
+ ret = ad_sd_init(&st->sd, indio_dev, spi, st->chip_info->sigma_delta_info);
if (ret)
return ret;
@@ -1163,6 +1338,7 @@ static const struct of_device_id ad7192_of_match[] = {
{ .compatible = "adi,ad7190", .data = &ad7192_chip_info_tbl[ID_AD7190] },
{ .compatible = "adi,ad7192", .data = &ad7192_chip_info_tbl[ID_AD7192] },
{ .compatible = "adi,ad7193", .data = &ad7192_chip_info_tbl[ID_AD7193] },
+ { .compatible = "adi,ad7194", .data = &ad7192_chip_info_tbl[ID_AD7194] },
{ .compatible = "adi,ad7195", .data = &ad7192_chip_info_tbl[ID_AD7195] },
{}
};
@@ -1172,6 +1348,7 @@ static const struct spi_device_id ad7192_ids[] = {
{ "ad7190", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7190] },
{ "ad7192", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7192] },
{ "ad7193", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7193] },
+ { "ad7194", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7194] },
{ "ad7195", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7195] },
{}
};
@@ -1188,6 +1365,6 @@ static struct spi_driver ad7192_driver = {
module_spi_driver(ad7192_driver);
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
-MODULE_DESCRIPTION("Analog Devices AD7190, AD7192, AD7193, AD7195 ADC");
+MODULE_DESCRIPTION("Analog Devices AD7192 and similar ADC");
MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS(IIO_AD_SIGMA_DELTA);
diff --git a/drivers/iio/adc/ad7291.c b/drivers/iio/adc/ad7291.c
index 14d02b085d3b..b59b2a51623c 100644
--- a/drivers/iio/adc/ad7291.c
+++ b/drivers/iio/adc/ad7291.c
@@ -536,7 +536,7 @@ static int ad7291_probe(struct i2c_client *client)
}
static const struct i2c_device_id ad7291_id[] = {
- { "ad7291", 0 },
+ { "ad7291" },
{}
};
diff --git a/drivers/iio/adc/ad7380.c b/drivers/iio/adc/ad7380.c
new file mode 100644
index 000000000000..7568cd0a2b32
--- /dev/null
+++ b/drivers/iio/adc/ad7380.c
@@ -0,0 +1,833 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Analog Devices AD738x Simultaneous Sampling SAR ADCs
+ *
+ * Copyright 2017 Analog Devices Inc.
+ * Copyright 2024 BayLibre, SAS
+ *
+ * Datasheets of supported parts:
+ * ad7380/1 : https://www.analog.com/media/en/technical-documentation/data-sheets/AD7380-7381.pdf
+ * ad7383/4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7383-7384.pdf
+ * ad7380-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7380-4.pdf
+ * ad7381-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7381-4.pdf
+ * ad7383/4-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7383-4-ad7384-4.pdf
+ */
+
+#include <linux/align.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/cleanup.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+
+#include <linux/iio/buffer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#define MAX_NUM_CHANNELS 4
+/* 2.5V internal reference voltage */
+#define AD7380_INTERNAL_REF_MV 2500
+
+/* reading and writing registers is more reliable at lower than max speed */
+#define AD7380_REG_WR_SPEED_HZ 10000000
+
+#define AD7380_REG_WR BIT(15)
+#define AD7380_REG_REGADDR GENMASK(14, 12)
+#define AD7380_REG_DATA GENMASK(11, 0)
+
+#define AD7380_REG_ADDR_NOP 0x0
+#define AD7380_REG_ADDR_CONFIG1 0x1
+#define AD7380_REG_ADDR_CONFIG2 0x2
+#define AD7380_REG_ADDR_ALERT 0x3
+#define AD7380_REG_ADDR_ALERT_LOW_TH 0x4
+#define AD7380_REG_ADDR_ALERT_HIGH_TH 0x5
+
+#define AD7380_CONFIG1_OS_MODE BIT(9)
+#define AD7380_CONFIG1_OSR GENMASK(8, 6)
+#define AD7380_CONFIG1_CRC_W BIT(5)
+#define AD7380_CONFIG1_CRC_R BIT(4)
+#define AD7380_CONFIG1_ALERTEN BIT(3)
+#define AD7380_CONFIG1_RES BIT(2)
+#define AD7380_CONFIG1_REFSEL BIT(1)
+#define AD7380_CONFIG1_PMODE BIT(0)
+
+#define AD7380_CONFIG2_SDO2 GENMASK(9, 8)
+#define AD7380_CONFIG2_SDO BIT(8)
+#define AD7380_CONFIG2_RESET GENMASK(7, 0)
+
+#define AD7380_CONFIG2_RESET_SOFT 0x3C
+#define AD7380_CONFIG2_RESET_HARD 0xFF
+
+#define AD7380_ALERT_LOW_TH GENMASK(11, 0)
+#define AD7380_ALERT_HIGH_TH GENMASK(11, 0)
+
+#define T_CONVERT_NS 190 /* conversion time */
+#define T_CONVERT_0_NS 10 /* 1st conversion start time (oversampling) */
+#define T_CONVERT_X_NS 500 /* xth conversion start time (oversampling) */
+
+struct ad7380_timing_specs {
+ const unsigned int t_csh_ns; /* CS minimum high time */
+};
+
+struct ad7380_chip_info {
+ const char *name;
+ const struct iio_chan_spec *channels;
+ unsigned int num_channels;
+ const char * const *vcm_supplies;
+ unsigned int num_vcm_supplies;
+ const unsigned long *available_scan_masks;
+ const struct ad7380_timing_specs *timing_specs;
+};
+
+enum {
+ AD7380_SCAN_TYPE_NORMAL,
+ AD7380_SCAN_TYPE_RESOLUTION_BOOST,
+};
+
+/* Extended scan types for 14-bit chips. */
+static const struct iio_scan_type ad7380_scan_type_14[] = {
+ [AD7380_SCAN_TYPE_NORMAL] = {
+ .sign = 's',
+ .realbits = 14,
+ .storagebits = 16,
+ .endianness = IIO_CPU
+ },
+ [AD7380_SCAN_TYPE_RESOLUTION_BOOST] = {
+ .sign = 's',
+ .realbits = 16,
+ .storagebits = 16,
+ .endianness = IIO_CPU
+ },
+};
+
+/* Extended scan types for 16-bit chips. */
+static const struct iio_scan_type ad7380_scan_type_16[] = {
+ [AD7380_SCAN_TYPE_NORMAL] = {
+ .sign = 's',
+ .realbits = 16,
+ .storagebits = 16,
+ .endianness = IIO_CPU
+ },
+ [AD7380_SCAN_TYPE_RESOLUTION_BOOST] = {
+ .sign = 's',
+ .realbits = 18,
+ .storagebits = 32,
+ .endianness = IIO_CPU
+ },
+};
+
+#define AD7380_CHANNEL(index, bits, diff) { \
+ .type = IIO_VOLTAGE, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ ((diff) ? 0 : BIT(IIO_CHAN_INFO_OFFSET)), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
+ .info_mask_shared_by_type_available = \
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
+ .indexed = 1, \
+ .differential = (diff), \
+ .channel = (diff) ? (2 * (index)) : (index), \
+ .channel2 = (diff) ? (2 * (index) + 1) : 0, \
+ .scan_index = (index), \
+ .has_ext_scan_type = 1, \
+ .ext_scan_type = ad7380_scan_type_##bits, \
+ .num_ext_scan_type = ARRAY_SIZE(ad7380_scan_type_##bits),\
+}
+
+#define DEFINE_AD7380_2_CHANNEL(name, bits, diff) \
+static const struct iio_chan_spec name[] = { \
+ AD7380_CHANNEL(0, bits, diff), \
+ AD7380_CHANNEL(1, bits, diff), \
+ IIO_CHAN_SOFT_TIMESTAMP(2), \
+}
+
+#define DEFINE_AD7380_4_CHANNEL(name, bits, diff) \
+static const struct iio_chan_spec name[] = { \
+ AD7380_CHANNEL(0, bits, diff), \
+ AD7380_CHANNEL(1, bits, diff), \
+ AD7380_CHANNEL(2, bits, diff), \
+ AD7380_CHANNEL(3, bits, diff), \
+ IIO_CHAN_SOFT_TIMESTAMP(4), \
+}
+
+/* fully differential */
+DEFINE_AD7380_2_CHANNEL(ad7380_channels, 16, 1);
+DEFINE_AD7380_2_CHANNEL(ad7381_channels, 14, 1);
+DEFINE_AD7380_4_CHANNEL(ad7380_4_channels, 16, 1);
+DEFINE_AD7380_4_CHANNEL(ad7381_4_channels, 14, 1);
+/* pseudo differential */
+DEFINE_AD7380_2_CHANNEL(ad7383_channels, 16, 0);
+DEFINE_AD7380_2_CHANNEL(ad7384_channels, 14, 0);
+DEFINE_AD7380_4_CHANNEL(ad7383_4_channels, 16, 0);
+DEFINE_AD7380_4_CHANNEL(ad7384_4_channels, 14, 0);
+
+static const char * const ad7380_2_channel_vcm_supplies[] = {
+ "aina", "ainb",
+};
+
+static const char * const ad7380_4_channel_vcm_supplies[] = {
+ "aina", "ainb", "ainc", "aind",
+};
+
+/* Since this is simultaneous sampling, we don't allow individual channels. */
+static const unsigned long ad7380_2_channel_scan_masks[] = {
+ GENMASK(1, 0),
+ 0
+};
+
+static const unsigned long ad7380_4_channel_scan_masks[] = {
+ GENMASK(3, 0),
+ 0
+};
+
+static const struct ad7380_timing_specs ad7380_timing = {
+ .t_csh_ns = 10,
+};
+
+static const struct ad7380_timing_specs ad7380_4_timing = {
+ .t_csh_ns = 20,
+};
+
+/*
+ * Available oversampling ratios. The indices correspond with the bit value
+ * expected by the chip. The available ratios depend on the averaging mode,
+ * only normal averaging is supported for now.
+ */
+static const int ad7380_oversampling_ratios[] = {
+ 1, 2, 4, 8, 16, 32,
+};
+
+static const struct ad7380_chip_info ad7380_chip_info = {
+ .name = "ad7380",
+ .channels = ad7380_channels,
+ .num_channels = ARRAY_SIZE(ad7380_channels),
+ .available_scan_masks = ad7380_2_channel_scan_masks,
+ .timing_specs = &ad7380_timing,
+};
+
+static const struct ad7380_chip_info ad7381_chip_info = {
+ .name = "ad7381",
+ .channels = ad7381_channels,
+ .num_channels = ARRAY_SIZE(ad7381_channels),
+ .available_scan_masks = ad7380_2_channel_scan_masks,
+ .timing_specs = &ad7380_timing,
+};
+
+static const struct ad7380_chip_info ad7383_chip_info = {
+ .name = "ad7383",
+ .channels = ad7383_channels,
+ .num_channels = ARRAY_SIZE(ad7383_channels),
+ .vcm_supplies = ad7380_2_channel_vcm_supplies,
+ .num_vcm_supplies = ARRAY_SIZE(ad7380_2_channel_vcm_supplies),
+ .available_scan_masks = ad7380_2_channel_scan_masks,
+ .timing_specs = &ad7380_timing,
+};
+
+static const struct ad7380_chip_info ad7384_chip_info = {
+ .name = "ad7384",
+ .channels = ad7384_channels,
+ .num_channels = ARRAY_SIZE(ad7384_channels),
+ .vcm_supplies = ad7380_2_channel_vcm_supplies,
+ .num_vcm_supplies = ARRAY_SIZE(ad7380_2_channel_vcm_supplies),
+ .available_scan_masks = ad7380_2_channel_scan_masks,
+ .timing_specs = &ad7380_timing,
+};
+
+static const struct ad7380_chip_info ad7380_4_chip_info = {
+ .name = "ad7380-4",
+ .channels = ad7380_4_channels,
+ .num_channels = ARRAY_SIZE(ad7380_4_channels),
+ .available_scan_masks = ad7380_4_channel_scan_masks,
+ .timing_specs = &ad7380_4_timing,
+};
+
+static const struct ad7380_chip_info ad7381_4_chip_info = {
+ .name = "ad7381-4",
+ .channels = ad7381_4_channels,
+ .num_channels = ARRAY_SIZE(ad7381_4_channels),
+ .available_scan_masks = ad7380_4_channel_scan_masks,
+ .timing_specs = &ad7380_4_timing,
+};
+
+static const struct ad7380_chip_info ad7383_4_chip_info = {
+ .name = "ad7383-4",
+ .channels = ad7383_4_channels,
+ .num_channels = ARRAY_SIZE(ad7383_4_channels),
+ .vcm_supplies = ad7380_4_channel_vcm_supplies,
+ .num_vcm_supplies = ARRAY_SIZE(ad7380_4_channel_vcm_supplies),
+ .available_scan_masks = ad7380_4_channel_scan_masks,
+ .timing_specs = &ad7380_4_timing,
+};
+
+static const struct ad7380_chip_info ad7384_4_chip_info = {
+ .name = "ad7384-4",
+ .channels = ad7384_4_channels,
+ .num_channels = ARRAY_SIZE(ad7384_4_channels),
+ .vcm_supplies = ad7380_4_channel_vcm_supplies,
+ .num_vcm_supplies = ARRAY_SIZE(ad7380_4_channel_vcm_supplies),
+ .available_scan_masks = ad7380_4_channel_scan_masks,
+ .timing_specs = &ad7380_4_timing,
+};
+
+struct ad7380_state {
+ const struct ad7380_chip_info *chip_info;
+ struct spi_device *spi;
+ struct regmap *regmap;
+ unsigned int oversampling_ratio;
+ bool resolution_boost_enabled;
+ unsigned int vref_mv;
+ unsigned int vcm_mv[MAX_NUM_CHANNELS];
+ /* xfers, message an buffer for reading sample data */
+ struct spi_transfer xfer[2];
+ struct spi_message msg;
+ /*
+ * DMA (thus cache coherency maintenance) requires the transfer buffers
+ * to live in their own cache lines.
+ *
+ * Make the buffer large enough for MAX_NUM_CHANNELS 32-bit samples and
+ * one 64-bit aligned 64-bit timestamp.
+ */
+ u8 scan_data[ALIGN(MAX_NUM_CHANNELS * sizeof(u32), sizeof(s64))
+ + sizeof(s64)] __aligned(IIO_DMA_MINALIGN);
+ /* buffers for reading/writing registers */
+ u16 tx;
+ u16 rx;
+};
+
+static int ad7380_regmap_reg_write(void *context, unsigned int reg,
+ unsigned int val)
+{
+ struct ad7380_state *st = context;
+ struct spi_transfer xfer = {
+ .speed_hz = AD7380_REG_WR_SPEED_HZ,
+ .bits_per_word = 16,
+ .len = 2,
+ .tx_buf = &st->tx,
+ };
+
+ st->tx = FIELD_PREP(AD7380_REG_WR, 1) |
+ FIELD_PREP(AD7380_REG_REGADDR, reg) |
+ FIELD_PREP(AD7380_REG_DATA, val);
+
+ return spi_sync_transfer(st->spi, &xfer, 1);
+}
+
+static int ad7380_regmap_reg_read(void *context, unsigned int reg,
+ unsigned int *val)
+{
+ struct ad7380_state *st = context;
+ struct spi_transfer xfers[] = {
+ {
+ .speed_hz = AD7380_REG_WR_SPEED_HZ,
+ .bits_per_word = 16,
+ .len = 2,
+ .tx_buf = &st->tx,
+ .cs_change = 1,
+ .cs_change_delay = {
+ .value = st->chip_info->timing_specs->t_csh_ns,
+ .unit = SPI_DELAY_UNIT_NSECS,
+ },
+ }, {
+ .speed_hz = AD7380_REG_WR_SPEED_HZ,
+ .bits_per_word = 16,
+ .len = 2,
+ .rx_buf = &st->rx,
+ },
+ };
+ int ret;
+
+ st->tx = FIELD_PREP(AD7380_REG_WR, 0) |
+ FIELD_PREP(AD7380_REG_REGADDR, reg) |
+ FIELD_PREP(AD7380_REG_DATA, 0);
+
+ ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers));
+ if (ret < 0)
+ return ret;
+
+ *val = FIELD_GET(AD7380_REG_DATA, st->rx);
+
+ return 0;
+}
+
+static const struct regmap_config ad7380_regmap_config = {
+ .reg_bits = 3,
+ .val_bits = 12,
+ .reg_read = ad7380_regmap_reg_read,
+ .reg_write = ad7380_regmap_reg_write,
+ .max_register = AD7380_REG_ADDR_ALERT_HIGH_TH,
+ .can_sleep = true,
+};
+
+static int ad7380_debugfs_reg_access(struct iio_dev *indio_dev, u32 reg,
+ u32 writeval, u32 *readval)
+{
+ iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
+ struct ad7380_state *st = iio_priv(indio_dev);
+
+ if (readval)
+ return regmap_read(st->regmap, reg, readval);
+ else
+ return regmap_write(st->regmap, reg, writeval);
+ }
+ unreachable();
+}
+
+/**
+ * ad7380_update_xfers - update the SPI transfers base on the current scan type
+ * @st: device instance specific state
+ * @scan_type: current scan type
+ */
+static void ad7380_update_xfers(struct ad7380_state *st,
+ const struct iio_scan_type *scan_type)
+{
+ /*
+ * First xfer only triggers conversion and has to be long enough for
+ * all conversions to complete, which can be multiple conversion in the
+ * case of oversampling. Technically T_CONVERT_X_NS is lower for some
+ * chips, but we use the maximum value for simplicity for now.
+ */
+ if (st->oversampling_ratio > 1)
+ st->xfer[0].delay.value = T_CONVERT_0_NS + T_CONVERT_X_NS *
+ (st->oversampling_ratio - 1);
+ else
+ st->xfer[0].delay.value = T_CONVERT_NS;
+
+ st->xfer[0].delay.unit = SPI_DELAY_UNIT_NSECS;
+
+ /*
+ * Second xfer reads all channels. Data size depends on if resolution
+ * boost is enabled or not.
+ */
+ st->xfer[1].bits_per_word = scan_type->realbits;
+ st->xfer[1].len = BITS_TO_BYTES(scan_type->storagebits) *
+ (st->chip_info->num_channels - 1);
+}
+
+static int ad7380_triggered_buffer_preenable(struct iio_dev *indio_dev)
+{
+ struct ad7380_state *st = iio_priv(indio_dev);
+ const struct iio_scan_type *scan_type;
+
+ /*
+ * Currently, we always read all channels at the same time. The scan_type
+ * is the same for all channels, so we just pass the first channel.
+ */
+ scan_type = iio_get_current_scan_type(indio_dev, &indio_dev->channels[0]);
+ if (IS_ERR(scan_type))
+ return PTR_ERR(scan_type);
+
+ ad7380_update_xfers(st, scan_type);
+
+ return spi_optimize_message(st->spi, &st->msg);
+}
+
+static int ad7380_triggered_buffer_postdisable(struct iio_dev *indio_dev)
+{
+ struct ad7380_state *st = iio_priv(indio_dev);
+
+ spi_unoptimize_message(&st->msg);
+
+ return 0;
+}
+
+static const struct iio_buffer_setup_ops ad7380_buffer_setup_ops = {
+ .preenable = ad7380_triggered_buffer_preenable,
+ .postdisable = ad7380_triggered_buffer_postdisable,
+};
+
+static irqreturn_t ad7380_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct ad7380_state *st = iio_priv(indio_dev);
+ int ret;
+
+ ret = spi_sync(st->spi, &st->msg);
+ if (ret)
+ goto out;
+
+ iio_push_to_buffers_with_timestamp(indio_dev, &st->scan_data,
+ pf->timestamp);
+
+out:
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+static int ad7380_read_direct(struct ad7380_state *st, unsigned int scan_index,
+ const struct iio_scan_type *scan_type, int *val)
+{
+ int ret;
+
+ ad7380_update_xfers(st, scan_type);
+
+ ret = spi_sync(st->spi, &st->msg);
+ if (ret < 0)
+ return ret;
+
+ if (scan_type->storagebits > 16)
+ *val = sign_extend32(*(u32 *)(st->scan_data + 4 * scan_index),
+ scan_type->realbits - 1);
+ else
+ *val = sign_extend32(*(u16 *)(st->scan_data + 2 * scan_index),
+ scan_type->realbits - 1);
+
+ return IIO_VAL_INT;
+}
+
+static int ad7380_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long info)
+{
+ struct ad7380_state *st = iio_priv(indio_dev);
+ const struct iio_scan_type *scan_type;
+
+ scan_type = iio_get_current_scan_type(indio_dev, chan);
+
+ if (IS_ERR(scan_type))
+ return PTR_ERR(scan_type);
+
+ switch (info) {
+ case IIO_CHAN_INFO_RAW:
+ iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
+ return ad7380_read_direct(st, chan->scan_index,
+ scan_type, val);
+ }
+ unreachable();
+ case IIO_CHAN_INFO_SCALE:
+ /*
+ * According to the datasheet, the LSB size is:
+ * * (2 × VREF) / 2^N, for differential chips
+ * * VREF / 2^N, for pseudo-differential chips
+ * where N is the ADC resolution (i.e realbits)
+ */
+ *val = st->vref_mv;
+ *val2 = scan_type->realbits - chan->differential;
+
+ return IIO_VAL_FRACTIONAL_LOG2;
+ case IIO_CHAN_INFO_OFFSET:
+ /*
+ * According to IIO ABI, offset is applied before scale,
+ * so offset is: vcm_mv / scale
+ */
+ *val = st->vcm_mv[chan->channel] * (1 << scan_type->realbits)
+ / st->vref_mv;
+
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ *val = st->oversampling_ratio;
+
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad7380_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long mask)
+{
+ switch (mask) {
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ *vals = ad7380_oversampling_ratios;
+ *length = ARRAY_SIZE(ad7380_oversampling_ratios);
+ *type = IIO_VAL_INT;
+
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+}
+
+/**
+ * ad7380_osr_to_regval - convert ratio to OSR register value
+ * @ratio: ratio to check
+ *
+ * Check if ratio is present in the list of available ratios and return the
+ * corresponding value that needs to be written to the register to select that
+ * ratio.
+ *
+ * Returns: register value (0 to 7) or -EINVAL if there is not an exact match
+ */
+static int ad7380_osr_to_regval(int ratio)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ad7380_oversampling_ratios); i++) {
+ if (ratio == ad7380_oversampling_ratios[i])
+ return i;
+ }
+
+ return -EINVAL;
+}
+
+static int ad7380_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val,
+ int val2, long mask)
+{
+ struct ad7380_state *st = iio_priv(indio_dev);
+ int ret, osr, boost;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ osr = ad7380_osr_to_regval(val);
+ if (osr < 0)
+ return osr;
+
+ /* always enable resolution boost when oversampling is enabled */
+ boost = osr > 0 ? 1 : 0;
+
+ iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
+ ret = regmap_update_bits(st->regmap,
+ AD7380_REG_ADDR_CONFIG1,
+ AD7380_CONFIG1_OSR | AD7380_CONFIG1_RES,
+ FIELD_PREP(AD7380_CONFIG1_OSR, osr) |
+ FIELD_PREP(AD7380_CONFIG1_RES, boost));
+
+ if (ret)
+ return ret;
+
+ st->oversampling_ratio = val;
+ st->resolution_boost_enabled = boost;
+
+ /*
+ * Perform a soft reset. This will flush the oversampling
+ * block and FIFO but will maintain the content of the
+ * configurable registers.
+ */
+ return regmap_update_bits(st->regmap,
+ AD7380_REG_ADDR_CONFIG2,
+ AD7380_CONFIG2_RESET,
+ FIELD_PREP(AD7380_CONFIG2_RESET,
+ AD7380_CONFIG2_RESET_SOFT));
+ }
+ unreachable();
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad7380_get_current_scan_type(const struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan)
+{
+ struct ad7380_state *st = iio_priv(indio_dev);
+
+ return st->resolution_boost_enabled ? AD7380_SCAN_TYPE_RESOLUTION_BOOST
+ : AD7380_SCAN_TYPE_NORMAL;
+}
+
+static const struct iio_info ad7380_info = {
+ .read_raw = &ad7380_read_raw,
+ .read_avail = &ad7380_read_avail,
+ .write_raw = &ad7380_write_raw,
+ .get_current_scan_type = &ad7380_get_current_scan_type,
+ .debugfs_reg_access = &ad7380_debugfs_reg_access,
+};
+
+static int ad7380_init(struct ad7380_state *st, struct regulator *vref)
+{
+ int ret;
+
+ /* perform hard reset */
+ ret = regmap_update_bits(st->regmap, AD7380_REG_ADDR_CONFIG2,
+ AD7380_CONFIG2_RESET,
+ FIELD_PREP(AD7380_CONFIG2_RESET,
+ AD7380_CONFIG2_RESET_HARD));
+ if (ret < 0)
+ return ret;
+
+ /* select internal or external reference voltage */
+ ret = regmap_update_bits(st->regmap, AD7380_REG_ADDR_CONFIG1,
+ AD7380_CONFIG1_REFSEL,
+ FIELD_PREP(AD7380_CONFIG1_REFSEL,
+ vref ? 1 : 0));
+ if (ret < 0)
+ return ret;
+
+ /* This is the default value after reset. */
+ st->oversampling_ratio = 1;
+
+ /* SPI 1-wire mode */
+ return regmap_update_bits(st->regmap, AD7380_REG_ADDR_CONFIG2,
+ AD7380_CONFIG2_SDO,
+ FIELD_PREP(AD7380_CONFIG2_SDO, 1));
+}
+
+static void ad7380_regulator_disable(void *p)
+{
+ regulator_disable(p);
+}
+
+static int ad7380_probe(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev;
+ struct ad7380_state *st;
+ struct regulator *vref;
+ int ret, i;
+
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+ st->spi = spi;
+ st->chip_info = spi_get_device_match_data(spi);
+ if (!st->chip_info)
+ return dev_err_probe(&spi->dev, -EINVAL, "missing match data\n");
+
+ vref = devm_regulator_get_optional(&spi->dev, "refio");
+ if (IS_ERR(vref)) {
+ if (PTR_ERR(vref) != -ENODEV)
+ return dev_err_probe(&spi->dev, PTR_ERR(vref),
+ "Failed to get refio regulator\n");
+
+ vref = NULL;
+ }
+
+ /*
+ * If there is no REFIO supply, then it means that we are using
+ * the internal 2.5V reference, otherwise REFIO is reference voltage.
+ */
+ if (vref) {
+ ret = regulator_enable(vref);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(&spi->dev,
+ ad7380_regulator_disable, vref);
+ if (ret)
+ return ret;
+
+ ret = regulator_get_voltage(vref);
+ if (ret < 0)
+ return ret;
+
+ st->vref_mv = ret / 1000;
+ } else {
+ st->vref_mv = AD7380_INTERNAL_REF_MV;
+ }
+
+ if (st->chip_info->num_vcm_supplies > ARRAY_SIZE(st->vcm_mv))
+ return dev_err_probe(&spi->dev, -EINVAL,
+ "invalid number of VCM supplies\n");
+
+ /*
+ * pseudo-differential chips have common mode supplies for the negative
+ * input pin.
+ */
+ for (i = 0; i < st->chip_info->num_vcm_supplies; i++) {
+ struct regulator *vcm;
+
+ vcm = devm_regulator_get(&spi->dev,
+ st->chip_info->vcm_supplies[i]);
+ if (IS_ERR(vcm))
+ return dev_err_probe(&spi->dev, PTR_ERR(vcm),
+ "Failed to get %s regulator\n",
+ st->chip_info->vcm_supplies[i]);
+
+ ret = regulator_enable(vcm);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(&spi->dev,
+ ad7380_regulator_disable, vcm);
+ if (ret)
+ return ret;
+
+ ret = regulator_get_voltage(vcm);
+ if (ret < 0)
+ return ret;
+
+ st->vcm_mv[i] = ret / 1000;
+ }
+
+ st->regmap = devm_regmap_init(&spi->dev, NULL, st, &ad7380_regmap_config);
+ if (IS_ERR(st->regmap))
+ return dev_err_probe(&spi->dev, PTR_ERR(st->regmap),
+ "failed to allocate register map\n");
+
+ /*
+ * Setting up a low latency read for getting sample data. Used for both
+ * direct read an triggered buffer. Additional fields will be set up in
+ * ad7380_update_xfers() based on the current state of the driver at the
+ * time of the read.
+ */
+
+ /* toggle CS (no data xfer) to trigger a conversion */
+ st->xfer[0].cs_change = 1;
+ st->xfer[0].cs_change_delay.value = st->chip_info->timing_specs->t_csh_ns;
+ st->xfer[0].cs_change_delay.unit = SPI_DELAY_UNIT_NSECS;
+
+ /* then do a second xfer to read the data */
+ st->xfer[1].rx_buf = st->scan_data;
+
+ spi_message_init_with_transfers(&st->msg, st->xfer, ARRAY_SIZE(st->xfer));
+
+ indio_dev->channels = st->chip_info->channels;
+ indio_dev->num_channels = st->chip_info->num_channels;
+ indio_dev->name = st->chip_info->name;
+ indio_dev->info = &ad7380_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->available_scan_masks = st->chip_info->available_scan_masks;
+
+ ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev,
+ iio_pollfunc_store_time,
+ ad7380_trigger_handler,
+ &ad7380_buffer_setup_ops);
+ if (ret)
+ return ret;
+
+ ret = ad7380_init(st, vref);
+ if (ret)
+ return ret;
+
+ return devm_iio_device_register(&spi->dev, indio_dev);
+}
+
+static const struct of_device_id ad7380_of_match_table[] = {
+ { .compatible = "adi,ad7380", .data = &ad7380_chip_info },
+ { .compatible = "adi,ad7381", .data = &ad7381_chip_info },
+ { .compatible = "adi,ad7383", .data = &ad7383_chip_info },
+ { .compatible = "adi,ad7384", .data = &ad7384_chip_info },
+ { .compatible = "adi,ad7380-4", .data = &ad7380_4_chip_info },
+ { .compatible = "adi,ad7381-4", .data = &ad7381_4_chip_info },
+ { .compatible = "adi,ad7383-4", .data = &ad7383_4_chip_info },
+ { .compatible = "adi,ad7384-4", .data = &ad7384_4_chip_info },
+ { }
+};
+
+static const struct spi_device_id ad7380_id_table[] = {
+ { "ad7380", (kernel_ulong_t)&ad7380_chip_info },
+ { "ad7381", (kernel_ulong_t)&ad7381_chip_info },
+ { "ad7383", (kernel_ulong_t)&ad7383_chip_info },
+ { "ad7384", (kernel_ulong_t)&ad7384_chip_info },
+ { "ad7380-4", (kernel_ulong_t)&ad7380_4_chip_info },
+ { "ad7381-4", (kernel_ulong_t)&ad7381_4_chip_info },
+ { "ad7383-4", (kernel_ulong_t)&ad7383_4_chip_info },
+ { "ad7384-4", (kernel_ulong_t)&ad7384_4_chip_info },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, ad7380_id_table);
+
+static struct spi_driver ad7380_driver = {
+ .driver = {
+ .name = "ad7380",
+ .of_match_table = ad7380_of_match_table,
+ },
+ .probe = ad7380_probe,
+ .id_table = ad7380_id_table,
+};
+module_spi_driver(ad7380_driver);
+
+MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>");
+MODULE_DESCRIPTION("Analog Devices AD738x ADC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c
index 1928d9ae5bcf..3a417595294f 100644
--- a/drivers/iio/adc/ad7606.c
+++ b/drivers/iio/adc/ad7606.c
@@ -174,17 +174,14 @@ static int ad7606_read_raw(struct iio_dev *indio_dev,
switch (m) {
case IIO_CHAN_INFO_RAW:
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
-
- ret = ad7606_scan_direct(indio_dev, chan->address);
- iio_device_release_direct_mode(indio_dev);
-
- if (ret < 0)
- return ret;
- *val = (short)ret;
- return IIO_VAL_INT;
+ iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
+ ret = ad7606_scan_direct(indio_dev, chan->address);
+ if (ret < 0)
+ return ret;
+ *val = (short) ret;
+ return IIO_VAL_INT;
+ }
+ unreachable();
case IIO_CHAN_INFO_SCALE:
if (st->sw_mode_en)
ch = chan->address;
diff --git a/drivers/iio/adc/ad7944.c b/drivers/iio/adc/ad7944.c
index 4602ab5ed2a6..e2cb64cef476 100644
--- a/drivers/iio/adc/ad7944.c
+++ b/drivers/iio/adc/ad7944.c
@@ -259,7 +259,6 @@ static int ad7944_chain_mode_init_msg(struct device *dev, struct ad7944_adc *adc
/**
* ad7944_convert_and_acquire - Perform a single conversion and acquisition
* @adc: The ADC device structure
- * @chan: The channel specification
* Return: 0 on success, a negative error code on failure
*
* Perform a conversion and acquisition of a single sample using the
@@ -268,8 +267,7 @@ static int ad7944_chain_mode_init_msg(struct device *dev, struct ad7944_adc *adc
* Upon successful return adc->sample.raw will contain the conversion result
* (or adc->chain_mode_buf if the device is using chain mode).
*/
-static int ad7944_convert_and_acquire(struct ad7944_adc *adc,
- const struct iio_chan_spec *chan)
+static int ad7944_convert_and_acquire(struct ad7944_adc *adc)
{
int ret;
@@ -291,7 +289,7 @@ static int ad7944_single_conversion(struct ad7944_adc *adc,
{
int ret;
- ret = ad7944_convert_and_acquire(adc, chan);
+ ret = ad7944_convert_and_acquire(adc);
if (ret)
return ret;
@@ -361,7 +359,7 @@ static irqreturn_t ad7944_trigger_handler(int irq, void *p)
struct ad7944_adc *adc = iio_priv(indio_dev);
int ret;
- ret = ad7944_convert_and_acquire(adc, &indio_dev->channels[0]);
+ ret = ad7944_convert_and_acquire(adc);
if (ret)
goto out;
diff --git a/drivers/iio/adc/ad9467.c b/drivers/iio/adc/ad9467.c
index 8f5b9c3f6e3d..41c1b519c573 100644
--- a/drivers/iio/adc/ad9467.c
+++ b/drivers/iio/adc/ad9467.c
@@ -107,27 +107,27 @@
#define AD9647_MAX_TEST_POINTS 32
struct ad9467_chip_info {
- const char *name;
- unsigned int id;
- const struct iio_chan_spec *channels;
- unsigned int num_channels;
- const unsigned int (*scale_table)[2];
- int num_scales;
- unsigned long max_rate;
- unsigned int default_output_mode;
- unsigned int vref_mask;
- unsigned int num_lanes;
+ const char *name;
+ unsigned int id;
+ const struct iio_chan_spec *channels;
+ unsigned int num_channels;
+ const unsigned int (*scale_table)[2];
+ int num_scales;
+ unsigned long max_rate;
+ unsigned int default_output_mode;
+ unsigned int vref_mask;
+ unsigned int num_lanes;
/* data clock output */
- bool has_dco;
+ bool has_dco;
};
struct ad9467_state {
- const struct ad9467_chip_info *info;
- struct iio_backend *back;
- struct spi_device *spi;
- struct clk *clk;
- unsigned int output_mode;
- unsigned int (*scales)[2];
+ const struct ad9467_chip_info *info;
+ struct iio_backend *back;
+ struct spi_device *spi;
+ struct clk *clk;
+ unsigned int output_mode;
+ unsigned int (*scales)[2];
/*
* Times 2 because we may also invert the signal polarity and run the
* calibration again. For some reference on the test points (ad9265) see:
@@ -138,12 +138,13 @@ struct ad9467_state {
* at the io delay control section.
*/
DECLARE_BITMAP(calib_map, AD9647_MAX_TEST_POINTS * 2);
- struct gpio_desc *pwrdown_gpio;
+ struct gpio_desc *pwrdown_gpio;
/* ensure consistent state obtained on multiple related accesses */
- struct mutex lock;
+ struct mutex lock;
+ u8 buf[3] __aligned(IIO_DMA_MINALIGN);
};
-static int ad9467_spi_read(struct spi_device *spi, unsigned int reg)
+static int ad9467_spi_read(struct ad9467_state *st, unsigned int reg)
{
unsigned char tbuf[2], rbuf[1];
int ret;
@@ -151,7 +152,7 @@ static int ad9467_spi_read(struct spi_device *spi, unsigned int reg)
tbuf[0] = 0x80 | (reg >> 8);
tbuf[1] = reg & 0xFF;
- ret = spi_write_then_read(spi,
+ ret = spi_write_then_read(st->spi,
tbuf, ARRAY_SIZE(tbuf),
rbuf, ARRAY_SIZE(rbuf));
@@ -161,35 +162,32 @@ static int ad9467_spi_read(struct spi_device *spi, unsigned int reg)
return rbuf[0];
}
-static int ad9467_spi_write(struct spi_device *spi, unsigned int reg,
+static int ad9467_spi_write(struct ad9467_state *st, unsigned int reg,
unsigned int val)
{
- unsigned char buf[3];
-
- buf[0] = reg >> 8;
- buf[1] = reg & 0xFF;
- buf[2] = val;
+ st->buf[0] = reg >> 8;
+ st->buf[1] = reg & 0xFF;
+ st->buf[2] = val;
- return spi_write(spi, buf, ARRAY_SIZE(buf));
+ return spi_write(st->spi, st->buf, ARRAY_SIZE(st->buf));
}
static int ad9467_reg_access(struct iio_dev *indio_dev, unsigned int reg,
unsigned int writeval, unsigned int *readval)
{
struct ad9467_state *st = iio_priv(indio_dev);
- struct spi_device *spi = st->spi;
int ret;
if (!readval) {
guard(mutex)(&st->lock);
- ret = ad9467_spi_write(spi, reg, writeval);
+ ret = ad9467_spi_write(st, reg, writeval);
if (ret)
return ret;
- return ad9467_spi_write(spi, AN877_ADC_REG_TRANSFER,
+ return ad9467_spi_write(st, AN877_ADC_REG_TRANSFER,
AN877_ADC_TRANSFER_SYNC);
}
- ret = ad9467_spi_read(spi, reg);
+ ret = ad9467_spi_read(st, reg);
if (ret < 0)
return ret;
*readval = ret;
@@ -295,7 +293,7 @@ static int ad9467_get_scale(struct ad9467_state *st, int *val, int *val2)
unsigned int i, vref_val;
int ret;
- ret = ad9467_spi_read(st->spi, AN877_ADC_REG_VREF);
+ ret = ad9467_spi_read(st, AN877_ADC_REG_VREF);
if (ret < 0)
return ret;
@@ -330,31 +328,31 @@ static int ad9467_set_scale(struct ad9467_state *st, int val, int val2)
continue;
guard(mutex)(&st->lock);
- ret = ad9467_spi_write(st->spi, AN877_ADC_REG_VREF,
+ ret = ad9467_spi_write(st, AN877_ADC_REG_VREF,
info->scale_table[i][1]);
if (ret < 0)
return ret;
- return ad9467_spi_write(st->spi, AN877_ADC_REG_TRANSFER,
+ return ad9467_spi_write(st, AN877_ADC_REG_TRANSFER,
AN877_ADC_TRANSFER_SYNC);
}
return -EINVAL;
}
-static int ad9467_outputmode_set(struct spi_device *spi, unsigned int mode)
+static int ad9467_outputmode_set(struct ad9467_state *st, unsigned int mode)
{
int ret;
- ret = ad9467_spi_write(spi, AN877_ADC_REG_OUTPUT_MODE, mode);
+ ret = ad9467_spi_write(st, AN877_ADC_REG_OUTPUT_MODE, mode);
if (ret < 0)
return ret;
- return ad9467_spi_write(spi, AN877_ADC_REG_TRANSFER,
+ return ad9467_spi_write(st, AN877_ADC_REG_TRANSFER,
AN877_ADC_TRANSFER_SYNC);
}
-static int ad9647_calibrate_prepare(const struct ad9467_state *st)
+static int ad9647_calibrate_prepare(struct ad9467_state *st)
{
struct iio_backend_data_fmt data = {
.enable = false,
@@ -362,17 +360,17 @@ static int ad9647_calibrate_prepare(const struct ad9467_state *st)
unsigned int c;
int ret;
- ret = ad9467_spi_write(st->spi, AN877_ADC_REG_TEST_IO,
+ ret = ad9467_spi_write(st, AN877_ADC_REG_TEST_IO,
AN877_ADC_TESTMODE_PN9_SEQ);
if (ret)
return ret;
- ret = ad9467_spi_write(st->spi, AN877_ADC_REG_TRANSFER,
+ ret = ad9467_spi_write(st, AN877_ADC_REG_TRANSFER,
AN877_ADC_TRANSFER_SYNC);
if (ret)
return ret;
- ret = ad9467_outputmode_set(st->spi, st->info->default_output_mode);
+ ret = ad9467_outputmode_set(st, st->info->default_output_mode);
if (ret)
return ret;
@@ -390,7 +388,7 @@ static int ad9647_calibrate_prepare(const struct ad9467_state *st)
return iio_backend_chan_enable(st->back, 0);
}
-static int ad9647_calibrate_polarity_set(const struct ad9467_state *st,
+static int ad9647_calibrate_polarity_set(struct ad9467_state *st,
bool invert)
{
enum iio_backend_sample_trigger trigger;
@@ -401,7 +399,7 @@ static int ad9647_calibrate_polarity_set(const struct ad9467_state *st,
if (invert)
phase |= AN877_ADC_INVERT_DCO_CLK;
- return ad9467_spi_write(st->spi, AN877_ADC_REG_OUTPUT_PHASE,
+ return ad9467_spi_write(st, AN877_ADC_REG_OUTPUT_PHASE,
phase);
}
@@ -437,19 +435,18 @@ static unsigned int ad9467_find_optimal_point(const unsigned long *calib_map,
return cnt;
}
-static int ad9467_calibrate_apply(const struct ad9467_state *st,
- unsigned int val)
+static int ad9467_calibrate_apply(struct ad9467_state *st, unsigned int val)
{
unsigned int lane;
int ret;
if (st->info->has_dco) {
- ret = ad9467_spi_write(st->spi, AN877_ADC_REG_OUTPUT_DELAY,
+ ret = ad9467_spi_write(st, AN877_ADC_REG_OUTPUT_DELAY,
val);
if (ret)
return ret;
- return ad9467_spi_write(st->spi, AN877_ADC_REG_TRANSFER,
+ return ad9467_spi_write(st, AN877_ADC_REG_TRANSFER,
AN877_ADC_TRANSFER_SYNC);
}
@@ -462,7 +459,7 @@ static int ad9467_calibrate_apply(const struct ad9467_state *st,
return 0;
}
-static int ad9647_calibrate_stop(const struct ad9467_state *st)
+static int ad9647_calibrate_stop(struct ad9467_state *st)
{
struct iio_backend_data_fmt data = {
.sign_extend = true,
@@ -487,16 +484,16 @@ static int ad9647_calibrate_stop(const struct ad9467_state *st)
}
mode = st->info->default_output_mode | AN877_ADC_OUTPUT_MODE_TWOS_COMPLEMENT;
- ret = ad9467_outputmode_set(st->spi, mode);
+ ret = ad9467_outputmode_set(st, mode);
if (ret)
return ret;
- ret = ad9467_spi_write(st->spi, AN877_ADC_REG_TEST_IO,
+ ret = ad9467_spi_write(st, AN877_ADC_REG_TEST_IO,
AN877_ADC_TESTMODE_OFF);
if (ret)
return ret;
- return ad9467_spi_write(st->spi, AN877_ADC_REG_TRANSFER,
+ return ad9467_spi_write(st, AN877_ADC_REG_TRANSFER,
AN877_ADC_TRANSFER_SYNC);
}
@@ -846,7 +843,7 @@ static int ad9467_probe(struct spi_device *spi)
if (ret)
return ret;
- id = ad9467_spi_read(spi, AN877_ADC_REG_CHIP_ID);
+ id = ad9467_spi_read(st, AN877_ADC_REG_CHIP_ID);
if (id != st->info->id) {
dev_err(&spi->dev, "Mismatch CHIP_ID, got 0x%X, expected 0x%X\n",
id, st->info->id);
diff --git a/drivers/iio/adc/adi-axi-adc.c b/drivers/iio/adc/adi-axi-adc.c
index 0cf0d81358fd..0f8bd1d75131 100644
--- a/drivers/iio/adc/adi-axi-adc.c
+++ b/drivers/iio/adc/adi-axi-adc.c
@@ -42,6 +42,9 @@
#define ADI_AXI_ADC_REG_CTRL 0x0044
#define ADI_AXI_ADC_CTRL_DDR_EDGESEL_MASK BIT(1)
+#define ADI_AXI_ADC_REG_DRP_STATUS 0x0074
+#define ADI_AXI_ADC_DRP_LOCKED BIT(17)
+
/* ADC Channel controls */
#define ADI_AXI_REG_CHAN_CTRL(c) (0x0400 + (c) * 0x40)
@@ -83,14 +86,26 @@ struct adi_axi_adc_state {
static int axi_adc_enable(struct iio_backend *back)
{
struct adi_axi_adc_state *st = iio_backend_get_priv(back);
+ unsigned int __val;
int ret;
+ guard(mutex)(&st->lock);
ret = regmap_set_bits(st->regmap, ADI_AXI_REG_RSTN,
ADI_AXI_REG_RSTN_MMCM_RSTN);
if (ret)
return ret;
- fsleep(10000);
+ /*
+ * Make sure the DRP (Dynamic Reconfiguration Port) is locked. Not all
+ * designs really use it but if they don't we still get the lock bit
+ * set. So let's do it all the time so the code is generic.
+ */
+ ret = regmap_read_poll_timeout(st->regmap, ADI_AXI_ADC_REG_DRP_STATUS,
+ __val, __val & ADI_AXI_ADC_DRP_LOCKED,
+ 100, 1000);
+ if (ret)
+ return ret;
+
return regmap_set_bits(st->regmap, ADI_AXI_REG_RSTN,
ADI_AXI_REG_RSTN_RSTN | ADI_AXI_REG_RSTN_MMCM_RSTN);
}
@@ -99,6 +114,7 @@ static void axi_adc_disable(struct iio_backend *back)
{
struct adi_axi_adc_state *st = iio_backend_get_priv(back);
+ guard(mutex)(&st->lock);
regmap_write(st->regmap, ADI_AXI_REG_RSTN, 0);
}
diff --git a/drivers/iio/adc/axp20x_adc.c b/drivers/iio/adc/axp20x_adc.c
index d6c51b0f48e3..913ea9e5d9c5 100644
--- a/drivers/iio/adc/axp20x_adc.c
+++ b/drivers/iio/adc/axp20x_adc.c
@@ -22,11 +22,19 @@
#include <linux/iio/machine.h>
#include <linux/mfd/axp20x.h>
+#define AXP192_ADC_EN1_MASK GENMASK(7, 0)
+#define AXP192_ADC_EN2_MASK (GENMASK(3, 0) | BIT(7))
+
#define AXP20X_ADC_EN1_MASK GENMASK(7, 0)
#define AXP20X_ADC_EN2_MASK (GENMASK(3, 2) | BIT(7))
#define AXP22X_ADC_EN1_MASK (GENMASK(7, 5) | BIT(0))
+#define AXP192_GPIO30_IN_RANGE_GPIO0 BIT(0)
+#define AXP192_GPIO30_IN_RANGE_GPIO1 BIT(1)
+#define AXP192_GPIO30_IN_RANGE_GPIO2 BIT(2)
+#define AXP192_GPIO30_IN_RANGE_GPIO3 BIT(3)
+
#define AXP20X_GPIO10_IN_RANGE_GPIO0 BIT(0)
#define AXP20X_GPIO10_IN_RANGE_GPIO1 BIT(1)
@@ -71,6 +79,25 @@ struct axp20x_adc_iio {
const struct axp_data *data;
};
+enum axp192_adc_channel_v {
+ AXP192_ACIN_V = 0,
+ AXP192_VBUS_V,
+ AXP192_TS_IN,
+ AXP192_GPIO0_V,
+ AXP192_GPIO1_V,
+ AXP192_GPIO2_V,
+ AXP192_GPIO3_V,
+ AXP192_IPSOUT_V,
+ AXP192_BATT_V,
+};
+
+enum axp192_adc_channel_i {
+ AXP192_ACIN_I = 0,
+ AXP192_VBUS_I,
+ AXP192_BATT_CHRG_I,
+ AXP192_BATT_DISCHRG_I,
+};
+
enum axp20x_adc_channel_v {
AXP20X_ACIN_V = 0,
AXP20X_VBUS_V,
@@ -158,6 +185,43 @@ static struct iio_map axp22x_maps[] = {
* The only exception is for the battery. batt_v will be in_voltage6_raw and
* charge current in_current6_raw and discharge current will be in_current7_raw.
*/
+static const struct iio_chan_spec axp192_adc_channels[] = {
+ AXP20X_ADC_CHANNEL(AXP192_ACIN_V, "acin_v", IIO_VOLTAGE,
+ AXP20X_ACIN_V_ADC_H),
+ AXP20X_ADC_CHANNEL(AXP192_ACIN_I, "acin_i", IIO_CURRENT,
+ AXP20X_ACIN_I_ADC_H),
+ AXP20X_ADC_CHANNEL(AXP192_VBUS_V, "vbus_v", IIO_VOLTAGE,
+ AXP20X_VBUS_V_ADC_H),
+ AXP20X_ADC_CHANNEL(AXP192_VBUS_I, "vbus_i", IIO_CURRENT,
+ AXP20X_VBUS_I_ADC_H),
+ {
+ .type = IIO_TEMP,
+ .address = AXP20X_TEMP_ADC_H,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_OFFSET),
+ .datasheet_name = "pmic_temp",
+ },
+ AXP20X_ADC_CHANNEL_OFFSET(AXP192_GPIO0_V, "gpio0_v", IIO_VOLTAGE,
+ AXP20X_GPIO0_V_ADC_H),
+ AXP20X_ADC_CHANNEL_OFFSET(AXP192_GPIO1_V, "gpio1_v", IIO_VOLTAGE,
+ AXP20X_GPIO1_V_ADC_H),
+ AXP20X_ADC_CHANNEL_OFFSET(AXP192_GPIO2_V, "gpio2_v", IIO_VOLTAGE,
+ AXP192_GPIO2_V_ADC_H),
+ AXP20X_ADC_CHANNEL_OFFSET(AXP192_GPIO3_V, "gpio3_v", IIO_VOLTAGE,
+ AXP192_GPIO3_V_ADC_H),
+ AXP20X_ADC_CHANNEL(AXP192_IPSOUT_V, "ipsout_v", IIO_VOLTAGE,
+ AXP20X_IPSOUT_V_HIGH_H),
+ AXP20X_ADC_CHANNEL(AXP192_BATT_V, "batt_v", IIO_VOLTAGE,
+ AXP20X_BATT_V_H),
+ AXP20X_ADC_CHANNEL(AXP192_BATT_CHRG_I, "batt_chrg_i", IIO_CURRENT,
+ AXP20X_BATT_CHRG_I_H),
+ AXP20X_ADC_CHANNEL(AXP192_BATT_DISCHRG_I, "batt_dischrg_i", IIO_CURRENT,
+ AXP20X_BATT_DISCHRG_I_H),
+ AXP20X_ADC_CHANNEL(AXP192_TS_IN, "ts_v", IIO_VOLTAGE,
+ AXP20X_TS_IN_H),
+};
+
static const struct iio_chan_spec axp20x_adc_channels[] = {
AXP20X_ADC_CHANNEL(AXP20X_ACIN_V, "acin_v", IIO_VOLTAGE,
AXP20X_ACIN_V_ADC_H),
@@ -231,6 +295,27 @@ static const struct iio_chan_spec axp813_adc_channels[] = {
AXP288_TS_ADC_H),
};
+static int axp192_adc_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val)
+{
+ struct axp20x_adc_iio *info = iio_priv(indio_dev);
+ int ret, size;
+
+ if (chan->type == IIO_CURRENT &&
+ (chan->channel == AXP192_BATT_CHRG_I ||
+ chan->channel == AXP192_BATT_DISCHRG_I))
+ size = 13;
+ else
+ size = 12;
+
+ ret = axp20x_read_variable_width(info->regmap, chan->address, size);
+ if (ret < 0)
+ return ret;
+
+ *val = ret;
+ return IIO_VAL_INT;
+}
+
static int axp20x_adc_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val)
{
@@ -283,6 +368,44 @@ static int axp813_adc_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT;
}
+static int axp192_adc_scale_voltage(int channel, int *val, int *val2)
+{
+ switch (channel) {
+ case AXP192_ACIN_V:
+ case AXP192_VBUS_V:
+ *val = 1;
+ *val2 = 700000;
+ return IIO_VAL_INT_PLUS_MICRO;
+
+ case AXP192_GPIO0_V:
+ case AXP192_GPIO1_V:
+ case AXP192_GPIO2_V:
+ case AXP192_GPIO3_V:
+ *val = 0;
+ *val2 = 500000;
+ return IIO_VAL_INT_PLUS_MICRO;
+
+ case AXP192_BATT_V:
+ *val = 1;
+ *val2 = 100000;
+ return IIO_VAL_INT_PLUS_MICRO;
+
+ case AXP192_IPSOUT_V:
+ *val = 1;
+ *val2 = 400000;
+ return IIO_VAL_INT_PLUS_MICRO;
+
+ case AXP192_TS_IN:
+ /* 0.8 mV per LSB */
+ *val = 0;
+ *val2 = 800000;
+ return IIO_VAL_INT_PLUS_MICRO;
+
+ default:
+ return -EINVAL;
+ }
+}
+
static int axp20x_adc_scale_voltage(int channel, int *val, int *val2)
{
switch (channel) {
@@ -386,6 +509,29 @@ static int axp20x_adc_scale_current(int channel, int *val, int *val2)
}
}
+static int axp192_adc_scale(struct iio_chan_spec const *chan, int *val,
+ int *val2)
+{
+ switch (chan->type) {
+ case IIO_VOLTAGE:
+ return axp192_adc_scale_voltage(chan->channel, val, val2);
+
+ case IIO_CURRENT:
+ /*
+ * AXP192 current channels are identical to the AXP20x,
+ * therefore we can re-use the scaling function.
+ */
+ return axp20x_adc_scale_current(chan->channel, val, val2);
+
+ case IIO_TEMP:
+ *val = 100;
+ return IIO_VAL_INT;
+
+ default:
+ return -EINVAL;
+ }
+}
+
static int axp20x_adc_scale(struct iio_chan_spec const *chan, int *val,
int *val2)
{
@@ -445,6 +591,42 @@ static int axp813_adc_scale(struct iio_chan_spec const *chan, int *val,
}
}
+static int axp192_adc_offset_voltage(struct iio_dev *indio_dev, int channel,
+ int *val)
+{
+ struct axp20x_adc_iio *info = iio_priv(indio_dev);
+ unsigned int regval;
+ int ret;
+
+ ret = regmap_read(info->regmap, AXP192_GPIO30_IN_RANGE, &regval);
+ if (ret < 0)
+ return ret;
+
+ switch (channel) {
+ case AXP192_GPIO0_V:
+ regval = FIELD_GET(AXP192_GPIO30_IN_RANGE_GPIO0, regval);
+ break;
+
+ case AXP192_GPIO1_V:
+ regval = FIELD_GET(AXP192_GPIO30_IN_RANGE_GPIO1, regval);
+ break;
+
+ case AXP192_GPIO2_V:
+ regval = FIELD_GET(AXP192_GPIO30_IN_RANGE_GPIO2, regval);
+ break;
+
+ case AXP192_GPIO3_V:
+ regval = FIELD_GET(AXP192_GPIO30_IN_RANGE_GPIO3, regval);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ *val = regval ? 700000 : 0;
+ return IIO_VAL_INT;
+}
+
static int axp20x_adc_offset_voltage(struct iio_dev *indio_dev, int channel,
int *val)
{
@@ -473,6 +655,22 @@ static int axp20x_adc_offset_voltage(struct iio_dev *indio_dev, int channel,
return IIO_VAL_INT;
}
+static int axp192_adc_offset(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val)
+{
+ switch (chan->type) {
+ case IIO_VOLTAGE:
+ return axp192_adc_offset_voltage(indio_dev, chan->channel, val);
+
+ case IIO_TEMP:
+ *val = -1447;
+ return IIO_VAL_INT;
+
+ default:
+ return -EINVAL;
+ }
+}
+
static int axp20x_adc_offset(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val)
{
@@ -489,6 +687,25 @@ static int axp20x_adc_offset(struct iio_dev *indio_dev,
}
}
+static int axp192_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ switch (mask) {
+ case IIO_CHAN_INFO_OFFSET:
+ return axp192_adc_offset(indio_dev, chan, val);
+
+ case IIO_CHAN_INFO_SCALE:
+ return axp192_adc_scale(chan, val, val2);
+
+ case IIO_CHAN_INFO_RAW:
+ return axp192_adc_raw(indio_dev, chan, val);
+
+ default:
+ return -EINVAL;
+ }
+}
+
static int axp20x_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val,
int *val2, long mask)
@@ -549,6 +766,51 @@ static int axp813_read_raw(struct iio_dev *indio_dev,
}
}
+static int axp192_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val, int val2,
+ long mask)
+{
+ struct axp20x_adc_iio *info = iio_priv(indio_dev);
+ unsigned int regmask, regval;
+
+ /*
+ * The AXP192 PMIC allows the user to choose between 0V and 0.7V offsets
+ * for (independently) GPIO0-3 when in ADC mode.
+ */
+ if (mask != IIO_CHAN_INFO_OFFSET)
+ return -EINVAL;
+
+ if (val != 0 && val != 700000)
+ return -EINVAL;
+
+ switch (chan->channel) {
+ case AXP192_GPIO0_V:
+ regmask = AXP192_GPIO30_IN_RANGE_GPIO0;
+ regval = FIELD_PREP(AXP192_GPIO30_IN_RANGE_GPIO0, !!val);
+ break;
+
+ case AXP192_GPIO1_V:
+ regmask = AXP192_GPIO30_IN_RANGE_GPIO1;
+ regval = FIELD_PREP(AXP192_GPIO30_IN_RANGE_GPIO1, !!val);
+ break;
+
+ case AXP192_GPIO2_V:
+ regmask = AXP192_GPIO30_IN_RANGE_GPIO2;
+ regval = FIELD_PREP(AXP192_GPIO30_IN_RANGE_GPIO2, !!val);
+ break;
+
+ case AXP192_GPIO3_V:
+ regmask = AXP192_GPIO30_IN_RANGE_GPIO3;
+ regval = FIELD_PREP(AXP192_GPIO30_IN_RANGE_GPIO3, !!val);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return regmap_update_bits(info->regmap, AXP192_GPIO30_IN_RANGE, regmask, regval);
+}
+
static int axp20x_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val, int val2,
long mask)
@@ -584,6 +846,11 @@ static int axp20x_write_raw(struct iio_dev *indio_dev,
return regmap_update_bits(info->regmap, AXP20X_GPIO10_IN_RANGE, regmask, regval);
}
+static const struct iio_info axp192_adc_iio_info = {
+ .read_raw = axp192_read_raw,
+ .write_raw = axp192_write_raw,
+};
+
static const struct iio_info axp20x_adc_iio_info = {
.read_raw = axp20x_read_raw,
.write_raw = axp20x_write_raw,
@@ -629,6 +896,16 @@ struct axp_data {
struct iio_map *maps;
};
+static const struct axp_data axp192_data = {
+ .iio_info = &axp192_adc_iio_info,
+ .num_channels = ARRAY_SIZE(axp192_adc_channels),
+ .channels = axp192_adc_channels,
+ .adc_en1_mask = AXP192_ADC_EN1_MASK,
+ .adc_en2_mask = AXP192_ADC_EN2_MASK,
+ .adc_rate = axp20x_adc_rate,
+ .maps = axp20x_maps,
+};
+
static const struct axp_data axp20x_data = {
.iio_info = &axp20x_adc_iio_info,
.num_channels = ARRAY_SIZE(axp20x_adc_channels),
@@ -658,6 +935,7 @@ static const struct axp_data axp813_data = {
};
static const struct of_device_id axp20x_adc_of_match[] = {
+ { .compatible = "x-powers,axp192-adc", .data = (void *)&axp192_data, },
{ .compatible = "x-powers,axp209-adc", .data = (void *)&axp20x_data, },
{ .compatible = "x-powers,axp221-adc", .data = (void *)&axp22x_data, },
{ .compatible = "x-powers,axp813-adc", .data = (void *)&axp813_data, },
@@ -666,6 +944,7 @@ static const struct of_device_id axp20x_adc_of_match[] = {
MODULE_DEVICE_TABLE(of, axp20x_adc_of_match);
static const struct platform_device_id axp20x_adc_id_match[] = {
+ { .name = "axp192-adc", .driver_data = (kernel_ulong_t)&axp192_data, },
{ .name = "axp20x-adc", .driver_data = (kernel_ulong_t)&axp20x_data, },
{ .name = "axp22x-adc", .driver_data = (kernel_ulong_t)&axp22x_data, },
{ .name = "axp813-adc", .driver_data = (kernel_ulong_t)&axp813_data, },
diff --git a/drivers/iio/adc/ingenic-adc.c b/drivers/iio/adc/ingenic-adc.c
index a7325dbbb99a..af70ca760797 100644
--- a/drivers/iio/adc/ingenic-adc.c
+++ b/drivers/iio/adc/ingenic-adc.c
@@ -920,4 +920,5 @@ static struct platform_driver ingenic_adc_driver = {
.probe = ingenic_adc_probe,
};
module_platform_driver(ingenic_adc_driver);
+MODULE_DESCRIPTION("ADC driver for the Ingenic JZ47xx SoCs");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/ltc2485.c b/drivers/iio/adc/ltc2485.c
index 859e4314cfa2..060651dd4130 100644
--- a/drivers/iio/adc/ltc2485.c
+++ b/drivers/iio/adc/ltc2485.c
@@ -124,7 +124,7 @@ static int ltc2485_probe(struct i2c_client *client)
}
static const struct i2c_device_id ltc2485_id[] = {
- { "ltc2485", 0 },
+ { "ltc2485" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ltc2485_id);
diff --git a/drivers/iio/adc/max11205.c b/drivers/iio/adc/max11205.c
index 65fc32971ba5..9d8bc0b154dd 100644
--- a/drivers/iio/adc/max11205.c
+++ b/drivers/iio/adc/max11205.c
@@ -116,10 +116,7 @@ static int max11205_probe(struct spi_device *spi)
ad_sd_init(&st->sd, indio_dev, spi, &max11205_sigma_delta_info);
- st->chip_info = device_get_match_data(&spi->dev);
- if (!st->chip_info)
- st->chip_info =
- (const struct max11205_chip_info *)spi_get_device_id(spi)->driver_data;
+ st->chip_info = spi_get_device_match_data(spi);
indio_dev->name = st->chip_info->name;
indio_dev->modes = INDIO_DIRECT_MODE;
diff --git a/drivers/iio/adc/mcp3564.c b/drivers/iio/adc/mcp3564.c
index e2ae13f1e842..d83bed0e63d2 100644
--- a/drivers/iio/adc/mcp3564.c
+++ b/drivers/iio/adc/mcp3564.c
@@ -1114,7 +1114,6 @@ static int mcp3564_config(struct iio_dev *indio_dev)
{
struct mcp3564_state *adc = iio_priv(indio_dev);
struct device *dev = &adc->spi->dev;
- const struct spi_device_id *dev_id;
u8 tmp_reg;
u16 tmp_u16;
enum mcp3564_ids ids;
@@ -1212,11 +1211,6 @@ static int mcp3564_config(struct iio_dev *indio_dev)
* try using fallback compatible in device tree to deal with some newer part number.
*/
adc->chip_info = spi_get_device_match_data(adc->spi);
- if (!adc->chip_info) {
- dev_id = spi_get_device_id(adc->spi);
- adc->chip_info = (const struct mcp3564_chip_info *)dev_id->driver_data;
- }
-
adc->have_vref = adc->chip_info->have_vref;
} else {
adc->chip_info = &mcp3564_chip_infos_tbl[ids];
diff --git a/drivers/iio/adc/nau7802.c b/drivers/iio/adc/nau7802.c
index d9e1696df7ae..600151a62f1f 100644
--- a/drivers/iio/adc/nau7802.c
+++ b/drivers/iio/adc/nau7802.c
@@ -532,7 +532,7 @@ static int nau7802_probe(struct i2c_client *client)
}
static const struct i2c_device_id nau7802_i2c_id[] = {
- { "nau7802", 0 },
+ { "nau7802" },
{ }
};
MODULE_DEVICE_TABLE(i2c, nau7802_i2c_id);
diff --git a/drivers/iio/adc/pac1934.c b/drivers/iio/adc/pac1934.c
index 456f12faa348..ae24a27805ab 100644
--- a/drivers/iio/adc/pac1934.c
+++ b/drivers/iio/adc/pac1934.c
@@ -227,11 +227,6 @@ struct pac1934_features {
const char *name;
};
-struct samp_rate_mapping {
- u16 samp_rate;
- u8 shift2value;
-};
-
static const unsigned int samp_rate_map_tbl[] = {
[PAC1934_SAMP_1024SPS] = 1024,
[PAC1934_SAMP_256SPS] = 256,
diff --git a/drivers/iio/adc/ti-adc161s626.c b/drivers/iio/adc/ti-adc161s626.c
index b789891dcf49..f7c78d0dd449 100644
--- a/drivers/iio/adc/ti-adc161s626.c
+++ b/drivers/iio/adc/ti-adc161s626.c
@@ -137,17 +137,13 @@ static int ti_adc_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
-
- ret = ti_adc_read_measurement(data, chan, val);
- iio_device_release_direct_mode(indio_dev);
-
- if (ret)
- return ret;
-
- return IIO_VAL_INT;
+ iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
+ ret = ti_adc_read_measurement(data, chan, val);
+ if (ret)
+ return ret;
+ return IIO_VAL_INT;
+ }
+ unreachable();
case IIO_CHAN_INFO_SCALE:
ret = regulator_get_voltage(data->ref);
if (ret < 0)
diff --git a/drivers/iio/adc/ti-ads131e08.c b/drivers/iio/adc/ti-ads131e08.c
index cb04a29b3dba..96dd9366f8ff 100644
--- a/drivers/iio/adc/ti-ads131e08.c
+++ b/drivers/iio/adc/ti-ads131e08.c
@@ -802,9 +802,7 @@ static int ads131e08_probe(struct spi_device *spi)
unsigned long adc_clk_ns;
int ret;
- info = device_get_match_data(&spi->dev);
- if (!info)
- info = (void *)spi_get_device_id(spi)->driver_data;
+ info = spi_get_device_match_data(spi);
if (!info) {
dev_err(&spi->dev, "failed to get match data\n");
return -ENODEV;
diff --git a/drivers/iio/adc/ti-ads7924.c b/drivers/iio/adc/ti-ads7924.c
index afdbd04778a8..4da78302359b 100644
--- a/drivers/iio/adc/ti-ads7924.c
+++ b/drivers/iio/adc/ti-ads7924.c
@@ -447,7 +447,7 @@ static int ads7924_probe(struct i2c_client *client)
}
static const struct i2c_device_id ads7924_id[] = {
- { "ads7924", 0 },
+ { "ads7924" },
{}
};
MODULE_DEVICE_TABLE(i2c, ads7924_id);
diff --git a/drivers/iio/adc/ti-tsc2046.c b/drivers/iio/adc/ti-tsc2046.c
index 1bbb51a6683c..edcef8f11522 100644
--- a/drivers/iio/adc/ti-tsc2046.c
+++ b/drivers/iio/adc/ti-tsc2046.c
@@ -804,12 +804,7 @@ static int tsc2046_adc_probe(struct spi_device *spi)
return -EINVAL;
}
- dcfg = device_get_match_data(dev);
- if (!dcfg) {
- const struct spi_device_id *id = spi_get_device_id(spi);
-
- dcfg = (const struct tsc2046_adc_dcfg *)id->driver_data;
- }
+ dcfg = spi_get_device_match_data(spi);
if (!dcfg)
return -EINVAL;
diff --git a/drivers/iio/adc/xilinx-ams.c b/drivers/iio/adc/xilinx-ams.c
index f0b71a1220e0..ee45475c495b 100644
--- a/drivers/iio/adc/xilinx-ams.c
+++ b/drivers/iio/adc/xilinx-ams.c
@@ -1430,5 +1430,6 @@ static struct platform_driver ams_driver = {
};
module_platform_driver(ams_driver);
+MODULE_DESCRIPTION("Xilinx AMS driver");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Xilinx, Inc.");
diff --git a/drivers/iio/addac/ad74413r.c b/drivers/iio/addac/ad74413r.c
index cd26a16dc0ff..2410d72da49b 100644
--- a/drivers/iio/addac/ad74413r.c
+++ b/drivers/iio/addac/ad74413r.c
@@ -1365,16 +1365,9 @@ static int ad74413r_probe(struct spi_device *spi)
st->spi = spi;
st->dev = &spi->dev;
- st->chip_info = device_get_match_data(&spi->dev);
- if (!st->chip_info) {
- const struct spi_device_id *id = spi_get_device_id(spi);
-
- if (id)
- st->chip_info =
- (struct ad74413r_chip_info *)id->driver_data;
- if (!st->chip_info)
- return -EINVAL;
- }
+ st->chip_info = spi_get_device_match_data(spi);
+ if (!st->chip_info)
+ return -EINVAL;
mutex_init(&st->lock);
init_completion(&st->adc_data_completion);
diff --git a/drivers/iio/buffer/kfifo_buf.c b/drivers/iio/buffer/kfifo_buf.c
index 05b285f0eb22..38034c8bcc04 100644
--- a/drivers/iio/buffer/kfifo_buf.c
+++ b/drivers/iio/buffer/kfifo_buf.c
@@ -287,4 +287,5 @@ int devm_iio_kfifo_buffer_setup_ext(struct device *dev,
}
EXPORT_SYMBOL_GPL(devm_iio_kfifo_buffer_setup_ext);
+MODULE_DESCRIPTION("Industrial I/O buffering based on kfifo");
MODULE_LICENSE("GPL");
diff --git a/drivers/iio/chemical/Kconfig b/drivers/iio/chemical/Kconfig
index 02649ab81b3c..678a6adb9a75 100644
--- a/drivers/iio/chemical/Kconfig
+++ b/drivers/iio/chemical/Kconfig
@@ -76,6 +76,26 @@ config CCS811
Say Y here to build I2C interface support for the AMS
CCS811 VOC (Volatile Organic Compounds) sensor
+config ENS160
+ tristate "ScioSense ENS160 sensor driver"
+ depends on (I2C || SPI)
+ select REGMAP
+ select ENS160_I2C if I2C
+ select ENS160_SPI if SPI
+ help
+ Say yes here to build support for ScioSense ENS160 multi-gas sensor.
+
+ This driver can also be built as a module. If so, the module for I2C
+ would be called ens160_i2c and ens160_spi for SPI support.
+
+config ENS160_I2C
+ tristate
+ select REGMAP_I2C
+
+config ENS160_SPI
+ tristate
+ select REGMAP_SPI
+
config IAQCORE
tristate "AMS iAQ-Core VOC sensors"
depends on I2C
diff --git a/drivers/iio/chemical/Makefile b/drivers/iio/chemical/Makefile
index 2f3dee8bb779..4866db06bdc9 100644
--- a/drivers/iio/chemical/Makefile
+++ b/drivers/iio/chemical/Makefile
@@ -11,6 +11,9 @@ obj-$(CONFIG_BME680) += bme680_core.o
obj-$(CONFIG_BME680_I2C) += bme680_i2c.o
obj-$(CONFIG_BME680_SPI) += bme680_spi.o
obj-$(CONFIG_CCS811) += ccs811.o
+obj-$(CONFIG_ENS160) += ens160_core.o
+obj-$(CONFIG_ENS160_I2C) += ens160_i2c.o
+obj-$(CONFIG_ENS160_SPI) += ens160_spi.o
obj-$(CONFIG_IAQCORE) += ams-iaq-core.o
obj-$(CONFIG_PMS7003) += pms7003.o
obj-$(CONFIG_SCD30_CORE) += scd30_core.o
diff --git a/drivers/iio/chemical/ams-iaq-core.c b/drivers/iio/chemical/ams-iaq-core.c
index 164facac5db6..10156d794092 100644
--- a/drivers/iio/chemical/ams-iaq-core.c
+++ b/drivers/iio/chemical/ams-iaq-core.c
@@ -24,7 +24,7 @@ struct ams_iaqcore_reading {
u8 status;
__be32 resistance;
__be16 voc_ppb;
-} __attribute__((__packed__));
+} __packed;
struct ams_iaqcore_data {
struct i2c_client *client;
@@ -163,7 +163,7 @@ static int ams_iaqcore_probe(struct i2c_client *client)
}
static const struct i2c_device_id ams_iaqcore_id[] = {
- { "ams-iaq-core", 0 },
+ { "ams-iaq-core" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ams_iaqcore_id);
diff --git a/drivers/iio/chemical/bme680_i2c.c b/drivers/iio/chemical/bme680_i2c.c
index 1c7076cf91ca..7c4224d75955 100644
--- a/drivers/iio/chemical/bme680_i2c.c
+++ b/drivers/iio/chemical/bme680_i2c.c
@@ -36,8 +36,8 @@ static int bme680_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id bme680_i2c_id[] = {
- {"bme680", 0},
- {},
+ { "bme680" },
+ {}
};
MODULE_DEVICE_TABLE(i2c, bme680_i2c_id);
diff --git a/drivers/iio/chemical/ccs811.c b/drivers/iio/chemical/ccs811.c
index 87741f155c32..17d1bc518bf2 100644
--- a/drivers/iio/chemical/ccs811.c
+++ b/drivers/iio/chemical/ccs811.c
@@ -551,7 +551,7 @@ static void ccs811_remove(struct i2c_client *client)
}
static const struct i2c_device_id ccs811_id[] = {
- {"ccs811", 0},
+ { "ccs811" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ccs811_id);
diff --git a/drivers/iio/chemical/ens160.h b/drivers/iio/chemical/ens160.h
new file mode 100644
index 000000000000..f9f0575ce55d
--- /dev/null
+++ b/drivers/iio/chemical/ens160.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef ENS160_H_
+#define ENS160_H_
+
+int devm_ens160_core_probe(struct device *dev, struct regmap *regmap, int irq,
+ const char *name);
+
+extern const struct dev_pm_ops ens160_pm_ops;
+
+#endif
diff --git a/drivers/iio/chemical/ens160_core.c b/drivers/iio/chemical/ens160_core.c
new file mode 100644
index 000000000000..c1aa3b498d3b
--- /dev/null
+++ b/drivers/iio/chemical/ens160_core.c
@@ -0,0 +1,367 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ScioSense ENS160 multi-gas sensor driver
+ *
+ * Copyright (c) 2024 Gustavo Silva <gustavograzs@gmail.com>
+ *
+ * Datasheet:
+ * https://www.sciosense.com/wp-content/uploads/2023/12/ENS160-Datasheet.pdf
+ */
+
+#include <linux/bitfield.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include "ens160.h"
+
+#define ENS160_PART_ID 0x160
+
+#define ENS160_BOOTING_TIME_MS 10U
+
+#define ENS160_REG_PART_ID 0x00
+
+#define ENS160_REG_OPMODE 0x10
+
+#define ENS160_REG_CONFIG 0x11
+#define ENS160_REG_CONFIG_INTEN BIT(0)
+#define ENS160_REG_CONFIG_INTDAT BIT(1)
+#define ENS160_REG_CONFIG_INT_CFG BIT(5)
+
+#define ENS160_REG_MODE_DEEP_SLEEP 0x00
+#define ENS160_REG_MODE_IDLE 0x01
+#define ENS160_REG_MODE_STANDARD 0x02
+#define ENS160_REG_MODE_RESET 0xF0
+
+#define ENS160_REG_COMMAND 0x12
+#define ENS160_REG_COMMAND_GET_APPVER 0x0E
+#define ENS160_REG_COMMAND_CLRGPR 0xCC
+
+#define ENS160_REG_TEMP_IN 0x13
+#define ENS160_REG_RH_IN 0x15
+#define ENS160_REG_DEVICE_STATUS 0x20
+#define ENS160_REG_DATA_AQI 0x21
+#define ENS160_REG_DATA_TVOC 0x22
+#define ENS160_REG_DATA_ECO2 0x24
+#define ENS160_REG_DATA_T 0x30
+#define ENS160_REG_DATA_RH 0x32
+#define ENS160_REG_GPR_READ4 0x4C
+
+#define ENS160_STATUS_VALIDITY_FLAG GENMASK(3, 2)
+
+#define ENS160_STATUS_NORMAL 0x00
+
+struct ens160_data {
+ struct regmap *regmap;
+ /* Protect reads from the sensor */
+ struct mutex mutex;
+ struct {
+ __le16 chans[2];
+ s64 timestamp __aligned(8);
+ } scan __aligned(IIO_DMA_MINALIGN);
+ u8 fw_version[3];
+ __le16 buf;
+};
+
+static const struct iio_chan_spec ens160_channels[] = {
+ {
+ .type = IIO_CONCENTRATION,
+ .channel2 = IIO_MOD_VOC,
+ .modified = 1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ .address = ENS160_REG_DATA_TVOC,
+ .scan_index = 0,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 16,
+ .storagebits = 16,
+ .endianness = IIO_LE,
+ },
+ },
+ {
+ .type = IIO_CONCENTRATION,
+ .channel2 = IIO_MOD_CO2,
+ .modified = 1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ .address = ENS160_REG_DATA_ECO2,
+ .scan_index = 1,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 16,
+ .storagebits = 16,
+ .endianness = IIO_LE,
+ },
+ },
+ IIO_CHAN_SOFT_TIMESTAMP(2),
+};
+
+static int ens160_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct ens160_data *data = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
+ guard(mutex)(&data->mutex);
+ ret = regmap_bulk_read(data->regmap, chan->address,
+ &data->buf, sizeof(data->buf));
+ if (ret)
+ return ret;
+ *val = le16_to_cpu(data->buf);
+ return IIO_VAL_INT;
+ }
+ unreachable();
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->channel2) {
+ case IIO_MOD_CO2:
+ /* The sensor reads CO2 data as ppm */
+ *val = 0;
+ *val2 = 100;
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_MOD_VOC:
+ /* The sensor reads VOC data as ppb */
+ *val = 0;
+ *val2 = 100;
+ return IIO_VAL_INT_PLUS_NANO;
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ens160_set_mode(struct ens160_data *data, u8 mode)
+{
+ int ret;
+
+ ret = regmap_write(data->regmap, ENS160_REG_OPMODE, mode);
+ if (ret)
+ return ret;
+
+ msleep(ENS160_BOOTING_TIME_MS);
+
+ return 0;
+}
+
+static void ens160_set_idle(void *data)
+{
+ ens160_set_mode(data, ENS160_REG_MODE_IDLE);
+}
+
+static int ens160_chip_init(struct ens160_data *data)
+{
+ struct device *dev = regmap_get_device(data->regmap);
+ unsigned int status;
+ int ret;
+
+ ret = ens160_set_mode(data, ENS160_REG_MODE_RESET);
+ if (ret)
+ return ret;
+
+ ret = regmap_bulk_read(data->regmap, ENS160_REG_PART_ID, &data->buf,
+ sizeof(data->buf));
+ if (ret)
+ return ret;
+
+ if (le16_to_cpu(data->buf) != ENS160_PART_ID)
+ return -ENODEV;
+
+ ret = ens160_set_mode(data, ENS160_REG_MODE_IDLE);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(data->regmap, ENS160_REG_COMMAND,
+ ENS160_REG_COMMAND_CLRGPR);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(data->regmap, ENS160_REG_COMMAND,
+ ENS160_REG_COMMAND_GET_APPVER);
+ if (ret)
+ return ret;
+
+ ret = regmap_bulk_read(data->regmap, ENS160_REG_GPR_READ4,
+ data->fw_version, sizeof(data->fw_version));
+ if (ret)
+ return ret;
+
+ dev_info(dev, "firmware version: %u.%u.%u\n", data->fw_version[2],
+ data->fw_version[1], data->fw_version[0]);
+
+ ret = ens160_set_mode(data, ENS160_REG_MODE_STANDARD);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(dev, ens160_set_idle, data);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(data->regmap, ENS160_REG_DEVICE_STATUS, &status);
+ if (ret)
+ return ret;
+
+ if (FIELD_GET(ENS160_STATUS_VALIDITY_FLAG, status)
+ != ENS160_STATUS_NORMAL)
+ return -EINVAL;
+
+ return 0;
+}
+
+static const struct iio_info ens160_info = {
+ .read_raw = ens160_read_raw,
+};
+
+static int ens160_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ens160_data *data = iio_priv(indio_dev);
+
+ return ens160_set_mode(data, ENS160_REG_MODE_DEEP_SLEEP);
+}
+
+static int ens160_resume(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct ens160_data *data = iio_priv(indio_dev);
+ int ret;
+
+ ret = ens160_set_mode(data, ENS160_REG_MODE_IDLE);
+ if (ret)
+ return ret;
+
+ return ens160_set_mode(data, ENS160_REG_MODE_STANDARD);
+}
+EXPORT_NS_SIMPLE_DEV_PM_OPS(ens160_pm_ops, ens160_suspend, ens160_resume,
+ IIO_ENS160);
+
+static irqreturn_t ens160_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct ens160_data *data = iio_priv(indio_dev);
+ int ret;
+
+ guard(mutex)(&data->mutex);
+
+ ret = regmap_bulk_read(data->regmap, ENS160_REG_DATA_TVOC,
+ data->scan.chans, sizeof(data->scan.chans));
+ if (ret)
+ goto err;
+
+ iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
+ pf->timestamp);
+err:
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+static int ens160_set_trigger_state(struct iio_trigger *trig, bool state)
+{
+ struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+ struct ens160_data *data = iio_priv(indio_dev);
+ unsigned int int_bits = ENS160_REG_CONFIG_INTEN |
+ ENS160_REG_CONFIG_INTDAT |
+ ENS160_REG_CONFIG_INT_CFG;
+
+ if (state)
+ return regmap_set_bits(data->regmap, ENS160_REG_CONFIG,
+ int_bits);
+ else
+ return regmap_clear_bits(data->regmap, ENS160_REG_CONFIG,
+ int_bits);
+}
+
+static const struct iio_trigger_ops ens160_trigger_ops = {
+ .set_trigger_state = ens160_set_trigger_state,
+ .validate_device = iio_trigger_validate_own_device,
+};
+
+static int ens160_setup_trigger(struct iio_dev *indio_dev, int irq)
+{
+ struct device *dev = indio_dev->dev.parent;
+ struct iio_trigger *trig;
+ int ret;
+
+ trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name,
+ iio_device_id(indio_dev));
+ if (!trig)
+ return dev_err_probe(dev, -ENOMEM,
+ "failed to allocate trigger\n");
+
+ trig->ops = &ens160_trigger_ops;
+ iio_trigger_set_drvdata(trig, indio_dev);
+
+ ret = devm_iio_trigger_register(dev, trig);
+ if (ret)
+ return ret;
+
+ indio_dev->trig = iio_trigger_get(trig);
+
+ ret = devm_request_threaded_irq(dev, irq,
+ iio_trigger_generic_data_rdy_poll,
+ NULL,
+ IRQF_ONESHOT,
+ indio_dev->name,
+ indio_dev->trig);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to request irq\n");
+
+ return 0;
+}
+
+int devm_ens160_core_probe(struct device *dev, struct regmap *regmap, int irq,
+ const char *name)
+{
+ struct ens160_data *data;
+ struct iio_dev *indio_dev;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ data = iio_priv(indio_dev);
+ data->regmap = regmap;
+
+ indio_dev->name = name;
+ indio_dev->info = &ens160_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = ens160_channels;
+ indio_dev->num_channels = ARRAY_SIZE(ens160_channels);
+
+ if (irq > 0) {
+ ret = ens160_setup_trigger(indio_dev, irq);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to setup trigger\n");
+ }
+
+ ret = ens160_chip_init(data);
+ if (ret)
+ return dev_err_probe(dev, ret, "chip initialization failed\n");
+
+ mutex_init(&data->mutex);
+
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
+ iio_pollfunc_store_time,
+ ens160_trigger_handler, NULL);
+ if (ret)
+ return ret;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+EXPORT_SYMBOL_NS(devm_ens160_core_probe, IIO_ENS160);
+
+MODULE_AUTHOR("Gustavo Silva <gustavograzs@gmail.com>");
+MODULE_DESCRIPTION("ScioSense ENS160 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/chemical/ens160_i2c.c b/drivers/iio/chemical/ens160_i2c.c
new file mode 100644
index 000000000000..57a189a4c257
--- /dev/null
+++ b/drivers/iio/chemical/ens160_i2c.c
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ScioSense ENS160 multi-gas sensor I2C driver
+ *
+ * Copyright (c) 2024 Gustavo Silva <gustavograzs@gmail.com>
+ *
+ * 7-Bit I2C slave address is:
+ * - 0x52 if ADDR pin LOW
+ * - 0x53 if ADDR pin HIGH
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include "ens160.h"
+
+static const struct regmap_config ens160_regmap_i2c_conf = {
+ .reg_bits = 8,
+ .val_bits = 8,
+};
+
+static int ens160_i2c_probe(struct i2c_client *client)
+{
+ struct regmap *regmap;
+
+ regmap = devm_regmap_init_i2c(client, &ens160_regmap_i2c_conf);
+ if (IS_ERR(regmap))
+ return dev_err_probe(&client->dev, PTR_ERR(regmap),
+ "Failed to register i2c regmap\n");
+
+ return devm_ens160_core_probe(&client->dev, regmap, client->irq,
+ "ens160");
+}
+
+static const struct i2c_device_id ens160_i2c_id[] = {
+ { "ens160" },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ens160_i2c_id);
+
+static const struct of_device_id ens160_of_i2c_match[] = {
+ { .compatible = "sciosense,ens160" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ens160_of_i2c_match);
+
+static struct i2c_driver ens160_i2c_driver = {
+ .driver = {
+ .name = "ens160",
+ .of_match_table = ens160_of_i2c_match,
+ .pm = pm_sleep_ptr(&ens160_pm_ops),
+ },
+ .probe = ens160_i2c_probe,
+ .id_table = ens160_i2c_id,
+};
+module_i2c_driver(ens160_i2c_driver);
+
+MODULE_AUTHOR("Gustavo Silva <gustavograzs@gmail.com>");
+MODULE_DESCRIPTION("ScioSense ENS160 I2C driver");
+MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_ENS160);
diff --git a/drivers/iio/chemical/ens160_spi.c b/drivers/iio/chemical/ens160_spi.c
new file mode 100644
index 000000000000..10e4f5fd0f45
--- /dev/null
+++ b/drivers/iio/chemical/ens160_spi.c
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ScioSense ENS160 multi-gas sensor SPI driver
+ *
+ * Copyright (c) 2024 Gustavo Silva <gustavograzs@gmail.com>
+ */
+
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+
+#include "ens160.h"
+
+#define ENS160_SPI_READ BIT(0)
+
+static const struct regmap_config ens160_regmap_spi_conf = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .reg_shift = -1,
+ .read_flag_mask = ENS160_SPI_READ,
+};
+
+static int ens160_spi_probe(struct spi_device *spi)
+{
+ struct regmap *regmap;
+
+ regmap = devm_regmap_init_spi(spi, &ens160_regmap_spi_conf);
+ if (IS_ERR(regmap))
+ return dev_err_probe(&spi->dev, PTR_ERR(regmap),
+ "Failed to register spi regmap\n");
+
+ return devm_ens160_core_probe(&spi->dev, regmap, spi->irq, "ens160");
+}
+
+static const struct of_device_id ens160_spi_of_match[] = {
+ { .compatible = "sciosense,ens160" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ens160_spi_of_match);
+
+static const struct spi_device_id ens160_spi_id[] = {
+ { "ens160" },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, ens160_spi_id);
+
+static struct spi_driver ens160_spi_driver = {
+ .driver = {
+ .name = "ens160",
+ .of_match_table = ens160_spi_of_match,
+ .pm = pm_sleep_ptr(&ens160_pm_ops),
+ },
+ .probe = ens160_spi_probe,
+ .id_table = ens160_spi_id,
+};
+module_spi_driver(ens160_spi_driver);
+
+MODULE_AUTHOR("Gustavo Silva <gustavograzs@gmail.com>");
+MODULE_DESCRIPTION("ScioSense ENS160 SPI driver");
+MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_ENS160);
diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
index 3c2bf620f00f..fb48dddbcc20 100644
--- a/drivers/iio/dac/Kconfig
+++ b/drivers/iio/dac/Kconfig
@@ -149,6 +149,7 @@ config AD9739A
config ADI_AXI_DAC
tristate "Analog Devices Generic AXI DAC IP core driver"
+ depends on MICROBLAZE || NIOS2 || ARCH_ZYNQ || ARCH_ZYNQMP || ARCH_INTEL_SOCFPGA || COMPILE_TEST
select IIO_BUFFER
select IIO_BUFFER_DMAENGINE
select REGMAP_MMIO
diff --git a/drivers/iio/dac/ad3552r.c b/drivers/iio/dac/ad3552r.c
index 8aa942896b5b..ddc6c262f801 100644
--- a/drivers/iio/dac/ad3552r.c
+++ b/drivers/iio/dac/ad3552r.c
@@ -117,7 +117,7 @@
#define AD3552R_REG_ADDR_CH_INPUT_24B(ch) (0x4B - (1 - ch) * 3)
/* Useful defines */
-#define AD3552R_NUM_CH 2
+#define AD3552R_MAX_CH 2
#define AD3552R_MASK_CH(ch) BIT(ch)
#define AD3552R_MASK_ALL_CH GENMASK(1, 0)
#define AD3552R_MAX_REG_SIZE 3
@@ -139,8 +139,10 @@ enum ad3552r_ch_vref_select {
AD3552R_EXTERNAL_VREF_PIN_INPUT
};
-enum ad3542r_id {
+enum ad3552r_id {
+ AD3541R_ID = 0x400b,
AD3542R_ID = 0x4009,
+ AD3551R_ID = 0x400a,
AD3552R_ID = 0x4008,
};
@@ -261,17 +263,26 @@ struct ad3552r_ch_data {
bool range_override;
};
+struct ad3552r_model_data {
+ const char *model_name;
+ enum ad3552r_id chip_id;
+ unsigned int num_hw_channels;
+ const s32 (*ranges_table)[2];
+ int num_ranges;
+ bool requires_output_range;
+};
+
struct ad3552r_desc {
+ const struct ad3552r_model_data *model_data;
/* Used to look the spi bus for atomic operations where needed */
struct mutex lock;
struct gpio_desc *gpio_reset;
struct gpio_desc *gpio_ldac;
struct spi_device *spi;
- struct ad3552r_ch_data ch_data[AD3552R_NUM_CH];
- struct iio_chan_spec channels[AD3552R_NUM_CH + 1];
+ struct ad3552r_ch_data ch_data[AD3552R_MAX_CH];
+ struct iio_chan_spec channels[AD3552R_MAX_CH + 1];
unsigned long enabled_ch;
unsigned int num_ch;
- enum ad3542r_id chip_id;
};
static const u16 addr_mask_map[][2] = {
@@ -528,7 +539,7 @@ static int32_t ad3552r_trigger_hw_ldac(struct gpio_desc *ldac)
static int ad3552r_write_all_channels(struct ad3552r_desc *dac, u8 *data)
{
int err, len;
- u8 addr, buff[AD3552R_NUM_CH * AD3552R_MAX_REG_SIZE + 1];
+ u8 addr, buff[AD3552R_MAX_CH * AD3552R_MAX_REG_SIZE + 1];
addr = AD3552R_REG_ADDR_CH_INPUT_24B(1);
/* CH1 */
@@ -586,7 +597,7 @@ static irqreturn_t ad3552r_trigger_handler(int irq, void *p)
struct iio_buffer *buf = indio_dev->buffer;
struct ad3552r_desc *dac = iio_priv(indio_dev);
/* Maximum size of a scan */
- u8 buff[AD3552R_NUM_CH * AD3552R_MAX_REG_SIZE];
+ u8 buff[AD3552R_MAX_CH * AD3552R_MAX_REG_SIZE];
int err;
memset(buff, 0, sizeof(buff));
@@ -745,13 +756,8 @@ static void ad3552r_calc_gain_and_offset(struct ad3552r_desc *dac, s32 ch)
} else {
/* Normal range */
idx = dac->ch_data[ch].range;
- if (dac->chip_id == AD3542R_ID) {
- v_min = ad3542r_ch_ranges[idx][0];
- v_max = ad3542r_ch_ranges[idx][1];
- } else {
- v_min = ad3552r_ch_ranges[idx][0];
- v_max = ad3552r_ch_ranges[idx][1];
- }
+ v_min = dac->model_data->ranges_table[idx][0];
+ v_max = dac->model_data->ranges_table[idx][1];
}
/*
@@ -775,22 +781,14 @@ static void ad3552r_calc_gain_and_offset(struct ad3552r_desc *dac, s32 ch)
dac->ch_data[ch].offset_dec = div_s64(tmp, span);
}
-static int ad3552r_find_range(u16 id, s32 *vals)
+static int ad3552r_find_range(const struct ad3552r_model_data *model_data,
+ s32 *vals)
{
- int i, len;
- const s32 (*ranges)[2];
+ int i;
- if (id == AD3542R_ID) {
- len = ARRAY_SIZE(ad3542r_ch_ranges);
- ranges = ad3542r_ch_ranges;
- } else {
- len = ARRAY_SIZE(ad3552r_ch_ranges);
- ranges = ad3552r_ch_ranges;
- }
-
- for (i = 0; i < len; i++)
- if (vals[0] == ranges[i][0] * 1000 &&
- vals[1] == ranges[i][1] * 1000)
+ for (i = 0; i < model_data->num_ranges; i++)
+ if (vals[0] == model_data->ranges_table[i][0] * 1000 &&
+ vals[1] == model_data->ranges_table[i][1] * 1000)
return i;
return -EINVAL;
@@ -940,10 +938,10 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac)
if (err)
return dev_err_probe(dev, err,
"mandatory reg property missing\n");
- if (ch >= AD3552R_NUM_CH)
+ if (ch >= dac->model_data->num_hw_channels)
return dev_err_probe(dev, -EINVAL,
"reg must be less than %d\n",
- AD3552R_NUM_CH);
+ dac->model_data->num_hw_channels);
if (fwnode_property_present(child, "adi,output-range-microvolt")) {
err = fwnode_property_read_u32_array(child,
@@ -954,7 +952,7 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac)
return dev_err_probe(dev, err,
"adi,output-range-microvolt property could not be parsed\n");
- err = ad3552r_find_range(dac->chip_id, vals);
+ err = ad3552r_find_range(dac->model_data, vals);
if (err < 0)
return dev_err_probe(dev, err,
"Invalid adi,output-range-microvolt value\n");
@@ -967,9 +965,10 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac)
return err;
dac->ch_data[ch].range = val;
- } else if (dac->chip_id == AD3542R_ID) {
+ } else if (dac->model_data->requires_output_range) {
return dev_err_probe(dev, -EINVAL,
- "adi,output-range-microvolt is required for ad3542r\n");
+ "adi,output-range-microvolt is required for %s\n",
+ dac->model_data->model_name);
} else {
err = ad3552r_configure_custom_gain(dac, child, ch);
if (err)
@@ -989,7 +988,8 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac)
}
/* Disable unused channels */
- for_each_clear_bit(ch, &dac->enabled_ch, AD3552R_NUM_CH) {
+ for_each_clear_bit(ch, &dac->enabled_ch,
+ dac->model_data->num_hw_channels) {
err = ad3552r_set_ch_value(dac, AD3552R_CH_AMPLIFIER_POWERDOWN,
ch, 1);
if (err)
@@ -1032,7 +1032,7 @@ static int ad3552r_init(struct ad3552r_desc *dac)
}
id |= val << 8;
- if (id != dac->chip_id) {
+ if (id != dac->model_data->chip_id) {
dev_err(&dac->spi->dev, "Product id not matching\n");
return -ENODEV;
}
@@ -1042,7 +1042,6 @@ static int ad3552r_init(struct ad3552r_desc *dac)
static int ad3552r_probe(struct spi_device *spi)
{
- const struct spi_device_id *id = spi_get_device_id(spi);
struct ad3552r_desc *dac;
struct iio_dev *indio_dev;
int err;
@@ -1053,7 +1052,9 @@ static int ad3552r_probe(struct spi_device *spi)
dac = iio_priv(indio_dev);
dac->spi = spi;
- dac->chip_id = id->driver_data;
+ dac->model_data = spi_get_device_match_data(spi);
+ if (!dac->model_data)
+ return -EINVAL;
mutex_init(&dac->lock);
@@ -1062,10 +1063,7 @@ static int ad3552r_probe(struct spi_device *spi)
return err;
/* Config triggered buffer device */
- if (dac->chip_id == AD3552R_ID)
- indio_dev->name = "ad3552r";
- else
- indio_dev->name = "ad3542r";
+ indio_dev->name = dac->model_data->model_name;
indio_dev->dev.parent = &spi->dev;
indio_dev->info = &ad3552r_iio_info;
indio_dev->num_channels = dac->num_ch;
@@ -1083,16 +1081,68 @@ static int ad3552r_probe(struct spi_device *spi)
return devm_iio_device_register(&spi->dev, indio_dev);
}
+static const struct ad3552r_model_data ad3541r_model_data = {
+ .model_name = "ad3541r",
+ .chip_id = AD3541R_ID,
+ .num_hw_channels = 1,
+ .ranges_table = ad3542r_ch_ranges,
+ .num_ranges = ARRAY_SIZE(ad3542r_ch_ranges),
+ .requires_output_range = true,
+};
+
+static const struct ad3552r_model_data ad3542r_model_data = {
+ .model_name = "ad3542r",
+ .chip_id = AD3542R_ID,
+ .num_hw_channels = 2,
+ .ranges_table = ad3542r_ch_ranges,
+ .num_ranges = ARRAY_SIZE(ad3542r_ch_ranges),
+ .requires_output_range = true,
+};
+
+static const struct ad3552r_model_data ad3551r_model_data = {
+ .model_name = "ad3551r",
+ .chip_id = AD3551R_ID,
+ .num_hw_channels = 1,
+ .ranges_table = ad3552r_ch_ranges,
+ .num_ranges = ARRAY_SIZE(ad3552r_ch_ranges),
+ .requires_output_range = false,
+};
+
+static const struct ad3552r_model_data ad3552r_model_data = {
+ .model_name = "ad3552r",
+ .chip_id = AD3552R_ID,
+ .num_hw_channels = 2,
+ .ranges_table = ad3552r_ch_ranges,
+ .num_ranges = ARRAY_SIZE(ad3552r_ch_ranges),
+ .requires_output_range = false,
+};
+
static const struct spi_device_id ad3552r_id[] = {
- { "ad3542r", AD3542R_ID },
- { "ad3552r", AD3552R_ID },
+ {
+ .name = "ad3541r",
+ .driver_data = (kernel_ulong_t)&ad3541r_model_data
+ },
+ {
+ .name = "ad3542r",
+ .driver_data = (kernel_ulong_t)&ad3542r_model_data
+ },
+ {
+ .name = "ad3551r",
+ .driver_data = (kernel_ulong_t)&ad3551r_model_data
+ },
+ {
+ .name = "ad3552r",
+ .driver_data = (kernel_ulong_t)&ad3552r_model_data
+ },
{ }
};
MODULE_DEVICE_TABLE(spi, ad3552r_id);
static const struct of_device_id ad3552r_of_match[] = {
- { .compatible = "adi,ad3542r"},
- { .compatible = "adi,ad3552r"},
+ { .compatible = "adi,ad3541r", .data = &ad3541r_model_data },
+ { .compatible = "adi,ad3542r", .data = &ad3542r_model_data },
+ { .compatible = "adi,ad3551r", .data = &ad3551r_model_data },
+ { .compatible = "adi,ad3552r", .data = &ad3552r_model_data },
{ }
};
MODULE_DEVICE_TABLE(of, ad3552r_of_match);
diff --git a/drivers/iio/dac/max5522.c b/drivers/iio/dac/max5522.c
index 05034a306597..9f72155dcbc7 100644
--- a/drivers/iio/dac/max5522.c
+++ b/drivers/iio/dac/max5522.c
@@ -132,7 +132,6 @@ static const struct regmap_config max5522_regmap_config = {
static int max5522_spi_probe(struct spi_device *spi)
{
- const struct spi_device_id *id = spi_get_device_id(spi);
struct iio_dev *indio_dev;
struct max5522_state *state;
int ret;
@@ -144,13 +143,9 @@ static int max5522_spi_probe(struct spi_device *spi)
}
state = iio_priv(indio_dev);
- state->chip_info = device_get_match_data(&spi->dev);
- if (!state->chip_info) {
- state->chip_info =
- (struct max5522_chip_info *)(id->driver_data);
- if (!state->chip_info)
- return -EINVAL;
- }
+ state->chip_info = spi_get_device_match_data(spi);
+ if (!state->chip_info)
+ return -EINVAL;
state->vrefin_reg = devm_regulator_get(&spi->dev, "vrefin");
if (IS_ERR(state->vrefin_reg))
diff --git a/drivers/iio/dac/mcp4728.c b/drivers/iio/dac/mcp4728.c
index 5113f67ddc31..c449ca949465 100644
--- a/drivers/iio/dac/mcp4728.c
+++ b/drivers/iio/dac/mcp4728.c
@@ -591,7 +591,7 @@ static int mcp4728_probe(struct i2c_client *client)
}
static const struct i2c_device_id mcp4728_id[] = {
- { "mcp4728", 0 },
+ { "mcp4728" },
{}
};
MODULE_DEVICE_TABLE(i2c, mcp4728_id);
diff --git a/drivers/iio/frequency/adrf6780.c b/drivers/iio/frequency/adrf6780.c
index b4defb82f37e..3f46032c9275 100644
--- a/drivers/iio/frequency/adrf6780.c
+++ b/drivers/iio/frequency/adrf6780.c
@@ -9,7 +9,6 @@
#include <linux/bits.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
-#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/iio/iio.h>
diff --git a/drivers/iio/gyro/bmg160_i2c.c b/drivers/iio/gyro/bmg160_i2c.c
index 9c8e20c25e96..672d0b720f61 100644
--- a/drivers/iio/gyro/bmg160_i2c.c
+++ b/drivers/iio/gyro/bmg160_i2c.c
@@ -47,9 +47,9 @@ static const struct acpi_device_id bmg160_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, bmg160_acpi_match);
static const struct i2c_device_id bmg160_i2c_id[] = {
- {"bmg160", 0},
- {"bmi055_gyro", 0},
- {"bmi088_gyro", 0},
+ { "bmg160" },
+ { "bmi055_gyro" },
+ { "bmi088_gyro" },
{}
};
diff --git a/drivers/iio/gyro/fxas21002c_i2c.c b/drivers/iio/gyro/fxas21002c_i2c.c
index ee7f21b718e2..b1318a1ea41b 100644
--- a/drivers/iio/gyro/fxas21002c_i2c.c
+++ b/drivers/iio/gyro/fxas21002c_i2c.c
@@ -39,7 +39,7 @@ static void fxas21002c_i2c_remove(struct i2c_client *i2c)
}
static const struct i2c_device_id fxas21002c_i2c_id[] = {
- { "fxas21002c", 0 },
+ { "fxas21002c" },
{ }
};
MODULE_DEVICE_TABLE(i2c, fxas21002c_i2c_id);
diff --git a/drivers/iio/gyro/itg3200_core.c b/drivers/iio/gyro/itg3200_core.c
index 53fb92f0ac7e..cd8a2dae56cd 100644
--- a/drivers/iio/gyro/itg3200_core.c
+++ b/drivers/iio/gyro/itg3200_core.c
@@ -387,7 +387,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(itg3200_pm_ops, itg3200_suspend,
itg3200_resume);
static const struct i2c_device_id itg3200_id[] = {
- { "itg3200", 0 },
+ { "itg3200" },
{ }
};
MODULE_DEVICE_TABLE(i2c, itg3200_id);
diff --git a/drivers/iio/health/afe4404.c b/drivers/iio/health/afe4404.c
index 7768b07ef7a6..390fbb6effaf 100644
--- a/drivers/iio/health/afe4404.c
+++ b/drivers/iio/health/afe4404.c
@@ -582,7 +582,7 @@ static int afe4404_probe(struct i2c_client *client)
}
static const struct i2c_device_id afe4404_ids[] = {
- { "afe4404", 0 },
+ { "afe4404" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, afe4404_ids);
diff --git a/drivers/iio/health/max30100.c b/drivers/iio/health/max30100.c
index 6236b4d96137..1dc0df21450d 100644
--- a/drivers/iio/health/max30100.c
+++ b/drivers/iio/health/max30100.c
@@ -483,7 +483,7 @@ static void max30100_remove(struct i2c_client *client)
}
static const struct i2c_device_id max30100_id[] = {
- { "max30100", 0 },
+ { "max30100" },
{}
};
MODULE_DEVICE_TABLE(i2c, max30100_id);
diff --git a/drivers/iio/humidity/am2315.c b/drivers/iio/humidity/am2315.c
index 37a35d1153d5..a56474be5dd2 100644
--- a/drivers/iio/humidity/am2315.c
+++ b/drivers/iio/humidity/am2315.c
@@ -253,7 +253,7 @@ static int am2315_probe(struct i2c_client *client)
}
static const struct i2c_device_id am2315_i2c_id[] = {
- {"am2315", 0},
+ { "am2315" },
{}
};
MODULE_DEVICE_TABLE(i2c, am2315_i2c_id);
diff --git a/drivers/iio/humidity/hdc100x.c b/drivers/iio/humidity/hdc100x.c
index 202014da2785..9b355380c9bf 100644
--- a/drivers/iio/humidity/hdc100x.c
+++ b/drivers/iio/humidity/hdc100x.c
@@ -396,12 +396,12 @@ static int hdc100x_probe(struct i2c_client *client)
}
static const struct i2c_device_id hdc100x_id[] = {
- { "hdc100x", 0 },
- { "hdc1000", 0 },
- { "hdc1008", 0 },
- { "hdc1010", 0 },
- { "hdc1050", 0 },
- { "hdc1080", 0 },
+ { "hdc100x" },
+ { "hdc1000" },
+ { "hdc1008" },
+ { "hdc1010" },
+ { "hdc1050" },
+ { "hdc1080" },
{ }
};
MODULE_DEVICE_TABLE(i2c, hdc100x_id);
diff --git a/drivers/iio/humidity/si7005.c b/drivers/iio/humidity/si7005.c
index 9465908cc65e..0797ece1fcba 100644
--- a/drivers/iio/humidity/si7005.c
+++ b/drivers/iio/humidity/si7005.c
@@ -163,8 +163,8 @@ static int si7005_probe(struct i2c_client *client)
}
static const struct i2c_device_id si7005_id[] = {
- { "si7005", 0 },
- { "th02", 0 },
+ { "si7005" },
+ { "th02" },
{ }
};
MODULE_DEVICE_TABLE(i2c, si7005_id);
diff --git a/drivers/iio/humidity/si7020.c b/drivers/iio/humidity/si7020.c
index fb1006649328..ff2dba50c0a5 100644
--- a/drivers/iio/humidity/si7020.c
+++ b/drivers/iio/humidity/si7020.c
@@ -23,6 +23,7 @@
#include <linux/mod_devicetable.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
+#include <linux/stat.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@@ -33,17 +34,38 @@
#define SI7020CMD_TEMP_HOLD 0xE3
/* Software Reset */
#define SI7020CMD_RESET 0xFE
+#define SI7020CMD_USR_WRITE 0xE6
+/* "Heater Enabled" bit in the User Register */
+#define SI7020_USR_HEATER_EN BIT(2)
+#define SI7020CMD_HEATER_WRITE 0x51
+/* Heater current configuration bits */
+#define SI7020_HEATER_VAL GENMASK(3, 0)
+
+struct si7020_data {
+ struct i2c_client *client;
+ /* Lock for cached register values */
+ struct mutex lock;
+ u8 user_reg;
+ u8 heater_reg;
+};
+
+static const int si7020_heater_vals[] = { 0, 1, 0xF };
static int si7020_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val,
int *val2, long mask)
{
- struct i2c_client **client = iio_priv(indio_dev);
+ struct si7020_data *data = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
- ret = i2c_smbus_read_word_swapped(*client,
+ if (chan->type == IIO_CURRENT) {
+ *val = data->heater_reg;
+ return IIO_VAL_INT;
+ }
+
+ ret = i2c_smbus_read_word_swapped(data->client,
chan->type == IIO_TEMP ?
SI7020CMD_TEMP_HOLD :
SI7020CMD_RH_HOLD);
@@ -96,17 +118,118 @@ static const struct iio_chan_spec si7020_channels[] = {
.type = IIO_TEMP,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET),
+ },
+ {
+ .type = IIO_CURRENT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW),
+ .extend_name = "heater",
+ }
+};
+
+static int si7020_update_reg(struct si7020_data *data,
+ u8 *reg, u8 cmd, u8 mask, u8 val)
+{
+ u8 new = (*reg & ~mask) | val;
+ int ret;
+
+ ret = i2c_smbus_write_byte_data(data->client, cmd, new);
+ if (ret)
+ return ret;
+
+ *reg = new;
+
+ return 0;
+}
+
+static int si7020_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct si7020_data *data = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ if (chan->type != IIO_CURRENT || val2 != 0 ||
+ val < si7020_heater_vals[0] || val > si7020_heater_vals[2])
+ return -EINVAL;
+
+ scoped_guard(mutex, &data->lock)
+ ret = si7020_update_reg(data, &data->heater_reg,
+ SI7020CMD_HEATER_WRITE, SI7020_HEATER_VAL, val);
+ return ret;
+ default:
+ return -EINVAL;
}
+}
+
+static int si7020_read_available(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals,
+ int *type, int *length, long mask)
+{
+ if (mask != IIO_CHAN_INFO_RAW || chan->type != IIO_CURRENT)
+ return -EINVAL;
+
+ *vals = si7020_heater_vals;
+ *type = IIO_VAL_INT;
+
+ return IIO_AVAIL_RANGE;
+}
+
+static ssize_t si7020_show_heater_en(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct si7020_data *data = iio_priv(indio_dev);
+
+ return sysfs_emit(buf, "%d\n", !!(data->user_reg & SI7020_USR_HEATER_EN));
+}
+
+static ssize_t si7020_store_heater_en(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct si7020_data *data = iio_priv(indio_dev);
+ int ret;
+ bool val;
+
+ ret = kstrtobool(buf, &val);
+ if (ret)
+ return ret;
+
+ scoped_guard(mutex, &data->lock)
+ ret = si7020_update_reg(data, &data->user_reg, SI7020CMD_USR_WRITE,
+ SI7020_USR_HEATER_EN, val ? SI7020_USR_HEATER_EN : 0);
+
+ return ret < 0 ? ret : len;
+}
+
+static IIO_DEVICE_ATTR(heater_enable, 0644,
+ si7020_show_heater_en, si7020_store_heater_en, 0);
+
+static struct attribute *si7020_attributes[] = {
+ &iio_dev_attr_heater_enable.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group si7020_attribute_group = {
+ .attrs = si7020_attributes,
};
static const struct iio_info si7020_info = {
.read_raw = si7020_read_raw,
+ .write_raw = si7020_write_raw,
+ .read_avail = si7020_read_available,
+ .attrs = &si7020_attribute_group,
};
static int si7020_probe(struct i2c_client *client)
{
struct iio_dev *indio_dev;
- struct i2c_client **data;
+ struct si7020_data *data;
int ret;
if (!i2c_check_functionality(client->adapter,
@@ -126,7 +249,9 @@ static int si7020_probe(struct i2c_client *client)
return -ENOMEM;
data = iio_priv(indio_dev);
- *data = client;
+ i2c_set_clientdata(client, indio_dev);
+ data->client = client;
+ mutex_init(&data->lock);
indio_dev->name = dev_name(&client->dev);
indio_dev->modes = INDIO_DIRECT_MODE;
@@ -134,12 +259,16 @@ static int si7020_probe(struct i2c_client *client)
indio_dev->channels = si7020_channels;
indio_dev->num_channels = ARRAY_SIZE(si7020_channels);
+ /* All the "reserved" bits in the User Register are 1s by default */
+ data->user_reg = 0x3A;
+ data->heater_reg = 0x0;
+
return devm_iio_device_register(&client->dev, indio_dev);
}
static const struct i2c_device_id si7020_id[] = {
- { "si7020", 0 },
- { "th06", 0 },
+ { "si7020" },
+ { "th06" },
{ }
};
MODULE_DEVICE_TABLE(i2c, si7020_id);
diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig
index 52a155ff3250..782fb80e44c2 100644
--- a/drivers/iio/imu/Kconfig
+++ b/drivers/iio/imu/Kconfig
@@ -36,8 +36,8 @@ config ADIS16475
select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
help
Say yes here to build support for Analog Devices ADIS16470, ADIS16475,
- ADIS16477, ADIS16465, ADIS16467, ADIS16500, ADIS16505, ADIS16507 inertial
- sensors.
+ ADIS16477, ADIS16465, ADIS16467, ADIS16500, ADIS16501, ADIS16505,
+ ADIS16507 inertial sensors.
To compile this driver as a module, choose M here: the module will be
called adis16475.
diff --git a/drivers/iio/imu/adis16475.c b/drivers/iio/imu/adis16475.c
index 060a21c70460..cf73c6f46c79 100644
--- a/drivers/iio/imu/adis16475.c
+++ b/drivers/iio/imu/adis16475.c
@@ -14,6 +14,7 @@
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
#include <linux/iio/imu/adis.h>
+#include <linux/iio/sysfs.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/irq.h>
#include <linux/lcm.h>
@@ -52,6 +53,8 @@
FIELD_PREP(ADIS16475_MSG_CTRL_DR_POL_MASK, x)
#define ADIS16475_SYNC_MODE_MASK GENMASK(4, 2)
#define ADIS16475_SYNC_MODE(x) FIELD_PREP(ADIS16475_SYNC_MODE_MASK, x)
+#define ADIS16575_SYNC_4KHZ_MASK BIT(11)
+#define ADIS16575_SYNC_4KHZ(x) FIELD_PREP(ADIS16575_SYNC_4KHZ_MASK, x)
#define ADIS16475_REG_UP_SCALE 0x62
#define ADIS16475_REG_DEC_RATE 0x64
#define ADIS16475_REG_GLOB_CMD 0x68
@@ -65,15 +68,32 @@
#define ADIS16500_BURST32_MASK BIT(9)
#define ADIS16500_BURST32(x) FIELD_PREP(ADIS16500_BURST32_MASK, x)
/* number of data elements in burst mode */
-#define ADIS16475_BURST32_MAX_DATA 32
+#define ADIS16475_BURST32_MAX_DATA_NO_TS32 32
+#define ADIS16575_BURST32_DATA_TS32 34
#define ADIS16475_BURST_MAX_DATA 20
#define ADIS16475_MAX_SCAN_DATA 20
/* spi max speed in brust mode */
#define ADIS16475_BURST_MAX_SPEED 1000000
+#define ADIS16575_BURST_MAX_SPEED 8000000
#define ADIS16475_LSB_DEC_MASK 0
#define ADIS16475_LSB_FIR_MASK 1
#define ADIS16500_BURST_DATA_SEL_0_CHN_MASK GENMASK(5, 0)
#define ADIS16500_BURST_DATA_SEL_1_CHN_MASK GENMASK(12, 7)
+#define ADIS16575_MAX_FIFO_WM 511UL
+#define ADIS16475_REG_FIFO_CTRL 0x5A
+#define ADIS16575_WM_LVL_MASK GENMASK(15, 4)
+#define ADIS16575_WM_LVL(x) FIELD_PREP(ADIS16575_WM_LVL_MASK, x)
+#define ADIS16575_WM_POL_MASK BIT(3)
+#define ADIS16575_WM_POL(x) FIELD_PREP(ADIS16575_WM_POL_MASK, x)
+#define ADIS16575_WM_EN_MASK BIT(2)
+#define ADIS16575_WM_EN(x) FIELD_PREP(ADIS16575_WM_EN_MASK, x)
+#define ADIS16575_OVERFLOW_MASK BIT(1)
+#define ADIS16575_STOP_ENQUEUE FIELD_PREP(ADIS16575_OVERFLOW_MASK, 0)
+#define ADIS16575_OVERWRITE_OLDEST FIELD_PREP(ADIS16575_OVERFLOW_MASK, 1)
+#define ADIS16575_FIFO_EN_MASK BIT(0)
+#define ADIS16575_FIFO_EN(x) FIELD_PREP(ADIS16575_FIFO_EN_MASK, x)
+#define ADIS16575_FIFO_FLUSH_CMD BIT(5)
+#define ADIS16575_REG_FIFO_CNT 0x3C
enum {
ADIS16475_SYNC_DIRECT = 1,
@@ -95,6 +115,8 @@ struct adis16475_chip_info {
const char *name;
#define ADIS16475_HAS_BURST32 BIT(0)
#define ADIS16475_HAS_BURST_DELTA_DATA BIT(1)
+#define ADIS16475_HAS_TIMESTAMP32 BIT(2)
+#define ADIS16475_NEEDS_BURST_REQUEST BIT(3)
const long flags;
u32 num_channels;
u32 gyro_max_val;
@@ -116,6 +138,7 @@ struct adis16475 {
bool burst32;
unsigned long lsb_flag;
u16 sync_mode;
+ u16 fifo_watermark;
/* Alignment needed for the timestamp */
__be16 data[ADIS16475_MAX_SCAN_DATA] __aligned(8);
};
@@ -310,6 +333,9 @@ static int adis16475_set_freq(struct adis16475 *st, const u32 freq)
u16 dec;
int ret;
u32 sample_rate = st->clk_freq;
+ /* The optimal sample rate for the supported IMUs is between int_clk - 100 and int_clk + 100. */
+ u32 max_sample_rate = st->info->int_clk * 1000 + 100000;
+ u32 min_sample_rate = st->info->int_clk * 1000 - 100000;
if (!freq)
return -EINVAL;
@@ -317,8 +343,9 @@ static int adis16475_set_freq(struct adis16475 *st, const u32 freq)
adis_dev_lock(&st->adis);
/*
* When using sync scaled mode, the input clock needs to be scaled so that we have
- * an IMU sample rate between (optimally) 1900 and 2100. After this, we can use the
- * decimation filter to lower the sampling rate in order to get what the user wants.
+ * an IMU sample rate between (optimally) int_clk - 100 and int_clk + 100.
+ * After this, we can use the decimation filter to lower the sampling rate in order
+ * to get what the user wants.
* Optimally, the user sample rate is a multiple of both the IMU sample rate and
* the input clock. Hence, calculating the sync_scale dynamically gives us better
* chances of achieving a perfect/integer value for DEC_RATE. The math here is:
@@ -336,23 +363,24 @@ static int adis16475_set_freq(struct adis16475 *st, const u32 freq)
* solution. In this case, we get the highest multiple of the input clock
* lower than the IMU max sample rate.
*/
- if (scaled_rate > 2100000)
- scaled_rate = 2100000 / st->clk_freq * st->clk_freq;
+ if (scaled_rate > max_sample_rate)
+ scaled_rate = max_sample_rate / st->clk_freq * st->clk_freq;
else
- scaled_rate = 2100000 / scaled_rate * scaled_rate;
+ scaled_rate = max_sample_rate / scaled_rate * scaled_rate;
/*
* This is not an hard requirement but it's not advised to run the IMU
- * with a sample rate lower than 1900Hz due to possible undersampling
- * issues. However, there are users that might really want to take the risk.
- * Hence, we provide a module parameter for them. If set, we allow sample
- * rates lower than 1.9KHz. By default, we won't allow this and we just roundup
- * the rate to the next multiple of the input clock bigger than 1.9KHz. This
- * is done like this as in some cases (when DEC_RATE is 0) might give
- * us the closest value to the one desired by the user...
+ * with a sample rate lower than internal clock frequency, due to possible
+ * undersampling issues. However, there are users that might really want
+ * to take the risk. Hence, we provide a module parameter for them. If set,
+ * we allow sample rates lower than internal clock frequency.
+ * By default, we won't allow this and we just roundup the rate to the next
+ * multiple of the input clock. This is done like this as in some cases
+ * (when DEC_RATE is 0) might give us the closest value to the one desired
+ * by the user...
*/
- if (scaled_rate < 1900000 && !low_rate_allow)
- scaled_rate = roundup(1900000, st->clk_freq);
+ if (scaled_rate < min_sample_rate && !low_rate_allow)
+ scaled_rate = roundup(min_sample_rate, st->clk_freq);
sync_scale = scaled_rate / st->clk_freq;
ret = __adis_write_reg_16(&st->adis, ADIS16475_REG_UP_SCALE, sync_scale);
@@ -437,6 +465,124 @@ static int adis16475_set_filter(struct adis16475 *st, const u32 filter)
return 0;
}
+static ssize_t adis16475_get_fifo_enabled(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct adis16475 *st = iio_priv(indio_dev);
+ int ret;
+ u16 val;
+
+ ret = adis_read_reg_16(&st->adis, ADIS16475_REG_FIFO_CTRL, &val);
+ if (ret)
+ return ret;
+
+ return sysfs_emit(buf, "%lu\n", FIELD_GET(ADIS16575_FIFO_EN_MASK, val));
+}
+
+static ssize_t adis16475_get_fifo_watermark(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct adis16475 *st = iio_priv(indio_dev);
+ int ret;
+ u16 val;
+
+ ret = adis_read_reg_16(&st->adis, ADIS16475_REG_FIFO_CTRL, &val);
+ if (ret)
+ return ret;
+
+ return sysfs_emit(buf, "%lu\n", FIELD_GET(ADIS16575_WM_LVL_MASK, val) + 1);
+}
+
+static ssize_t hwfifo_watermark_min_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sysfs_emit(buf, "1\n");
+}
+
+static ssize_t hwfifo_watermark_max_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sysfs_emit(buf, "%lu\n", ADIS16575_MAX_FIFO_WM);
+}
+
+static IIO_DEVICE_ATTR_RO(hwfifo_watermark_min, 0);
+static IIO_DEVICE_ATTR_RO(hwfifo_watermark_max, 0);
+static IIO_DEVICE_ATTR(hwfifo_watermark, 0444,
+ adis16475_get_fifo_watermark, NULL, 0);
+static IIO_DEVICE_ATTR(hwfifo_enabled, 0444,
+ adis16475_get_fifo_enabled, NULL, 0);
+
+static const struct iio_dev_attr *adis16475_fifo_attributes[] = {
+ &iio_dev_attr_hwfifo_watermark_min,
+ &iio_dev_attr_hwfifo_watermark_max,
+ &iio_dev_attr_hwfifo_watermark,
+ &iio_dev_attr_hwfifo_enabled,
+ NULL
+};
+
+static int adis16475_buffer_postenable(struct iio_dev *indio_dev)
+{
+ struct adis16475 *st = iio_priv(indio_dev);
+ struct adis *adis = &st->adis;
+
+ return adis_update_bits(adis, ADIS16475_REG_FIFO_CTRL,
+ ADIS16575_FIFO_EN_MASK, (u16)ADIS16575_FIFO_EN(1));
+}
+
+static int adis16475_buffer_postdisable(struct iio_dev *indio_dev)
+{
+ struct adis16475 *st = iio_priv(indio_dev);
+ struct adis *adis = &st->adis;
+ int ret;
+
+ adis_dev_lock(&st->adis);
+
+ ret = __adis_update_bits(adis, ADIS16475_REG_FIFO_CTRL,
+ ADIS16575_FIFO_EN_MASK, (u16)ADIS16575_FIFO_EN(0));
+ if (ret)
+ goto unlock;
+
+ ret = __adis_write_reg_16(adis, ADIS16475_REG_GLOB_CMD,
+ ADIS16575_FIFO_FLUSH_CMD);
+
+unlock:
+ adis_dev_unlock(&st->adis);
+ return ret;
+}
+
+static const struct iio_buffer_setup_ops adis16475_buffer_ops = {
+ .postenable = adis16475_buffer_postenable,
+ .postdisable = adis16475_buffer_postdisable,
+};
+
+static int adis16475_set_watermark(struct iio_dev *indio_dev, unsigned int val)
+{
+ struct adis16475 *st = iio_priv(indio_dev);
+ int ret;
+ u16 wm_lvl;
+
+ adis_dev_lock(&st->adis);
+
+ val = min_t(unsigned int, val, ADIS16575_MAX_FIFO_WM);
+
+ wm_lvl = ADIS16575_WM_LVL(val - 1);
+ ret = __adis_update_bits(&st->adis, ADIS16475_REG_FIFO_CTRL, ADIS16575_WM_LVL_MASK, wm_lvl);
+ if (ret)
+ goto unlock;
+
+ st->fifo_watermark = val;
+
+unlock:
+ adis_dev_unlock(&st->adis);
+ return ret;
+}
+
static const u32 adis16475_calib_regs[] = {
[ADIS16475_SCAN_GYRO_X] = ADIS16475_REG_X_GYRO_BIAS_L,
[ADIS16475_SCAN_GYRO_Y] = ADIS16475_REG_Y_GYRO_BIAS_L,
@@ -646,6 +792,22 @@ static const struct iio_chan_spec adis16475_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(7)
};
+static const struct iio_chan_spec adis16575_channels[] = {
+ ADIS16475_GYRO_CHANNEL(X),
+ ADIS16475_GYRO_CHANNEL(Y),
+ ADIS16475_GYRO_CHANNEL(Z),
+ ADIS16475_ACCEL_CHANNEL(X),
+ ADIS16475_ACCEL_CHANNEL(Y),
+ ADIS16475_ACCEL_CHANNEL(Z),
+ ADIS16475_TEMP_CHANNEL(),
+ ADIS16475_DELTANG_CHAN(X),
+ ADIS16475_DELTANG_CHAN(Y),
+ ADIS16475_DELTANG_CHAN(Z),
+ ADIS16475_DELTVEL_CHAN(X),
+ ADIS16475_DELTVEL_CHAN(Y),
+ ADIS16475_DELTVEL_CHAN(Z),
+};
+
enum adis16475_variant {
ADIS16470,
ADIS16475_1,
@@ -661,12 +823,19 @@ enum adis16475_variant {
ADIS16467_2,
ADIS16467_3,
ADIS16500,
+ ADIS16501,
ADIS16505_1,
ADIS16505_2,
ADIS16505_3,
ADIS16507_1,
ADIS16507_2,
ADIS16507_3,
+ ADIS16575_2,
+ ADIS16575_3,
+ ADIS16576_2,
+ ADIS16576_3,
+ ADIS16577_2,
+ ADIS16577_3,
};
enum {
@@ -689,32 +858,33 @@ static const char * const adis16475_status_error_msgs[] = {
[ADIS16475_DIAG_STAT_CLK] = "Clock error",
};
-#define ADIS16475_DATA(_prod_id, _timeouts) \
-{ \
- .msc_ctrl_reg = ADIS16475_REG_MSG_CTRL, \
- .glob_cmd_reg = ADIS16475_REG_GLOB_CMD, \
- .diag_stat_reg = ADIS16475_REG_DIAG_STAT, \
- .prod_id_reg = ADIS16475_REG_PROD_ID, \
- .prod_id = (_prod_id), \
- .self_test_mask = BIT(2), \
- .self_test_reg = ADIS16475_REG_GLOB_CMD, \
- .cs_change_delay = 16, \
- .read_delay = 5, \
- .write_delay = 5, \
- .status_error_msgs = adis16475_status_error_msgs, \
- .status_error_mask = BIT(ADIS16475_DIAG_STAT_DATA_PATH) | \
- BIT(ADIS16475_DIAG_STAT_FLASH_MEM) | \
- BIT(ADIS16475_DIAG_STAT_SPI) | \
- BIT(ADIS16475_DIAG_STAT_STANDBY) | \
- BIT(ADIS16475_DIAG_STAT_SENSOR) | \
- BIT(ADIS16475_DIAG_STAT_MEMORY) | \
- BIT(ADIS16475_DIAG_STAT_CLK), \
- .unmasked_drdy = true, \
- .timeouts = (_timeouts), \
- .burst_reg_cmd = ADIS16475_REG_GLOB_CMD, \
- .burst_len = ADIS16475_BURST_MAX_DATA, \
- .burst_max_len = ADIS16475_BURST32_MAX_DATA, \
- .burst_max_speed_hz = ADIS16475_BURST_MAX_SPEED \
+#define ADIS16475_DATA(_prod_id, _timeouts, _burst_max_len, _burst_max_speed_hz, _has_fifo) \
+{ \
+ .msc_ctrl_reg = ADIS16475_REG_MSG_CTRL, \
+ .glob_cmd_reg = ADIS16475_REG_GLOB_CMD, \
+ .diag_stat_reg = ADIS16475_REG_DIAG_STAT, \
+ .prod_id_reg = ADIS16475_REG_PROD_ID, \
+ .prod_id = (_prod_id), \
+ .self_test_mask = BIT(2), \
+ .self_test_reg = ADIS16475_REG_GLOB_CMD, \
+ .cs_change_delay = 16, \
+ .read_delay = 5, \
+ .write_delay = 5, \
+ .status_error_msgs = adis16475_status_error_msgs, \
+ .status_error_mask = BIT(ADIS16475_DIAG_STAT_DATA_PATH) | \
+ BIT(ADIS16475_DIAG_STAT_FLASH_MEM) | \
+ BIT(ADIS16475_DIAG_STAT_SPI) | \
+ BIT(ADIS16475_DIAG_STAT_STANDBY) | \
+ BIT(ADIS16475_DIAG_STAT_SENSOR) | \
+ BIT(ADIS16475_DIAG_STAT_MEMORY) | \
+ BIT(ADIS16475_DIAG_STAT_CLK), \
+ .unmasked_drdy = true, \
+ .has_fifo = _has_fifo, \
+ .timeouts = (_timeouts), \
+ .burst_reg_cmd = ADIS16475_REG_GLOB_CMD, \
+ .burst_len = ADIS16475_BURST_MAX_DATA, \
+ .burst_max_len = _burst_max_len, \
+ .burst_max_speed_hz = _burst_max_speed_hz \
}
static const struct adis16475_sync adis16475_sync_mode[] = {
@@ -724,6 +894,12 @@ static const struct adis16475_sync adis16475_sync_mode[] = {
{ ADIS16475_SYNC_PULSE, 1000, 2100 },
};
+static const struct adis16475_sync adis16575_sync_mode[] = {
+ { ADIS16475_SYNC_OUTPUT },
+ { ADIS16475_SYNC_DIRECT, 1900, 4100 },
+ { ADIS16475_SYNC_SCALED, 1, 400 },
+};
+
static const struct adis_timeout adis16475_timeouts = {
.reset_ms = 200,
.sw_reset_ms = 200,
@@ -752,7 +928,9 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
.max_dec = 1999,
.sync = adis16475_sync_mode,
.num_sync = ARRAY_SIZE(adis16475_sync_mode),
- .adis_data = ADIS16475_DATA(16470, &adis16475_timeouts),
+ .adis_data = ADIS16475_DATA(16470, &adis16475_timeouts,
+ ADIS16475_BURST32_MAX_DATA_NO_TS32,
+ ADIS16475_BURST_MAX_SPEED, false),
},
[ADIS16475_1] = {
.name = "adis16475-1",
@@ -769,7 +947,9 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
.max_dec = 1999,
.sync = adis16475_sync_mode,
.num_sync = ARRAY_SIZE(adis16475_sync_mode),
- .adis_data = ADIS16475_DATA(16475, &adis16475_timeouts),
+ .adis_data = ADIS16475_DATA(16475, &adis16475_timeouts,
+ ADIS16475_BURST32_MAX_DATA_NO_TS32,
+ ADIS16475_BURST_MAX_SPEED, false),
},
[ADIS16475_2] = {
.name = "adis16475-2",
@@ -786,7 +966,9 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
.max_dec = 1999,
.sync = adis16475_sync_mode,
.num_sync = ARRAY_SIZE(adis16475_sync_mode),
- .adis_data = ADIS16475_DATA(16475, &adis16475_timeouts),
+ .adis_data = ADIS16475_DATA(16475, &adis16475_timeouts,
+ ADIS16475_BURST32_MAX_DATA_NO_TS32,
+ ADIS16475_BURST_MAX_SPEED, false),
},
[ADIS16475_3] = {
.name = "adis16475-3",
@@ -803,7 +985,9 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
.max_dec = 1999,
.sync = adis16475_sync_mode,
.num_sync = ARRAY_SIZE(adis16475_sync_mode),
- .adis_data = ADIS16475_DATA(16475, &adis16475_timeouts),
+ .adis_data = ADIS16475_DATA(16475, &adis16475_timeouts,
+ ADIS16475_BURST32_MAX_DATA_NO_TS32,
+ ADIS16475_BURST_MAX_SPEED, false),
},
[ADIS16477_1] = {
.name = "adis16477-1",
@@ -821,7 +1005,9 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
.sync = adis16475_sync_mode,
.num_sync = ARRAY_SIZE(adis16475_sync_mode),
.flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
- .adis_data = ADIS16475_DATA(16477, &adis16475_timeouts),
+ .adis_data = ADIS16475_DATA(16477, &adis16475_timeouts,
+ ADIS16475_BURST32_MAX_DATA_NO_TS32,
+ ADIS16475_BURST_MAX_SPEED, false),
},
[ADIS16477_2] = {
.name = "adis16477-2",
@@ -839,7 +1025,9 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
.sync = adis16475_sync_mode,
.num_sync = ARRAY_SIZE(adis16475_sync_mode),
.flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
- .adis_data = ADIS16475_DATA(16477, &adis16475_timeouts),
+ .adis_data = ADIS16475_DATA(16477, &adis16475_timeouts,
+ ADIS16475_BURST32_MAX_DATA_NO_TS32,
+ ADIS16475_BURST_MAX_SPEED, false),
},
[ADIS16477_3] = {
.name = "adis16477-3",
@@ -857,7 +1045,9 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
.sync = adis16475_sync_mode,
.num_sync = ARRAY_SIZE(adis16475_sync_mode),
.flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
- .adis_data = ADIS16475_DATA(16477, &adis16475_timeouts),
+ .adis_data = ADIS16475_DATA(16477, &adis16475_timeouts,
+ ADIS16475_BURST32_MAX_DATA_NO_TS32,
+ ADIS16475_BURST_MAX_SPEED, false),
},
[ADIS16465_1] = {
.name = "adis16465-1",
@@ -874,7 +1064,9 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
.max_dec = 1999,
.sync = adis16475_sync_mode,
.num_sync = ARRAY_SIZE(adis16475_sync_mode),
- .adis_data = ADIS16475_DATA(16465, &adis16475_timeouts),
+ .adis_data = ADIS16475_DATA(16465, &adis16475_timeouts,
+ ADIS16475_BURST32_MAX_DATA_NO_TS32,
+ ADIS16475_BURST_MAX_SPEED, false),
},
[ADIS16465_2] = {
.name = "adis16465-2",
@@ -891,7 +1083,9 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
.max_dec = 1999,
.sync = adis16475_sync_mode,
.num_sync = ARRAY_SIZE(adis16475_sync_mode),
- .adis_data = ADIS16475_DATA(16465, &adis16475_timeouts),
+ .adis_data = ADIS16475_DATA(16465, &adis16475_timeouts,
+ ADIS16475_BURST32_MAX_DATA_NO_TS32,
+ ADIS16475_BURST_MAX_SPEED, false),
},
[ADIS16465_3] = {
.name = "adis16465-3",
@@ -908,7 +1102,9 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
.max_dec = 1999,
.sync = adis16475_sync_mode,
.num_sync = ARRAY_SIZE(adis16475_sync_mode),
- .adis_data = ADIS16475_DATA(16465, &adis16475_timeouts),
+ .adis_data = ADIS16475_DATA(16465, &adis16475_timeouts,
+ ADIS16475_BURST32_MAX_DATA_NO_TS32,
+ ADIS16475_BURST_MAX_SPEED, false),
},
[ADIS16467_1] = {
.name = "adis16467-1",
@@ -925,7 +1121,9 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
.max_dec = 1999,
.sync = adis16475_sync_mode,
.num_sync = ARRAY_SIZE(adis16475_sync_mode),
- .adis_data = ADIS16475_DATA(16467, &adis16475_timeouts),
+ .adis_data = ADIS16475_DATA(16467, &adis16475_timeouts,
+ ADIS16475_BURST32_MAX_DATA_NO_TS32,
+ ADIS16475_BURST_MAX_SPEED, false),
},
[ADIS16467_2] = {
.name = "adis16467-2",
@@ -942,7 +1140,9 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
.max_dec = 1999,
.sync = adis16475_sync_mode,
.num_sync = ARRAY_SIZE(adis16475_sync_mode),
- .adis_data = ADIS16475_DATA(16467, &adis16475_timeouts),
+ .adis_data = ADIS16475_DATA(16467, &adis16475_timeouts,
+ ADIS16475_BURST32_MAX_DATA_NO_TS32,
+ ADIS16475_BURST_MAX_SPEED, false),
},
[ADIS16467_3] = {
.name = "adis16467-3",
@@ -959,7 +1159,9 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
.max_dec = 1999,
.sync = adis16475_sync_mode,
.num_sync = ARRAY_SIZE(adis16475_sync_mode),
- .adis_data = ADIS16475_DATA(16467, &adis16475_timeouts),
+ .adis_data = ADIS16475_DATA(16467, &adis16475_timeouts,
+ ADIS16475_BURST32_MAX_DATA_NO_TS32,
+ ADIS16475_BURST_MAX_SPEED, false),
},
[ADIS16500] = {
.name = "adis16500",
@@ -978,7 +1180,30 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
/* pulse sync not supported */
.num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1,
.flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
- .adis_data = ADIS16475_DATA(16500, &adis1650x_timeouts),
+ .adis_data = ADIS16475_DATA(16500, &adis1650x_timeouts,
+ ADIS16475_BURST32_MAX_DATA_NO_TS32,
+ ADIS16475_BURST_MAX_SPEED, false),
+ },
+ [ADIS16501] = {
+ .name = "adis16501",
+ .num_channels = ARRAY_SIZE(adis16477_channels),
+ .channels = adis16477_channels,
+ .gyro_max_val = 1,
+ .gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16),
+ .accel_max_val = 1,
+ .accel_max_scale = IIO_M_S_2_TO_G(800 << 16),
+ .temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(720),
+ .deltvel_max_val = 125,
+ .int_clk = 2000,
+ .max_dec = 1999,
+ .sync = adis16475_sync_mode,
+ /* pulse sync not supported */
+ .num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1,
+ .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
+ .adis_data = ADIS16475_DATA(16501, &adis1650x_timeouts,
+ ADIS16475_BURST32_MAX_DATA_NO_TS32,
+ ADIS16475_BURST_MAX_SPEED, false),
},
[ADIS16505_1] = {
.name = "adis16505-1",
@@ -997,7 +1222,9 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
/* pulse sync not supported */
.num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1,
.flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
- .adis_data = ADIS16475_DATA(16505, &adis1650x_timeouts),
+ .adis_data = ADIS16475_DATA(16505, &adis1650x_timeouts,
+ ADIS16475_BURST32_MAX_DATA_NO_TS32,
+ ADIS16475_BURST_MAX_SPEED, false),
},
[ADIS16505_2] = {
.name = "adis16505-2",
@@ -1016,7 +1243,9 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
/* pulse sync not supported */
.num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1,
.flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
- .adis_data = ADIS16475_DATA(16505, &adis1650x_timeouts),
+ .adis_data = ADIS16475_DATA(16505, &adis1650x_timeouts,
+ ADIS16475_BURST32_MAX_DATA_NO_TS32,
+ ADIS16475_BURST_MAX_SPEED, false),
},
[ADIS16505_3] = {
.name = "adis16505-3",
@@ -1035,7 +1264,9 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
/* pulse sync not supported */
.num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1,
.flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
- .adis_data = ADIS16475_DATA(16505, &adis1650x_timeouts),
+ .adis_data = ADIS16475_DATA(16505, &adis1650x_timeouts,
+ ADIS16475_BURST32_MAX_DATA_NO_TS32,
+ ADIS16475_BURST_MAX_SPEED, false),
},
[ADIS16507_1] = {
.name = "adis16507-1",
@@ -1054,7 +1285,9 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
/* pulse sync not supported */
.num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1,
.flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
- .adis_data = ADIS16475_DATA(16507, &adis1650x_timeouts),
+ .adis_data = ADIS16475_DATA(16507, &adis1650x_timeouts,
+ ADIS16475_BURST32_MAX_DATA_NO_TS32,
+ ADIS16475_BURST_MAX_SPEED, false),
},
[ADIS16507_2] = {
.name = "adis16507-2",
@@ -1073,7 +1306,9 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
/* pulse sync not supported */
.num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1,
.flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
- .adis_data = ADIS16475_DATA(16507, &adis1650x_timeouts),
+ .adis_data = ADIS16475_DATA(16507, &adis1650x_timeouts,
+ ADIS16475_BURST32_MAX_DATA_NO_TS32,
+ ADIS16475_BURST_MAX_SPEED, false),
},
[ADIS16507_3] = {
.name = "adis16507-3",
@@ -1092,7 +1327,147 @@ static const struct adis16475_chip_info adis16475_chip_info[] = {
/* pulse sync not supported */
.num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1,
.flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA,
- .adis_data = ADIS16475_DATA(16507, &adis1650x_timeouts),
+ .adis_data = ADIS16475_DATA(16507, &adis1650x_timeouts,
+ ADIS16475_BURST32_MAX_DATA_NO_TS32,
+ ADIS16475_BURST_MAX_SPEED, false),
+ },
+ [ADIS16575_2] = {
+ .name = "adis16575-2",
+ .num_channels = ARRAY_SIZE(adis16575_channels),
+ .channels = adis16575_channels,
+ .gyro_max_val = 1,
+ .gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16),
+ .accel_max_val = 8,
+ .accel_max_scale = IIO_M_S_2_TO_G(32000 << 16),
+ .temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(450),
+ .deltvel_max_val = 100,
+ .int_clk = 4000,
+ .max_dec = 3999,
+ .sync = adis16575_sync_mode,
+ .num_sync = ARRAY_SIZE(adis16575_sync_mode),
+ .flags = ADIS16475_HAS_BURST32 |
+ ADIS16475_HAS_BURST_DELTA_DATA |
+ ADIS16475_NEEDS_BURST_REQUEST |
+ ADIS16475_HAS_TIMESTAMP32,
+ .adis_data = ADIS16475_DATA(16575, &adis16475_timeouts,
+ ADIS16575_BURST32_DATA_TS32,
+ ADIS16575_BURST_MAX_SPEED, true),
+ },
+ [ADIS16575_3] = {
+ .name = "adis16575-3",
+ .num_channels = ARRAY_SIZE(adis16575_channels),
+ .channels = adis16575_channels,
+ .gyro_max_val = 1,
+ .gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
+ .accel_max_val = 8,
+ .accel_max_scale = IIO_M_S_2_TO_G(32000 << 16),
+ .temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(2000),
+ .deltvel_max_val = 100,
+ .int_clk = 4000,
+ .max_dec = 3999,
+ .sync = adis16575_sync_mode,
+ .num_sync = ARRAY_SIZE(adis16575_sync_mode),
+ .flags = ADIS16475_HAS_BURST32 |
+ ADIS16475_HAS_BURST_DELTA_DATA |
+ ADIS16475_NEEDS_BURST_REQUEST |
+ ADIS16475_HAS_TIMESTAMP32,
+ .adis_data = ADIS16475_DATA(16575, &adis16475_timeouts,
+ ADIS16575_BURST32_DATA_TS32,
+ ADIS16575_BURST_MAX_SPEED, true),
+ },
+ [ADIS16576_2] = {
+ .name = "adis16576-2",
+ .num_channels = ARRAY_SIZE(adis16575_channels),
+ .channels = adis16575_channels,
+ .gyro_max_val = 1,
+ .gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16),
+ .accel_max_val = 40,
+ .accel_max_scale = IIO_M_S_2_TO_G(32000 << 16),
+ .temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(450),
+ .deltvel_max_val = 125,
+ .int_clk = 4000,
+ .max_dec = 3999,
+ .sync = adis16575_sync_mode,
+ .num_sync = ARRAY_SIZE(adis16575_sync_mode),
+ .flags = ADIS16475_HAS_BURST32 |
+ ADIS16475_HAS_BURST_DELTA_DATA |
+ ADIS16475_NEEDS_BURST_REQUEST |
+ ADIS16475_HAS_TIMESTAMP32,
+ .adis_data = ADIS16475_DATA(16576, &adis16475_timeouts,
+ ADIS16575_BURST32_DATA_TS32,
+ ADIS16575_BURST_MAX_SPEED, true),
+ },
+ [ADIS16576_3] = {
+ .name = "adis16576-3",
+ .num_channels = ARRAY_SIZE(adis16575_channels),
+ .channels = adis16575_channels,
+ .gyro_max_val = 1,
+ .gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
+ .accel_max_val = 40,
+ .accel_max_scale = IIO_M_S_2_TO_G(32000 << 16),
+ .temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(2000),
+ .deltvel_max_val = 125,
+ .int_clk = 4000,
+ .max_dec = 3999,
+ .sync = adis16575_sync_mode,
+ .num_sync = ARRAY_SIZE(adis16575_sync_mode),
+ .flags = ADIS16475_HAS_BURST32 |
+ ADIS16475_HAS_BURST_DELTA_DATA |
+ ADIS16475_NEEDS_BURST_REQUEST |
+ ADIS16475_HAS_TIMESTAMP32,
+ .adis_data = ADIS16475_DATA(16576, &adis16475_timeouts,
+ ADIS16575_BURST32_DATA_TS32,
+ ADIS16575_BURST_MAX_SPEED, true),
+ },
+ [ADIS16577_2] = {
+ .name = "adis16577-2",
+ .num_channels = ARRAY_SIZE(adis16575_channels),
+ .channels = adis16575_channels,
+ .gyro_max_val = 1,
+ .gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16),
+ .accel_max_val = 40,
+ .accel_max_scale = IIO_M_S_2_TO_G(32000 << 16),
+ .temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(450),
+ .deltvel_max_val = 400,
+ .int_clk = 4000,
+ .max_dec = 3999,
+ .sync = adis16575_sync_mode,
+ .num_sync = ARRAY_SIZE(adis16575_sync_mode),
+ .flags = ADIS16475_HAS_BURST32 |
+ ADIS16475_HAS_BURST_DELTA_DATA |
+ ADIS16475_NEEDS_BURST_REQUEST |
+ ADIS16475_HAS_TIMESTAMP32,
+ .adis_data = ADIS16475_DATA(16577, &adis16475_timeouts,
+ ADIS16575_BURST32_DATA_TS32,
+ ADIS16575_BURST_MAX_SPEED, true),
+ },
+ [ADIS16577_3] = {
+ .name = "adis16577-3",
+ .num_channels = ARRAY_SIZE(adis16575_channels),
+ .channels = adis16575_channels,
+ .gyro_max_val = 1,
+ .gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16),
+ .accel_max_val = 40,
+ .accel_max_scale = IIO_M_S_2_TO_G(32000 << 16),
+ .temp_scale = 100,
+ .deltang_max_val = IIO_DEGREE_TO_RAD(2000),
+ .deltvel_max_val = 400,
+ .int_clk = 4000,
+ .max_dec = 3999,
+ .sync = adis16575_sync_mode,
+ .num_sync = ARRAY_SIZE(adis16575_sync_mode),
+ .flags = ADIS16475_HAS_BURST32 |
+ ADIS16475_HAS_BURST_DELTA_DATA |
+ ADIS16475_NEEDS_BURST_REQUEST |
+ ADIS16475_HAS_TIMESTAMP32,
+ .adis_data = ADIS16475_DATA(16577, &adis16475_timeouts,
+ ADIS16575_BURST32_DATA_TS32,
+ ADIS16575_BURST_MAX_SPEED, true),
},
};
@@ -1128,15 +1503,20 @@ static const struct iio_info adis16475_info = {
.debugfs_reg_access = adis_debugfs_reg_access,
};
+static const struct iio_info adis16575_info = {
+ .read_raw = &adis16475_read_raw,
+ .write_raw = &adis16475_write_raw,
+ .update_scan_mode = adis16475_update_scan_mode,
+ .debugfs_reg_access = adis_debugfs_reg_access,
+ .hwfifo_set_watermark = adis16475_set_watermark,
+};
+
static bool adis16475_validate_crc(const u8 *buffer, u16 crc,
- const bool burst32)
+ u16 burst_size, u16 start_idx)
{
int i;
- /* extra 6 elements for low gyro and accel */
- const u16 sz = burst32 ? ADIS16475_BURST32_MAX_DATA :
- ADIS16475_BURST_MAX_DATA;
- for (i = 0; i < sz - 2; i++)
+ for (i = start_idx; i < burst_size - 2; i++)
crc -= buffer[i];
return crc == 0;
@@ -1146,10 +1526,14 @@ static void adis16475_burst32_check(struct adis16475 *st)
{
int ret;
struct adis *adis = &st->adis;
+ u8 timestamp32 = 0;
if (!(st->info->flags & ADIS16475_HAS_BURST32))
return;
+ if (st->info->flags & ADIS16475_HAS_TIMESTAMP32)
+ timestamp32 = 1;
+
if (st->lsb_flag && !st->burst32) {
const u16 en = ADIS16500_BURST32(1);
@@ -1163,9 +1547,12 @@ static void adis16475_burst32_check(struct adis16475 *st)
/*
* In 32-bit mode we need extra 2 bytes for all gyro
* and accel channels.
+ * If the device has 32-bit timestamp value we need 2 extra
+ * bytes for it.
*/
- adis->burst_extra_len = 6 * sizeof(u16);
- adis->xfer[1].len += 6 * sizeof(u16);
+ adis->burst_extra_len = (6 + timestamp32) * sizeof(u16);
+ adis->xfer[1].len += (6 + timestamp32) * sizeof(u16);
+
dev_dbg(&adis->spi->dev, "Enable burst32 mode, xfer:%d",
adis->xfer[1].len);
@@ -1181,15 +1568,14 @@ static void adis16475_burst32_check(struct adis16475 *st)
/* Remove the extra bits */
adis->burst_extra_len = 0;
- adis->xfer[1].len -= 6 * sizeof(u16);
+ adis->xfer[1].len -= (6 + timestamp32) * sizeof(u16);
dev_dbg(&adis->spi->dev, "Disable burst32 mode, xfer:%d\n",
adis->xfer[1].len);
}
}
-static irqreturn_t adis16475_trigger_handler(int irq, void *p)
+static int adis16475_push_single_sample(struct iio_poll_func *pf)
{
- struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct adis16475 *st = iio_priv(indio_dev);
struct adis *adis = &st->adis;
@@ -1197,20 +1583,29 @@ static irqreturn_t adis16475_trigger_handler(int irq, void *p)
__be16 *buffer;
u16 crc;
bool valid;
+ u8 crc_offset = 9;
+ u16 burst_size = ADIS16475_BURST_MAX_DATA;
+ u16 start_idx = (st->info->flags & ADIS16475_HAS_TIMESTAMP32) ? 2 : 0;
+
/* offset until the first element after gyro and accel */
const u8 offset = st->burst32 ? 13 : 7;
+ if (st->burst32) {
+ crc_offset = (st->info->flags & ADIS16475_HAS_TIMESTAMP32) ? 16 : 15;
+ burst_size = adis->data->burst_max_len;
+ }
+
ret = spi_sync(adis->spi, &adis->msg);
if (ret)
- goto check_burst32;
+ return ret;
buffer = adis->buffer;
- crc = be16_to_cpu(buffer[offset + 2]);
- valid = adis16475_validate_crc(adis->buffer, crc, st->burst32);
+ crc = be16_to_cpu(buffer[crc_offset]);
+ valid = adis16475_validate_crc(adis->buffer, crc, burst_size, start_idx);
if (!valid) {
dev_err(&adis->spi->dev, "Invalid crc\n");
- goto check_burst32;
+ return -EINVAL;
}
for_each_set_bit(bit, indio_dev->active_scan_mask,
@@ -1270,14 +1665,123 @@ static irqreturn_t adis16475_trigger_handler(int irq, void *p)
}
}
+ /* There might not be a timestamp option for some devices. */
iio_push_to_buffers_with_timestamp(indio_dev, st->data, pf->timestamp);
-check_burst32:
+
+ return 0;
+}
+
+static irqreturn_t adis16475_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct adis16475 *st = iio_priv(indio_dev);
+
+ adis16475_push_single_sample(pf);
/*
* We only check the burst mode at the end of the current capture since
* it takes a full data ready cycle for the device to update the burst
* array.
*/
adis16475_burst32_check(st);
+
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * This function updates the first tx byte from the adis message based on the
+ * given burst request.
+ */
+static void adis16575_update_msg_for_burst(struct adis *adis, u8 burst_req)
+{
+ unsigned int burst_max_length;
+ u8 *tx;
+
+ if (adis->data->burst_max_len)
+ burst_max_length = adis->data->burst_max_len;
+ else
+ burst_max_length = adis->data->burst_len + adis->burst_extra_len;
+
+ tx = adis->buffer + burst_max_length;
+ tx[0] = ADIS_READ_REG(burst_req);
+}
+
+static int adis16575_custom_burst_read(struct iio_poll_func *pf, u8 burst_req)
+{
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct adis16475 *st = iio_priv(indio_dev);
+ struct adis *adis = &st->adis;
+
+ adis16575_update_msg_for_burst(adis, burst_req);
+
+ if (burst_req)
+ return spi_sync(adis->spi, &adis->msg);
+
+ return adis16475_push_single_sample(pf);
+}
+
+/*
+ * This handler is meant to be used for devices which support burst readings
+ * from FIFO (namely devices from adis1657x family).
+ * In order to pop the FIFO the 0x68 0x00 FIFO pop burst request has to be sent.
+ * If the previous device command was not a FIFO pop burst request, the FIFO pop
+ * burst request will simply pop the FIFO without returning valid data.
+ * For the nth consecutive burst request, thedevice will send the data popped
+ * with the (n-1)th consecutive burst request.
+ * In order to read the data which was popped previously, without popping the
+ * FIFO, the 0x00 0x00 burst request has to be sent.
+ * If after a 0x68 0x00 FIFO pop burst request, there is any other device access
+ * different from a 0x68 0x00 or a 0x00 0x00 burst request, the FIFO data popped
+ * previously will be lost.
+ */
+static irqreturn_t adis16475_trigger_handler_with_fifo(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct adis16475 *st = iio_priv(indio_dev);
+ struct adis *adis = &st->adis;
+ int ret;
+ u16 fifo_cnt, i;
+
+ adis_dev_lock(&st->adis);
+
+ ret = __adis_read_reg_16(adis, ADIS16575_REG_FIFO_CNT, &fifo_cnt);
+ if (ret)
+ goto unlock;
+
+ /*
+ * If no sample is available, nothing can be read. This can happen if
+ * a the used trigger has a higher frequency than the selected sample rate.
+ */
+ if (!fifo_cnt)
+ goto unlock;
+
+ /*
+ * First burst request - FIFO pop: popped data will be returned in the
+ * next burst request.
+ */
+ ret = adis16575_custom_burst_read(pf, adis->data->burst_reg_cmd);
+ if (ret)
+ goto unlock;
+
+ for (i = 0; i < fifo_cnt - 1; i++) {
+ ret = adis16475_push_single_sample(pf);
+ if (ret)
+ goto unlock;
+ }
+
+ /* FIFO read without popping */
+ ret = adis16575_custom_burst_read(pf, 0);
+
+unlock:
+ /*
+ * We only check the burst mode at the end of the current capture since
+ * reading data from registers will impact the FIFO reading.
+ */
+ adis16475_burst32_check(st);
+ adis_dev_unlock(&st->adis);
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
@@ -1289,8 +1793,18 @@ static int adis16475_config_sync_mode(struct adis16475 *st)
struct device *dev = &st->adis.spi->dev;
const struct adis16475_sync *sync;
u32 sync_mode;
+ u16 max_sample_rate = st->info->int_clk + 100;
u16 val;
+ /* if available, enable 4khz internal clock */
+ if (st->info->int_clk == 4000) {
+ ret = __adis_update_bits(&st->adis, ADIS16475_REG_MSG_CTRL,
+ ADIS16575_SYNC_4KHZ_MASK,
+ (u16)ADIS16575_SYNC_4KHZ(1));
+ if (ret)
+ return ret;
+ }
+
/* default to internal clk */
st->clk_freq = st->info->int_clk * 1000;
@@ -1329,10 +1843,9 @@ static int adis16475_config_sync_mode(struct adis16475 *st)
/*
* In sync scaled mode, the IMU sample rate is the clk_freq * sync_scale.
* Hence, default the IMU sample rate to the highest multiple of the input
- * clock lower than the IMU max sample rate. The optimal range is
- * 1900-2100 sps...
+ * clock lower than the IMU max sample rate.
*/
- up_scale = 2100 / st->clk_freq;
+ up_scale = max_sample_rate / st->clk_freq;
ret = __adis_write_reg_16(&st->adis,
ADIS16475_REG_UP_SCALE,
@@ -1370,34 +1883,69 @@ static int adis16475_config_irq_pin(struct adis16475 *st)
u8 polarity;
struct spi_device *spi = st->adis.spi;
- /*
- * It is possible to configure the data ready polarity. Furthermore, we
- * need to update the adis struct if we want data ready as active low.
- */
irq_type = irq_get_trigger_type(spi->irq);
- if (irq_type == IRQ_TYPE_EDGE_RISING) {
- polarity = 1;
- st->adis.irq_flag = IRQF_TRIGGER_RISING;
- } else if (irq_type == IRQ_TYPE_EDGE_FALLING) {
- polarity = 0;
- st->adis.irq_flag = IRQF_TRIGGER_FALLING;
+
+ if (st->adis.data->has_fifo) {
+ /*
+ * It is possible to configure the fifo watermark pin polarity.
+ * Furthermore, we need to update the adis struct if we want the
+ * watermark pin active low.
+ */
+ if (irq_type == IRQ_TYPE_LEVEL_HIGH) {
+ polarity = 1;
+ st->adis.irq_flag = IRQF_TRIGGER_HIGH;
+ } else if (irq_type == IRQ_TYPE_LEVEL_LOW) {
+ polarity = 0;
+ st->adis.irq_flag = IRQF_TRIGGER_LOW;
+ } else {
+ dev_err(&spi->dev, "Invalid interrupt type 0x%x specified\n",
+ irq_type);
+ return -EINVAL;
+ }
+
+ /* Configure the watermark pin polarity. */
+ val = ADIS16575_WM_POL(polarity);
+ ret = adis_update_bits(&st->adis, ADIS16475_REG_FIFO_CTRL,
+ ADIS16575_WM_POL_MASK, val);
+ if (ret)
+ return ret;
+
+ /* Enable watermark interrupt pin. */
+ ret = adis_update_bits(&st->adis, ADIS16475_REG_FIFO_CTRL,
+ ADIS16575_WM_EN_MASK,
+ (u16)ADIS16575_WM_EN(1));
+ if (ret)
+ return ret;
+
} else {
- dev_err(&spi->dev, "Invalid interrupt type 0x%x specified\n",
- irq_type);
- return -EINVAL;
- }
+ /*
+ * It is possible to configure the data ready polarity. Furthermore, we
+ * need to update the adis struct if we want data ready as active low.
+ */
+ if (irq_type == IRQ_TYPE_EDGE_RISING) {
+ polarity = 1;
+ st->adis.irq_flag = IRQF_TRIGGER_RISING;
+ } else if (irq_type == IRQ_TYPE_EDGE_FALLING) {
+ polarity = 0;
+ st->adis.irq_flag = IRQF_TRIGGER_FALLING;
+ } else {
+ dev_err(&spi->dev, "Invalid interrupt type 0x%x specified\n",
+ irq_type);
+ return -EINVAL;
+ }
- val = ADIS16475_MSG_CTRL_DR_POL(polarity);
- ret = __adis_update_bits(&st->adis, ADIS16475_REG_MSG_CTRL,
- ADIS16475_MSG_CTRL_DR_POL_MASK, val);
- if (ret)
- return ret;
- /*
- * There is a delay writing to any bits written to the MSC_CTRL
- * register. It should not be bigger than 200us, so 250 should be more
- * than enough!
- */
- usleep_range(250, 260);
+ val = ADIS16475_MSG_CTRL_DR_POL(polarity);
+ ret = __adis_update_bits(&st->adis, ADIS16475_REG_MSG_CTRL,
+ ADIS16475_MSG_CTRL_DR_POL_MASK, val);
+ if (ret)
+ return ret;
+ /*
+ * There is a delay writing to any bits written to the MSC_CTRL
+ * register. It should not be bigger than 200us, so 250 should be more
+ * than enough!
+ */
+ usleep_range(250, 260);
+ }
return 0;
}
@@ -1408,6 +1956,7 @@ static int adis16475_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
struct adis16475 *st;
int ret;
+ u16 val;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
@@ -1426,7 +1975,10 @@ static int adis16475_probe(struct spi_device *spi)
indio_dev->name = st->info->name;
indio_dev->channels = st->info->channels;
indio_dev->num_channels = st->info->num_channels;
- indio_dev->info = &adis16475_info;
+ if (st->adis.data->has_fifo)
+ indio_dev->info = &adis16575_info;
+ else
+ indio_dev->info = &adis16475_info;
indio_dev->modes = INDIO_DIRECT_MODE;
ret = __adis_initial_startup(&st->adis);
@@ -1441,10 +1993,26 @@ static int adis16475_probe(struct spi_device *spi)
if (ret)
return ret;
- ret = devm_adis_setup_buffer_and_trigger(&st->adis, indio_dev,
- adis16475_trigger_handler);
- if (ret)
- return ret;
+ if (st->adis.data->has_fifo) {
+ ret = devm_adis_setup_buffer_and_trigger_with_attrs(&st->adis, indio_dev,
+ adis16475_trigger_handler_with_fifo,
+ &adis16475_buffer_ops,
+ adis16475_fifo_attributes);
+ if (ret)
+ return ret;
+
+ /* Update overflow behavior to always overwrite the oldest sample. */
+ val = ADIS16575_OVERWRITE_OLDEST;
+ ret = adis_update_bits(&st->adis, ADIS16475_REG_FIFO_CTRL,
+ ADIS16575_OVERFLOW_MASK, val);
+ if (ret)
+ return ret;
+ } else {
+ ret = devm_adis_setup_buffer_and_trigger(&st->adis, indio_dev,
+ adis16475_trigger_handler);
+ if (ret)
+ return ret;
+ }
ret = devm_iio_device_register(&spi->dev, indio_dev);
if (ret)
@@ -1484,6 +2052,8 @@ static const struct of_device_id adis16475_of_match[] = {
.data = &adis16475_chip_info[ADIS16467_3] },
{ .compatible = "adi,adis16500",
.data = &adis16475_chip_info[ADIS16500] },
+ { .compatible = "adi,adis16501",
+ .data = &adis16475_chip_info[ADIS16501] },
{ .compatible = "adi,adis16505-1",
.data = &adis16475_chip_info[ADIS16505_1] },
{ .compatible = "adi,adis16505-2",
@@ -1496,6 +2066,18 @@ static const struct of_device_id adis16475_of_match[] = {
.data = &adis16475_chip_info[ADIS16507_2] },
{ .compatible = "adi,adis16507-3",
.data = &adis16475_chip_info[ADIS16507_3] },
+ { .compatible = "adi,adis16575-2",
+ .data = &adis16475_chip_info[ADIS16575_2] },
+ { .compatible = "adi,adis16575-3",
+ .data = &adis16475_chip_info[ADIS16575_3] },
+ { .compatible = "adi,adis16576-2",
+ .data = &adis16475_chip_info[ADIS16576_2] },
+ { .compatible = "adi,adis16576-3",
+ .data = &adis16475_chip_info[ADIS16576_3] },
+ { .compatible = "adi,adis16577-2",
+ .data = &adis16475_chip_info[ADIS16577_2] },
+ { .compatible = "adi,adis16577-3",
+ .data = &adis16475_chip_info[ADIS16577_3] },
{ },
};
MODULE_DEVICE_TABLE(of, adis16475_of_match);
@@ -1515,12 +2097,19 @@ static const struct spi_device_id adis16475_ids[] = {
{ "adis16467-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16467_2] },
{ "adis16467-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16467_3] },
{ "adis16500", (kernel_ulong_t)&adis16475_chip_info[ADIS16500] },
+ { "adis16501", (kernel_ulong_t)&adis16475_chip_info[ADIS16501] },
{ "adis16505-1", (kernel_ulong_t)&adis16475_chip_info[ADIS16505_1] },
{ "adis16505-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16505_2] },
{ "adis16505-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16505_3] },
{ "adis16507-1", (kernel_ulong_t)&adis16475_chip_info[ADIS16507_1] },
{ "adis16507-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16507_2] },
{ "adis16507-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16507_3] },
+ { "adis16575-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16575_2] },
+ { "adis16575-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16575_3] },
+ { "adis16576-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16576_2] },
+ { "adis16576-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16576_3] },
+ { "adis16577-2", (kernel_ulong_t)&adis16475_chip_info[ADIS16577_2] },
+ { "adis16577-3", (kernel_ulong_t)&adis16475_chip_info[ADIS16577_3] },
{ }
};
MODULE_DEVICE_TABLE(spi, adis16475_ids);
diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c
index b40a55bba30c..56ca5a09fbbf 100644
--- a/drivers/iio/imu/adis16480.c
+++ b/drivers/iio/imu/adis16480.c
@@ -104,11 +104,10 @@
*/
#define ADIS16495_REG_SYNC_SCALE ADIS16480_REG(0x03, 0x10)
#define ADIS16495_REG_BURST_CMD ADIS16480_REG(0x00, 0x7C)
-#define ADIS16495_BURST_ID 0xA5A5
+#define ADIS16495_GYRO_ACCEL_BURST_ID 0xA5A5
+#define ADIS16545_DELTA_ANG_VEL_BURST_ID 0xC3C3
/* total number of segments in burst */
#define ADIS16495_BURST_MAX_DATA 20
-/* spi max speed in burst mode */
-#define ADIS16495_BURST_MAX_SPEED 6000000
#define ADIS16480_REG_SERIAL_NUM ADIS16480_REG(0x04, 0x20)
@@ -134,6 +133,10 @@
#define ADIS16480_SYNC_MODE_MSK BIT(8)
#define ADIS16480_SYNC_MODE(x) FIELD_PREP(ADIS16480_SYNC_MODE_MSK, x)
+#define ADIS16545_BURST_DATA_SEL_0_CHN_MASK GENMASK(5, 0)
+#define ADIS16545_BURST_DATA_SEL_1_CHN_MASK GENMASK(16, 11)
+#define ADIS16545_BURST_DATA_SEL_MASK BIT(8)
+
struct adis16480_chip_info {
unsigned int num_channels;
const struct iio_chan_spec *channels;
@@ -142,11 +145,14 @@ struct adis16480_chip_info {
unsigned int accel_max_val;
unsigned int accel_max_scale;
unsigned int temp_scale;
+ unsigned int deltang_max_val;
+ unsigned int deltvel_max_val;
unsigned int int_clk;
unsigned int max_dec_rate;
const unsigned int *filter_freqs;
bool has_pps_clk_mode;
bool has_sleep_cnt;
+ bool has_burst_delta_data;
const struct adis_data adis_data;
};
@@ -170,6 +176,7 @@ struct adis16480 {
struct clk *ext_clk;
enum adis16480_clock_mode clk_mode;
unsigned int clk_freq;
+ u16 burst_id;
/* Alignment needed for the timestamp */
__be16 data[ADIS16495_BURST_MAX_DATA] __aligned(8);
};
@@ -447,6 +454,12 @@ enum {
ADIS16480_SCAN_MAGN_Z,
ADIS16480_SCAN_BARO,
ADIS16480_SCAN_TEMP,
+ ADIS16480_SCAN_DELTANG_X,
+ ADIS16480_SCAN_DELTANG_Y,
+ ADIS16480_SCAN_DELTANG_Z,
+ ADIS16480_SCAN_DELTVEL_X,
+ ADIS16480_SCAN_DELTVEL_Y,
+ ADIS16480_SCAN_DELTVEL_Z,
};
static const unsigned int adis16480_calibbias_regs[] = {
@@ -690,6 +703,14 @@ static int adis16480_read_raw(struct iio_dev *indio_dev,
*val = 131; /* 1310mbar = 131 kPa */
*val2 = 32767 << 16;
return IIO_VAL_FRACTIONAL;
+ case IIO_DELTA_ANGL:
+ *val = st->chip_info->deltang_max_val;
+ *val2 = 31;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ case IIO_DELTA_VELOCITY:
+ *val = st->chip_info->deltvel_max_val;
+ *val2 = 31;
+ return IIO_VAL_FRACTIONAL_LOG2;
default:
return -EINVAL;
}
@@ -763,6 +784,24 @@ static int adis16480_write_raw(struct iio_dev *indio_dev,
BIT(IIO_CHAN_INFO_CALIBSCALE), \
32)
+#define ADIS16480_DELTANG_CHANNEL(_mod) \
+ ADIS16480_MOD_CHANNEL(IIO_DELTA_ANGL, IIO_MOD_ ## _mod, \
+ ADIS16480_REG_ ## _mod ## _DELTAANG_OUT, ADIS16480_SCAN_DELTANG_ ## _mod, \
+ 0, 32)
+
+#define ADIS16480_DELTANG_CHANNEL_NO_SCAN(_mod) \
+ ADIS16480_MOD_CHANNEL(IIO_DELTA_ANGL, IIO_MOD_ ## _mod, \
+ ADIS16480_REG_ ## _mod ## _DELTAANG_OUT, -1, 0, 32)
+
+#define ADIS16480_DELTVEL_CHANNEL(_mod) \
+ ADIS16480_MOD_CHANNEL(IIO_DELTA_VELOCITY, IIO_MOD_ ## _mod, \
+ ADIS16480_REG_ ## _mod ## _DELTAVEL_OUT, ADIS16480_SCAN_DELTVEL_ ## _mod, \
+ 0, 32)
+
+#define ADIS16480_DELTVEL_CHANNEL_NO_SCAN(_mod) \
+ ADIS16480_MOD_CHANNEL(IIO_DELTA_VELOCITY, IIO_MOD_ ## _mod, \
+ ADIS16480_REG_ ## _mod ## _DELTAVEL_OUT, -1, 0, 32)
+
#define ADIS16480_MAGN_CHANNEL(_mod) \
ADIS16480_MOD_CHANNEL(IIO_MAGN, IIO_MOD_ ## _mod, \
ADIS16480_REG_ ## _mod ## _MAGN_OUT, ADIS16480_SCAN_MAGN_ ## _mod, \
@@ -818,7 +857,13 @@ static const struct iio_chan_spec adis16480_channels[] = {
ADIS16480_MAGN_CHANNEL(Z),
ADIS16480_PRESSURE_CHANNEL(),
ADIS16480_TEMP_CHANNEL(),
- IIO_CHAN_SOFT_TIMESTAMP(11)
+ IIO_CHAN_SOFT_TIMESTAMP(11),
+ ADIS16480_DELTANG_CHANNEL_NO_SCAN(X),
+ ADIS16480_DELTANG_CHANNEL_NO_SCAN(Y),
+ ADIS16480_DELTANG_CHANNEL_NO_SCAN(Z),
+ ADIS16480_DELTVEL_CHANNEL_NO_SCAN(X),
+ ADIS16480_DELTVEL_CHANNEL_NO_SCAN(Y),
+ ADIS16480_DELTVEL_CHANNEL_NO_SCAN(Z),
};
static const struct iio_chan_spec adis16485_channels[] = {
@@ -829,7 +874,30 @@ static const struct iio_chan_spec adis16485_channels[] = {
ADIS16480_ACCEL_CHANNEL(Y),
ADIS16480_ACCEL_CHANNEL(Z),
ADIS16480_TEMP_CHANNEL(),
- IIO_CHAN_SOFT_TIMESTAMP(7)
+ IIO_CHAN_SOFT_TIMESTAMP(7),
+ ADIS16480_DELTANG_CHANNEL_NO_SCAN(X),
+ ADIS16480_DELTANG_CHANNEL_NO_SCAN(Y),
+ ADIS16480_DELTANG_CHANNEL_NO_SCAN(Z),
+ ADIS16480_DELTVEL_CHANNEL_NO_SCAN(X),
+ ADIS16480_DELTVEL_CHANNEL_NO_SCAN(Y),
+ ADIS16480_DELTVEL_CHANNEL_NO_SCAN(Z),
+};
+
+static const struct iio_chan_spec adis16545_channels[] = {
+ ADIS16480_GYRO_CHANNEL(X),
+ ADIS16480_GYRO_CHANNEL(Y),
+ ADIS16480_GYRO_CHANNEL(Z),
+ ADIS16480_ACCEL_CHANNEL(X),
+ ADIS16480_ACCEL_CHANNEL(Y),
+ ADIS16480_ACCEL_CHANNEL(Z),
+ ADIS16480_TEMP_CHANNEL(),
+ ADIS16480_DELTANG_CHANNEL(X),
+ ADIS16480_DELTANG_CHANNEL(Y),
+ ADIS16480_DELTANG_CHANNEL(Z),
+ ADIS16480_DELTVEL_CHANNEL(X),
+ ADIS16480_DELTVEL_CHANNEL(Y),
+ ADIS16480_DELTVEL_CHANNEL(Z),
+ IIO_CHAN_SOFT_TIMESTAMP(17),
};
enum adis16480_variant {
@@ -844,6 +912,12 @@ enum adis16480_variant {
ADIS16497_1,
ADIS16497_2,
ADIS16497_3,
+ ADIS16545_1,
+ ADIS16545_2,
+ ADIS16545_3,
+ ADIS16547_1,
+ ADIS16547_2,
+ ADIS16547_3
};
#define ADIS16480_DIAG_STAT_XGYRO_FAIL 0
@@ -872,33 +946,33 @@ static const char * const adis16480_status_error_msgs[] = {
static int adis16480_enable_irq(struct adis *adis, bool enable);
-#define ADIS16480_DATA(_prod_id, _timeouts, _burst_len) \
-{ \
- .diag_stat_reg = ADIS16480_REG_DIAG_STS, \
- .glob_cmd_reg = ADIS16480_REG_GLOB_CMD, \
- .prod_id_reg = ADIS16480_REG_PROD_ID, \
- .prod_id = (_prod_id), \
- .has_paging = true, \
- .read_delay = 5, \
- .write_delay = 5, \
- .self_test_mask = BIT(1), \
- .self_test_reg = ADIS16480_REG_GLOB_CMD, \
- .status_error_msgs = adis16480_status_error_msgs, \
- .status_error_mask = BIT(ADIS16480_DIAG_STAT_XGYRO_FAIL) | \
- BIT(ADIS16480_DIAG_STAT_YGYRO_FAIL) | \
- BIT(ADIS16480_DIAG_STAT_ZGYRO_FAIL) | \
- BIT(ADIS16480_DIAG_STAT_XACCL_FAIL) | \
- BIT(ADIS16480_DIAG_STAT_YACCL_FAIL) | \
- BIT(ADIS16480_DIAG_STAT_ZACCL_FAIL) | \
- BIT(ADIS16480_DIAG_STAT_XMAGN_FAIL) | \
- BIT(ADIS16480_DIAG_STAT_YMAGN_FAIL) | \
- BIT(ADIS16480_DIAG_STAT_ZMAGN_FAIL) | \
- BIT(ADIS16480_DIAG_STAT_BARO_FAIL), \
- .enable_irq = adis16480_enable_irq, \
- .timeouts = (_timeouts), \
- .burst_reg_cmd = ADIS16495_REG_BURST_CMD, \
- .burst_len = (_burst_len), \
- .burst_max_speed_hz = ADIS16495_BURST_MAX_SPEED \
+#define ADIS16480_DATA(_prod_id, _timeouts, _burst_len, _burst_max_speed) \
+{ \
+ .diag_stat_reg = ADIS16480_REG_DIAG_STS, \
+ .glob_cmd_reg = ADIS16480_REG_GLOB_CMD, \
+ .prod_id_reg = ADIS16480_REG_PROD_ID, \
+ .prod_id = (_prod_id), \
+ .has_paging = true, \
+ .read_delay = 5, \
+ .write_delay = 5, \
+ .self_test_mask = BIT(1), \
+ .self_test_reg = ADIS16480_REG_GLOB_CMD, \
+ .status_error_msgs = adis16480_status_error_msgs, \
+ .status_error_mask = BIT(ADIS16480_DIAG_STAT_XGYRO_FAIL) | \
+ BIT(ADIS16480_DIAG_STAT_YGYRO_FAIL) | \
+ BIT(ADIS16480_DIAG_STAT_ZGYRO_FAIL) | \
+ BIT(ADIS16480_DIAG_STAT_XACCL_FAIL) | \
+ BIT(ADIS16480_DIAG_STAT_YACCL_FAIL) | \
+ BIT(ADIS16480_DIAG_STAT_ZACCL_FAIL) | \
+ BIT(ADIS16480_DIAG_STAT_XMAGN_FAIL) | \
+ BIT(ADIS16480_DIAG_STAT_YMAGN_FAIL) | \
+ BIT(ADIS16480_DIAG_STAT_ZMAGN_FAIL) | \
+ BIT(ADIS16480_DIAG_STAT_BARO_FAIL), \
+ .enable_irq = adis16480_enable_irq, \
+ .timeouts = (_timeouts), \
+ .burst_reg_cmd = ADIS16495_REG_BURST_CMD, \
+ .burst_len = (_burst_len), \
+ .burst_max_speed_hz = _burst_max_speed \
}
static const struct adis_timeout adis16485_timeouts = {
@@ -925,6 +999,12 @@ static const struct adis_timeout adis16495_1_timeouts = {
.self_test_ms = 20,
};
+static const struct adis_timeout adis16545_timeouts = {
+ .reset_ms = 315,
+ .sw_reset_ms = 270,
+ .self_test_ms = 35,
+};
+
static const struct adis16480_chip_info adis16480_chip_info[] = {
[ADIS16375] = {
.channels = adis16485_channels,
@@ -940,11 +1020,13 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.accel_max_val = IIO_M_S_2_TO_G(21973 << 16),
.accel_max_scale = 18,
.temp_scale = 5650, /* 5.65 milli degree Celsius */
+ .deltang_max_val = IIO_DEGREE_TO_RAD(180),
+ .deltvel_max_val = 100,
.int_clk = 2460000,
.max_dec_rate = 2048,
.has_sleep_cnt = true,
.filter_freqs = adis16480_def_filter_freqs,
- .adis_data = ADIS16480_DATA(16375, &adis16485_timeouts, 0),
+ .adis_data = ADIS16480_DATA(16375, &adis16485_timeouts, 0, 0),
},
[ADIS16480] = {
.channels = adis16480_channels,
@@ -954,11 +1036,13 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.accel_max_val = IIO_M_S_2_TO_G(12500 << 16),
.accel_max_scale = 10,
.temp_scale = 5650, /* 5.65 milli degree Celsius */
+ .deltang_max_val = IIO_DEGREE_TO_RAD(720),
+ .deltvel_max_val = 200,
.int_clk = 2460000,
.max_dec_rate = 2048,
.has_sleep_cnt = true,
.filter_freqs = adis16480_def_filter_freqs,
- .adis_data = ADIS16480_DATA(16480, &adis16480_timeouts, 0),
+ .adis_data = ADIS16480_DATA(16480, &adis16480_timeouts, 0, 0),
},
[ADIS16485] = {
.channels = adis16485_channels,
@@ -968,11 +1052,13 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.accel_max_val = IIO_M_S_2_TO_G(20000 << 16),
.accel_max_scale = 5,
.temp_scale = 5650, /* 5.65 milli degree Celsius */
+ .deltang_max_val = IIO_DEGREE_TO_RAD(720),
+ .deltvel_max_val = 50,
.int_clk = 2460000,
.max_dec_rate = 2048,
.has_sleep_cnt = true,
.filter_freqs = adis16480_def_filter_freqs,
- .adis_data = ADIS16480_DATA(16485, &adis16485_timeouts, 0),
+ .adis_data = ADIS16480_DATA(16485, &adis16485_timeouts, 0, 0),
},
[ADIS16488] = {
.channels = adis16480_channels,
@@ -982,11 +1068,13 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.accel_max_val = IIO_M_S_2_TO_G(22500 << 16),
.accel_max_scale = 18,
.temp_scale = 5650, /* 5.65 milli degree Celsius */
+ .deltang_max_val = IIO_DEGREE_TO_RAD(720),
+ .deltvel_max_val = 200,
.int_clk = 2460000,
.max_dec_rate = 2048,
.has_sleep_cnt = true,
.filter_freqs = adis16480_def_filter_freqs,
- .adis_data = ADIS16480_DATA(16488, &adis16485_timeouts, 0),
+ .adis_data = ADIS16480_DATA(16488, &adis16485_timeouts, 0, 0),
},
[ADIS16490] = {
.channels = adis16485_channels,
@@ -996,11 +1084,13 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.accel_max_val = IIO_M_S_2_TO_G(16000 << 16),
.accel_max_scale = 8,
.temp_scale = 14285, /* 14.285 milli degree Celsius */
+ .deltang_max_val = IIO_DEGREE_TO_RAD(720),
+ .deltvel_max_val = 200,
.int_clk = 4250000,
.max_dec_rate = 4250,
.filter_freqs = adis16495_def_filter_freqs,
.has_pps_clk_mode = true,
- .adis_data = ADIS16480_DATA(16490, &adis16495_timeouts, 0),
+ .adis_data = ADIS16480_DATA(16490, &adis16495_timeouts, 0, 0),
},
[ADIS16495_1] = {
.channels = adis16485_channels,
@@ -1010,13 +1100,16 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
.accel_max_scale = 8,
.temp_scale = 12500, /* 12.5 milli degree Celsius */
+ .deltang_max_val = IIO_DEGREE_TO_RAD(360),
+ .deltvel_max_val = 100,
.int_clk = 4250000,
.max_dec_rate = 4250,
.filter_freqs = adis16495_def_filter_freqs,
.has_pps_clk_mode = true,
/* 20 elements of 16bits */
.adis_data = ADIS16480_DATA(16495, &adis16495_1_timeouts,
- ADIS16495_BURST_MAX_DATA * 2),
+ ADIS16495_BURST_MAX_DATA * 2,
+ 6000000),
},
[ADIS16495_2] = {
.channels = adis16485_channels,
@@ -1026,13 +1119,16 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
.accel_max_scale = 8,
.temp_scale = 12500, /* 12.5 milli degree Celsius */
+ .deltang_max_val = IIO_DEGREE_TO_RAD(720),
+ .deltvel_max_val = 100,
.int_clk = 4250000,
.max_dec_rate = 4250,
.filter_freqs = adis16495_def_filter_freqs,
.has_pps_clk_mode = true,
/* 20 elements of 16bits */
.adis_data = ADIS16480_DATA(16495, &adis16495_1_timeouts,
- ADIS16495_BURST_MAX_DATA * 2),
+ ADIS16495_BURST_MAX_DATA * 2,
+ 6000000),
},
[ADIS16495_3] = {
.channels = adis16485_channels,
@@ -1042,13 +1138,16 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
.accel_max_scale = 8,
.temp_scale = 12500, /* 12.5 milli degree Celsius */
+ .deltang_max_val = IIO_DEGREE_TO_RAD(2160),
+ .deltvel_max_val = 100,
.int_clk = 4250000,
.max_dec_rate = 4250,
.filter_freqs = adis16495_def_filter_freqs,
.has_pps_clk_mode = true,
/* 20 elements of 16bits */
.adis_data = ADIS16480_DATA(16495, &adis16495_1_timeouts,
- ADIS16495_BURST_MAX_DATA * 2),
+ ADIS16495_BURST_MAX_DATA * 2,
+ 6000000),
},
[ADIS16497_1] = {
.channels = adis16485_channels,
@@ -1058,13 +1157,16 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
.accel_max_scale = 40,
.temp_scale = 12500, /* 12.5 milli degree Celsius */
+ .deltang_max_val = IIO_DEGREE_TO_RAD(360),
+ .deltvel_max_val = 400,
.int_clk = 4250000,
.max_dec_rate = 4250,
.filter_freqs = adis16495_def_filter_freqs,
.has_pps_clk_mode = true,
/* 20 elements of 16bits */
.adis_data = ADIS16480_DATA(16497, &adis16495_1_timeouts,
- ADIS16495_BURST_MAX_DATA * 2),
+ ADIS16495_BURST_MAX_DATA * 2,
+ 6000000),
},
[ADIS16497_2] = {
.channels = adis16485_channels,
@@ -1074,13 +1176,16 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
.accel_max_scale = 40,
.temp_scale = 12500, /* 12.5 milli degree Celsius */
+ .deltang_max_val = IIO_DEGREE_TO_RAD(720),
+ .deltvel_max_val = 400,
.int_clk = 4250000,
.max_dec_rate = 4250,
.filter_freqs = adis16495_def_filter_freqs,
.has_pps_clk_mode = true,
/* 20 elements of 16bits */
.adis_data = ADIS16480_DATA(16497, &adis16495_1_timeouts,
- ADIS16495_BURST_MAX_DATA * 2),
+ ADIS16495_BURST_MAX_DATA * 2,
+ 6000000),
},
[ADIS16497_3] = {
.channels = adis16485_channels,
@@ -1090,13 +1195,136 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
.accel_max_scale = 40,
.temp_scale = 12500, /* 12.5 milli degree Celsius */
+ .deltang_max_val = IIO_DEGREE_TO_RAD(2160),
+ .deltvel_max_val = 400,
.int_clk = 4250000,
.max_dec_rate = 4250,
.filter_freqs = adis16495_def_filter_freqs,
.has_pps_clk_mode = true,
/* 20 elements of 16bits */
.adis_data = ADIS16480_DATA(16497, &adis16495_1_timeouts,
- ADIS16495_BURST_MAX_DATA * 2),
+ ADIS16495_BURST_MAX_DATA * 2,
+ 6000000),
+ },
+ [ADIS16545_1] = {
+ .channels = adis16545_channels,
+ .num_channels = ARRAY_SIZE(adis16545_channels),
+ .gyro_max_val = 20000 << 16,
+ .gyro_max_scale = IIO_DEGREE_TO_RAD(125),
+ .accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
+ .accel_max_scale = 8,
+ .temp_scale = 7000, /* 7 milli degree Celsius */
+ .deltang_max_val = IIO_DEGREE_TO_RAD(360),
+ .deltvel_max_val = 100,
+ .int_clk = 4250000,
+ .max_dec_rate = 4250,
+ .filter_freqs = adis16495_def_filter_freqs,
+ .has_pps_clk_mode = true,
+ .has_burst_delta_data = true,
+ /* 20 elements of 16bits */
+ .adis_data = ADIS16480_DATA(16545, &adis16545_timeouts,
+ ADIS16495_BURST_MAX_DATA * 2,
+ 6500000),
+ },
+ [ADIS16545_2] = {
+ .channels = adis16545_channels,
+ .num_channels = ARRAY_SIZE(adis16545_channels),
+ .gyro_max_val = 18000 << 16,
+ .gyro_max_scale = IIO_DEGREE_TO_RAD(450),
+ .accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
+ .accel_max_scale = 8,
+ .temp_scale = 7000, /* 7 milli degree Celsius */
+ .deltang_max_val = IIO_DEGREE_TO_RAD(720),
+ .deltvel_max_val = 100,
+ .int_clk = 4250000,
+ .max_dec_rate = 4250,
+ .filter_freqs = adis16495_def_filter_freqs,
+ .has_pps_clk_mode = true,
+ .has_burst_delta_data = true,
+ /* 20 elements of 16bits */
+ .adis_data = ADIS16480_DATA(16545, &adis16545_timeouts,
+ ADIS16495_BURST_MAX_DATA * 2,
+ 6500000),
+ },
+ [ADIS16545_3] = {
+ .channels = adis16545_channels,
+ .num_channels = ARRAY_SIZE(adis16545_channels),
+ .gyro_max_val = 20000 << 16,
+ .gyro_max_scale = IIO_DEGREE_TO_RAD(2000),
+ .accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
+ .accel_max_scale = 8,
+ .temp_scale = 7000, /* 7 milli degree Celsius */
+ .deltang_max_val = IIO_DEGREE_TO_RAD(2160),
+ .deltvel_max_val = 100,
+ .int_clk = 4250000,
+ .max_dec_rate = 4250,
+ .filter_freqs = adis16495_def_filter_freqs,
+ .has_pps_clk_mode = true,
+ .has_burst_delta_data = true,
+ /* 20 elements of 16bits */
+ .adis_data = ADIS16480_DATA(16545, &adis16545_timeouts,
+ ADIS16495_BURST_MAX_DATA * 2,
+ 6500000),
+ },
+ [ADIS16547_1] = {
+ .channels = adis16545_channels,
+ .num_channels = ARRAY_SIZE(adis16545_channels),
+ .gyro_max_val = 20000 << 16,
+ .gyro_max_scale = IIO_DEGREE_TO_RAD(125),
+ .accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
+ .accel_max_scale = 40,
+ .temp_scale = 7000, /* 7 milli degree Celsius */
+ .deltang_max_val = IIO_DEGREE_TO_RAD(360),
+ .deltvel_max_val = 400,
+ .int_clk = 4250000,
+ .max_dec_rate = 4250,
+ .filter_freqs = adis16495_def_filter_freqs,
+ .has_pps_clk_mode = true,
+ .has_burst_delta_data = true,
+ /* 20 elements of 16bits */
+ .adis_data = ADIS16480_DATA(16547, &adis16545_timeouts,
+ ADIS16495_BURST_MAX_DATA * 2,
+ 6500000),
+ },
+ [ADIS16547_2] = {
+ .channels = adis16545_channels,
+ .num_channels = ARRAY_SIZE(adis16545_channels),
+ .gyro_max_val = 18000 << 16,
+ .gyro_max_scale = IIO_DEGREE_TO_RAD(450),
+ .accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
+ .accel_max_scale = 40,
+ .temp_scale = 7000, /* 7 milli degree Celsius */
+ .deltang_max_val = IIO_DEGREE_TO_RAD(720),
+ .deltvel_max_val = 400,
+ .int_clk = 4250000,
+ .max_dec_rate = 4250,
+ .filter_freqs = adis16495_def_filter_freqs,
+ .has_pps_clk_mode = true,
+ .has_burst_delta_data = true,
+ /* 20 elements of 16bits */
+ .adis_data = ADIS16480_DATA(16547, &adis16545_timeouts,
+ ADIS16495_BURST_MAX_DATA * 2,
+ 6500000),
+ },
+ [ADIS16547_3] = {
+ .channels = adis16545_channels,
+ .num_channels = ARRAY_SIZE(adis16545_channels),
+ .gyro_max_val = 20000 << 16,
+ .gyro_max_scale = IIO_DEGREE_TO_RAD(2000),
+ .accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
+ .accel_max_scale = 40,
+ .temp_scale = 7000, /* 7 milli degree Celsius */
+ .deltang_max_val = IIO_DEGREE_TO_RAD(2160),
+ .deltvel_max_val = 400,
+ .int_clk = 4250000,
+ .max_dec_rate = 4250,
+ .filter_freqs = adis16495_def_filter_freqs,
+ .has_pps_clk_mode = true,
+ .has_burst_delta_data = true,
+ /* 20 elements of 16bits */
+ .adis_data = ADIS16480_DATA(16547, &adis16545_timeouts,
+ ADIS16495_BURST_MAX_DATA * 2,
+ 6500000),
},
};
@@ -1122,7 +1350,7 @@ static irqreturn_t adis16480_trigger_handler(int irq, void *p)
struct adis16480 *st = iio_priv(indio_dev);
struct adis *adis = &st->adis;
struct device *dev = &adis->spi->dev;
- int ret, bit, offset, i = 0;
+ int ret, bit, offset, i = 0, buff_offset = 0;
__be16 *buffer;
u32 crc;
bool valid;
@@ -1155,8 +1383,8 @@ static irqreturn_t adis16480_trigger_handler(int irq, void *p)
* 16-bit responses containing the BURST_ID depending on the sclk. If
* clk > 3.6MHz, then we will have two BURST_ID in a row. If clk < 3MHZ,
* we have only one. To manage that variation, we use the transition from the
- * BURST_ID to the SYS_E_FLAG register, which will not be equal to 0xA5A5. If
- * we not find this variation in the first 4 segments, then the data should
+ * BURST_ID to the SYS_E_FLAG register, which will not be equal to 0xA5A5/0xC3C3.
+ * If we not find this variation in the first 4 segments, then the data should
* not be valid.
*/
buffer = adis->buffer;
@@ -1164,7 +1392,7 @@ static irqreturn_t adis16480_trigger_handler(int irq, void *p)
u16 curr = be16_to_cpu(buffer[offset]);
u16 next = be16_to_cpu(buffer[offset + 1]);
- if (curr == ADIS16495_BURST_ID && next != ADIS16495_BURST_ID) {
+ if (curr == st->burst_id && next != st->burst_id) {
offset++;
break;
}
@@ -1191,11 +1419,24 @@ static irqreturn_t adis16480_trigger_handler(int irq, void *p)
switch (bit) {
case ADIS16480_SCAN_TEMP:
st->data[i++] = buffer[offset + 1];
+ /*
+ * The temperature channel has 16-bit storage size.
+ * We need to perform the padding to have the buffer
+ * elements naturally aligned in case there are any
+ * 32-bit storage size channels enabled which are added
+ * in the buffer after the temprature data. In case
+ * there is no data being added after the temperature
+ * data, the padding is harmless.
+ */
+ st->data[i++] = 0;
break;
+ case ADIS16480_SCAN_DELTANG_X ... ADIS16480_SCAN_DELTVEL_Z:
+ buff_offset = ADIS16480_SCAN_DELTANG_X;
+ fallthrough;
case ADIS16480_SCAN_GYRO_X ... ADIS16480_SCAN_ACCEL_Z:
/* The lower register data is sequenced first */
- st->data[i++] = buffer[2 * bit + offset + 3];
- st->data[i++] = buffer[2 * bit + offset + 2];
+ st->data[i++] = buffer[2 * (bit - buff_offset) + offset + 3];
+ st->data[i++] = buffer[2 * (bit - buff_offset) + offset + 2];
break;
}
}
@@ -1207,10 +1448,41 @@ irq_done:
return IRQ_HANDLED;
}
+static const unsigned long adis16545_channel_masks[] = {
+ ADIS16545_BURST_DATA_SEL_0_CHN_MASK | BIT(ADIS16480_SCAN_TEMP) | BIT(17),
+ ADIS16545_BURST_DATA_SEL_1_CHN_MASK | BIT(ADIS16480_SCAN_TEMP) | BIT(17),
+ 0,
+};
+
+static int adis16480_update_scan_mode(struct iio_dev *indio_dev,
+ const unsigned long *scan_mask)
+{
+ u16 en;
+ int ret;
+ struct adis16480 *st = iio_priv(indio_dev);
+
+ if (st->chip_info->has_burst_delta_data) {
+ if (*scan_mask & ADIS16545_BURST_DATA_SEL_0_CHN_MASK) {
+ en = FIELD_PREP(ADIS16545_BURST_DATA_SEL_MASK, 0);
+ st->burst_id = ADIS16495_GYRO_ACCEL_BURST_ID;
+ } else {
+ en = FIELD_PREP(ADIS16545_BURST_DATA_SEL_MASK, 1);
+ st->burst_id = ADIS16545_DELTA_ANG_VEL_BURST_ID;
+ }
+
+ ret = __adis_update_bits(&st->adis, ADIS16480_REG_CONFIG,
+ ADIS16545_BURST_DATA_SEL_MASK, en);
+ if (ret)
+ return ret;
+ }
+
+ return adis_update_scan_mode(indio_dev, scan_mask);
+}
+
static const struct iio_info adis16480_info = {
.read_raw = &adis16480_read_raw,
.write_raw = &adis16480_write_raw,
- .update_scan_mode = adis_update_scan_mode,
+ .update_scan_mode = &adis16480_update_scan_mode,
.debugfs_reg_access = adis_debugfs_reg_access,
};
@@ -1407,6 +1679,8 @@ static int adis16480_probe(struct spi_device *spi)
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->channels = st->chip_info->channels;
indio_dev->num_channels = st->chip_info->num_channels;
+ if (st->chip_info->has_burst_delta_data)
+ indio_dev->available_scan_masks = adis16545_channel_masks;
indio_dev->info = &adis16480_info;
indio_dev->modes = INDIO_DIRECT_MODE;
@@ -1420,6 +1694,13 @@ static int adis16480_probe(struct spi_device *spi)
if (ret)
return ret;
+ /*
+ * By default, use burst id for gyroscope and accelerometer data.
+ * This is the only option for devices which do not offer delta angle
+ * and delta velocity burst readings.
+ */
+ st->burst_id = ADIS16495_GYRO_ACCEL_BURST_ID;
+
if (st->chip_info->has_sleep_cnt) {
ret = devm_add_action_or_reset(dev, adis16480_stop, indio_dev);
if (ret)
@@ -1493,6 +1774,12 @@ static const struct spi_device_id adis16480_ids[] = {
{ "adis16497-1", ADIS16497_1 },
{ "adis16497-2", ADIS16497_2 },
{ "adis16497-3", ADIS16497_3 },
+ { "adis16545-1", ADIS16545_1 },
+ { "adis16545-2", ADIS16545_2 },
+ { "adis16545-3", ADIS16545_3 },
+ { "adis16547-1", ADIS16547_1 },
+ { "adis16547-2", ADIS16547_2 },
+ { "adis16547-3", ADIS16547_3 },
{ }
};
MODULE_DEVICE_TABLE(spi, adis16480_ids);
@@ -1509,6 +1796,12 @@ static const struct of_device_id adis16480_of_match[] = {
{ .compatible = "adi,adis16497-1" },
{ .compatible = "adi,adis16497-2" },
{ .compatible = "adi,adis16497-3" },
+ { .compatible = "adi,adis16545-1" },
+ { .compatible = "adi,adis16545-2" },
+ { .compatible = "adi,adis16545-3" },
+ { .compatible = "adi,adis16547-1" },
+ { .compatible = "adi,adis16547-2" },
+ { .compatible = "adi,adis16547-3" },
{ },
};
MODULE_DEVICE_TABLE(of, adis16480_of_match);
diff --git a/drivers/iio/imu/adis_buffer.c b/drivers/iio/imu/adis_buffer.c
index 928933027ae3..871b78b225e2 100644
--- a/drivers/iio/imu/adis_buffer.c
+++ b/drivers/iio/imu/adis_buffer.c
@@ -175,31 +175,36 @@ static void adis_buffer_cleanup(void *arg)
}
/**
- * devm_adis_setup_buffer_and_trigger() - Sets up buffer and trigger for
- * the managed adis device
+ * devm_adis_setup_buffer_and_trigger_with_attrs() - Sets up buffer and trigger
+ * for the managed adis device with buffer attributes.
* @adis: The adis device
* @indio_dev: The IIO device
- * @trigger_handler: Optional trigger handler, may be NULL.
+ * @trigger_handler: Trigger handler: should handle the buffer readings.
+ * @ops: Optional buffer setup functions, may be NULL.
+ * @buffer_attrs: Extra buffer attributes.
*
* Returns 0 on success, a negative error code otherwise.
*
- * This function sets up the buffer and trigger for a adis devices. If
- * 'trigger_handler' is NULL the default trigger handler will be used. The
- * default trigger handler will simply read the registers assigned to the
- * currently active channels.
+ * This function sets up the buffer (with buffer setup functions and extra
+ * buffer attributes) and trigger for a adis devices with buffer attributes.
*/
int
-devm_adis_setup_buffer_and_trigger(struct adis *adis, struct iio_dev *indio_dev,
- irq_handler_t trigger_handler)
+devm_adis_setup_buffer_and_trigger_with_attrs(struct adis *adis, struct iio_dev *indio_dev,
+ irq_handler_t trigger_handler,
+ const struct iio_buffer_setup_ops *ops,
+ const struct iio_dev_attr **buffer_attrs)
{
int ret;
if (!trigger_handler)
trigger_handler = adis_trigger_handler;
- ret = devm_iio_triggered_buffer_setup(&adis->spi->dev, indio_dev,
- &iio_pollfunc_store_time,
- trigger_handler, NULL);
+ ret = devm_iio_triggered_buffer_setup_ext(&adis->spi->dev, indio_dev,
+ &iio_pollfunc_store_time,
+ trigger_handler,
+ IIO_BUFFER_DIRECTION_IN,
+ ops,
+ buffer_attrs);
if (ret)
return ret;
@@ -212,5 +217,4 @@ devm_adis_setup_buffer_and_trigger(struct adis *adis, struct iio_dev *indio_dev,
return devm_add_action_or_reset(&adis->spi->dev, adis_buffer_cleanup,
adis);
}
-EXPORT_SYMBOL_NS_GPL(devm_adis_setup_buffer_and_trigger, IIO_ADISLIB);
-
+EXPORT_SYMBOL_NS_GPL(devm_adis_setup_buffer_and_trigger_with_attrs, IIO_ADISLIB);
diff --git a/drivers/iio/imu/adis_trigger.c b/drivers/iio/imu/adis_trigger.c
index f890bf842db8..a8740b043cfe 100644
--- a/drivers/iio/imu/adis_trigger.c
+++ b/drivers/iio/imu/adis_trigger.c
@@ -34,17 +34,24 @@ static int adis_validate_irq_flag(struct adis *adis)
if (adis->data->unmasked_drdy)
adis->irq_flag |= IRQF_NO_AUTOEN;
/*
- * Typically this devices have data ready either on the rising edge or
- * on the falling edge of the data ready pin. This checks enforces that
- * one of those is set in the drivers... It defaults to
- * IRQF_TRIGGER_RISING for backward compatibility with devices that
- * don't support changing the pin polarity.
+ * Typically adis devices without FIFO have data ready either on the
+ * rising edge or on the falling edge of the data ready pin.
+ * IMU devices with FIFO support have the watermark pin level driven
+ * either high or low when the FIFO is filled with the desired number
+ * of samples.
+ * It defaults to IRQF_TRIGGER_RISING for backward compatibility with
+ * devices that don't support changing the pin polarity.
*/
if (direction == IRQF_TRIGGER_NONE) {
adis->irq_flag |= IRQF_TRIGGER_RISING;
return 0;
} else if (direction != IRQF_TRIGGER_RISING &&
- direction != IRQF_TRIGGER_FALLING) {
+ direction != IRQF_TRIGGER_FALLING && !adis->data->has_fifo) {
+ dev_err(&adis->spi->dev, "Invalid IRQ mask: %08lx\n",
+ adis->irq_flag);
+ return -EINVAL;
+ } else if (direction != IRQF_TRIGGER_HIGH &&
+ direction != IRQF_TRIGGER_LOW && adis->data->has_fifo) {
dev_err(&adis->spi->dev, "Invalid IRQ mask: %08lx\n",
adis->irq_flag);
return -EINVAL;
@@ -77,11 +84,19 @@ int devm_adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev)
if (ret)
return ret;
- ret = devm_request_irq(&adis->spi->dev, adis->spi->irq,
- &iio_trigger_generic_data_rdy_poll,
- adis->irq_flag,
- indio_dev->name,
- adis->trig);
+ if (adis->data->has_fifo)
+ ret = devm_request_threaded_irq(&adis->spi->dev, adis->spi->irq,
+ NULL,
+ &iio_trigger_generic_data_rdy_poll,
+ adis->irq_flag | IRQF_ONESHOT,
+ indio_dev->name,
+ adis->trig);
+ else
+ ret = devm_request_irq(&adis->spi->dev, adis->spi->irq,
+ &iio_trigger_generic_data_rdy_poll,
+ adis->irq_flag,
+ indio_dev->name,
+ adis->trig);
if (ret)
return ret;
diff --git a/drivers/iio/imu/bmi160/bmi160_core.c b/drivers/iio/imu/bmi160/bmi160_core.c
index a77f1a8348ff..90aa04d94da5 100644
--- a/drivers/iio/imu/bmi160/bmi160_core.c
+++ b/drivers/iio/imu/bmi160/bmi160_core.c
@@ -26,6 +26,7 @@
#include "bmi160.h"
#define BMI160_REG_CHIP_ID 0x00
+#define BMI120_CHIP_ID_VAL 0xD3
#define BMI160_CHIP_ID_VAL 0xD1
#define BMI160_REG_PMU_STATUS 0x03
@@ -112,6 +113,11 @@
.ext_info = bmi160_ext_info, \
}
+static const u8 bmi_chip_ids[] = {
+ BMI120_CHIP_ID_VAL,
+ BMI160_CHIP_ID_VAL,
+};
+
/* scan indexes follow DATA register order */
enum bmi160_scan_axis {
BMI160_SCAN_EXT_MAGN_X = 0,
@@ -704,6 +710,16 @@ static int bmi160_setup_irq(struct iio_dev *indio_dev, int irq,
return bmi160_probe_trigger(indio_dev, irq, irq_type);
}
+static int bmi160_check_chip_id(const u8 chip_id)
+{
+ for (int i = 0; i < ARRAY_SIZE(bmi_chip_ids); i++) {
+ if (chip_id == bmi_chip_ids[i])
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
static int bmi160_chip_init(struct bmi160_data *data, bool use_spi)
{
int ret;
@@ -737,12 +753,10 @@ static int bmi160_chip_init(struct bmi160_data *data, bool use_spi)
dev_err(dev, "Error reading chip id\n");
goto disable_regulator;
}
- if (val != BMI160_CHIP_ID_VAL) {
- dev_err(dev, "Wrong chip id, got %x expected %x\n",
- val, BMI160_CHIP_ID_VAL);
- ret = -ENODEV;
- goto disable_regulator;
- }
+
+ ret = bmi160_check_chip_id(val);
+ if (ret)
+ dev_warn(dev, "Chip id not found: %x\n", val);
ret = bmi160_set_mode(data, BMI160_ACCEL, true);
if (ret)
diff --git a/drivers/iio/imu/bmi160/bmi160_i2c.c b/drivers/iio/imu/bmi160/bmi160_i2c.c
index a081305254db..3aa5d748f9b6 100644
--- a/drivers/iio/imu/bmi160/bmi160_i2c.c
+++ b/drivers/iio/imu/bmi160/bmi160_i2c.c
@@ -37,7 +37,8 @@ static int bmi160_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id bmi160_i2c_id[] = {
- {"bmi160", 0},
+ { "bmi120" },
+ { "bmi160" },
{}
};
MODULE_DEVICE_TABLE(i2c, bmi160_i2c_id);
@@ -52,12 +53,14 @@ static const struct acpi_device_id bmi160_acpi_match[] = {
* the affected devices are from 2021/2022.
*/
{"10EC5280", 0},
+ {"BMI0120", 0},
{"BMI0160", 0},
{ },
};
MODULE_DEVICE_TABLE(acpi, bmi160_acpi_match);
static const struct of_device_id bmi160_of_match[] = {
+ { .compatible = "bosch,bmi120" },
{ .compatible = "bosch,bmi160" },
{ },
};
diff --git a/drivers/iio/imu/bmi160/bmi160_spi.c b/drivers/iio/imu/bmi160/bmi160_spi.c
index 8b573ea99af2..9f40500132f7 100644
--- a/drivers/iio/imu/bmi160/bmi160_spi.c
+++ b/drivers/iio/imu/bmi160/bmi160_spi.c
@@ -34,18 +34,21 @@ static int bmi160_spi_probe(struct spi_device *spi)
}
static const struct spi_device_id bmi160_spi_id[] = {
+ {"bmi120", 0},
{"bmi160", 0},
{}
};
MODULE_DEVICE_TABLE(spi, bmi160_spi_id);
static const struct acpi_device_id bmi160_acpi_match[] = {
+ {"BMI0120", 0},
{"BMI0160", 0},
{ },
};
MODULE_DEVICE_TABLE(acpi, bmi160_acpi_match);
static const struct of_device_id bmi160_of_match[] = {
+ { .compatible = "bosch,bmi120" },
{ .compatible = "bosch,bmi160" },
{ },
};
diff --git a/drivers/iio/imu/bmi323/bmi323_core.c b/drivers/iio/imu/bmi323/bmi323_core.c
index 67d74a1a1b26..d708d1fe3e42 100644
--- a/drivers/iio/imu/bmi323/bmi323_core.c
+++ b/drivers/iio/imu/bmi323/bmi323_core.c
@@ -2084,9 +2084,11 @@ int bmi323_core_probe(struct device *dev)
if (ret)
return -EINVAL;
- ret = iio_read_mount_matrix(dev, &data->orientation);
- if (ret)
- return ret;
+ if (!iio_read_acpi_mount_matrix(dev, &data->orientation, "ROTM")) {
+ ret = iio_read_mount_matrix(dev, &data->orientation);
+ if (ret)
+ return ret;
+ }
indio_dev->name = "bmi323-imu";
indio_dev->info = &bmi323_info;
diff --git a/drivers/iio/imu/bno055/bno055_i2c.c b/drivers/iio/imu/bno055/bno055_i2c.c
index 6ecd750c6b76..cf3dd62a83ba 100644
--- a/drivers/iio/imu/bno055/bno055_i2c.c
+++ b/drivers/iio/imu/bno055/bno055_i2c.c
@@ -30,7 +30,7 @@ static int bno055_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id bno055_i2c_id[] = {
- {"bno055", 0},
+ { "bno055" },
{ }
};
MODULE_DEVICE_TABLE(i2c, bno055_i2c_id);
diff --git a/drivers/iio/imu/fxos8700_i2c.c b/drivers/iio/imu/fxos8700_i2c.c
index e99677ad96a2..2cc4a27a4527 100644
--- a/drivers/iio/imu/fxos8700_i2c.c
+++ b/drivers/iio/imu/fxos8700_i2c.c
@@ -36,7 +36,7 @@ static int fxos8700_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id fxos8700_i2c_id[] = {
- {"fxos8700", 0},
+ { "fxos8700" },
{ }
};
MODULE_DEVICE_TABLE(i2c, fxos8700_i2c_id);
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h
index c4ac91f6bafe..3a07e43e4cf1 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h
@@ -177,11 +177,15 @@ struct inv_icm42600_state {
* struct inv_icm42600_sensor_state - sensor state variables
* @scales: table of scales.
* @scales_len: length (nb of items) of the scales table.
+ * @power_mode: sensor requested power mode (for common frequencies)
+ * @filter: sensor filter.
* @ts: timestamp module states.
*/
struct inv_icm42600_sensor_state {
const int *scales;
size_t scales_len;
+ enum inv_icm42600_sensor_mode power_mode;
+ enum inv_icm42600_filter filter;
struct inv_sensors_timestamp ts;
};
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
index 4b2566693614..56ac19814250 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
@@ -55,8 +55,108 @@ enum inv_icm42600_accel_scan {
INV_ICM42600_ACCEL_SCAN_TIMESTAMP,
};
+static const char * const inv_icm42600_accel_power_mode_items[] = {
+ "low-noise",
+ "low-power",
+};
+static const int inv_icm42600_accel_power_mode_values[] = {
+ INV_ICM42600_SENSOR_MODE_LOW_NOISE,
+ INV_ICM42600_SENSOR_MODE_LOW_POWER,
+};
+static const int inv_icm42600_accel_filter_values[] = {
+ INV_ICM42600_FILTER_BW_ODR_DIV_2,
+ INV_ICM42600_FILTER_AVG_16X,
+};
+
+static int inv_icm42600_accel_power_mode_set(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ unsigned int idx)
+{
+ struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
+ struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev);
+ int power_mode, filter;
+
+ if (chan->type != IIO_ACCEL)
+ return -EINVAL;
+
+ if (idx >= ARRAY_SIZE(inv_icm42600_accel_power_mode_values))
+ return -EINVAL;
+
+ if (iio_buffer_enabled(indio_dev))
+ return -EBUSY;
+
+ power_mode = inv_icm42600_accel_power_mode_values[idx];
+ filter = inv_icm42600_accel_filter_values[idx];
+
+ guard(mutex)(&st->lock);
+
+ /* prevent change if power mode is not supported by the ODR */
+ switch (power_mode) {
+ case INV_ICM42600_SENSOR_MODE_LOW_NOISE:
+ if (st->conf.accel.odr >= INV_ICM42600_ODR_6_25HZ_LP &&
+ st->conf.accel.odr <= INV_ICM42600_ODR_1_5625HZ_LP)
+ return -EPERM;
+ break;
+ case INV_ICM42600_SENSOR_MODE_LOW_POWER:
+ default:
+ if (st->conf.accel.odr <= INV_ICM42600_ODR_1KHZ_LN)
+ return -EPERM;
+ break;
+ }
+
+ accel_st->power_mode = power_mode;
+ accel_st->filter = filter;
+
+ return 0;
+}
+
+static int inv_icm42600_accel_power_mode_get(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan)
+{
+ struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
+ struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev);
+ unsigned int idx;
+ int power_mode;
+
+ if (chan->type != IIO_ACCEL)
+ return -EINVAL;
+
+ guard(mutex)(&st->lock);
+
+ /* if sensor is on, returns actual power mode and not configured one */
+ switch (st->conf.accel.mode) {
+ case INV_ICM42600_SENSOR_MODE_LOW_POWER:
+ case INV_ICM42600_SENSOR_MODE_LOW_NOISE:
+ power_mode = st->conf.accel.mode;
+ break;
+ default:
+ power_mode = accel_st->power_mode;
+ break;
+ }
+
+ for (idx = 0; idx < ARRAY_SIZE(inv_icm42600_accel_power_mode_values); ++idx) {
+ if (power_mode == inv_icm42600_accel_power_mode_values[idx])
+ break;
+ }
+ if (idx >= ARRAY_SIZE(inv_icm42600_accel_power_mode_values))
+ return -EINVAL;
+
+ return idx;
+}
+
+static const struct iio_enum inv_icm42600_accel_power_mode_enum = {
+ .items = inv_icm42600_accel_power_mode_items,
+ .num_items = ARRAY_SIZE(inv_icm42600_accel_power_mode_items),
+ .set = inv_icm42600_accel_power_mode_set,
+ .get = inv_icm42600_accel_power_mode_get,
+};
+
static const struct iio_chan_spec_ext_info inv_icm42600_accel_ext_infos[] = {
IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, inv_icm42600_get_mount_matrix),
+ IIO_ENUM_AVAILABLE("power_mode", IIO_SHARED_BY_TYPE,
+ &inv_icm42600_accel_power_mode_enum),
+ IIO_ENUM("power_mode", IIO_SHARED_BY_TYPE,
+ &inv_icm42600_accel_power_mode_enum),
{},
};
@@ -120,7 +220,8 @@ static int inv_icm42600_accel_update_scan_mode(struct iio_dev *indio_dev,
if (*scan_mask & INV_ICM42600_SCAN_MASK_ACCEL_3AXIS) {
/* enable accel sensor */
- conf.mode = INV_ICM42600_SENSOR_MODE_LOW_NOISE;
+ conf.mode = accel_st->power_mode;
+ conf.filter = accel_st->filter;
ret = inv_icm42600_set_accel_conf(st, &conf, &sleep_accel);
if (ret)
goto out_unlock;
@@ -140,10 +241,12 @@ out_unlock:
return ret;
}
-static int inv_icm42600_accel_read_sensor(struct inv_icm42600_state *st,
+static int inv_icm42600_accel_read_sensor(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int16_t *val)
{
+ struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
+ struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev);
struct device *dev = regmap_get_device(st->map);
struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT;
unsigned int reg;
@@ -171,7 +274,8 @@ static int inv_icm42600_accel_read_sensor(struct inv_icm42600_state *st,
mutex_lock(&st->lock);
/* enable accel sensor */
- conf.mode = INV_ICM42600_SENSOR_MODE_LOW_NOISE;
+ conf.mode = accel_st->power_mode;
+ conf.filter = accel_st->filter;
ret = inv_icm42600_set_accel_conf(st, &conf, NULL);
if (ret)
goto exit;
@@ -273,6 +377,12 @@ static int inv_icm42600_accel_write_scale(struct iio_dev *indio_dev,
/* IIO format int + micro */
static const int inv_icm42600_accel_odr[] = {
+ /* 1.5625Hz */
+ 1, 562500,
+ /* 3.125Hz */
+ 3, 125000,
+ /* 6.25Hz */
+ 6, 250000,
/* 12.5Hz */
12, 500000,
/* 25Hz */
@@ -292,6 +402,9 @@ static const int inv_icm42600_accel_odr[] = {
};
static const int inv_icm42600_accel_odr_conv[] = {
+ INV_ICM42600_ODR_1_5625HZ_LP,
+ INV_ICM42600_ODR_3_125HZ_LP,
+ INV_ICM42600_ODR_6_25HZ_LP,
INV_ICM42600_ODR_12_5HZ,
INV_ICM42600_ODR_25HZ,
INV_ICM42600_ODR_50HZ,
@@ -577,7 +690,7 @@ static int inv_icm42600_accel_read_raw(struct iio_dev *indio_dev,
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
- ret = inv_icm42600_accel_read_sensor(st, chan, &data);
+ ret = inv_icm42600_accel_read_sensor(indio_dev, chan, &data);
iio_device_release_direct_mode(indio_dev);
if (ret)
return ret;
@@ -750,6 +863,9 @@ struct iio_dev *inv_icm42600_accel_init(struct inv_icm42600_state *st)
accel_st->scales_len = ARRAY_SIZE(inv_icm42600_accel_scale);
break;
}
+ /* low-power by default at init */
+ accel_st->power_mode = INV_ICM42600_SENSOR_MODE_LOW_POWER;
+ accel_st->filter = INV_ICM42600_FILTER_AVG_16X;
/*
* clock period is 32kHz (31250ns)
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
index 62fdae530334..61f1f6d4c421 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
@@ -34,12 +34,56 @@ static const struct regmap_range_cfg inv_icm42600_regmap_ranges[] = {
},
};
+static const struct regmap_range inv_icm42600_regmap_volatile_yes_ranges[] = {
+ /* Sensor data registers */
+ regmap_reg_range(0x001D, 0x002A),
+ /* INT status, FIFO, APEX data */
+ regmap_reg_range(0x002D, 0x0038),
+ /* Signal path reset */
+ regmap_reg_range(0x004B, 0x004B),
+ /* FIFO lost packets */
+ regmap_reg_range(0x006C, 0x006D),
+ /* Timestamp value */
+ regmap_reg_range(0x1062, 0x1064),
+};
+
+static const struct regmap_range inv_icm42600_regmap_volatile_no_ranges[] = {
+ regmap_reg_range(0x0000, 0x001C),
+ regmap_reg_range(0x006E, 0x1061),
+ regmap_reg_range(0x1065, 0x4FFF),
+};
+
+static const struct regmap_access_table inv_icm42600_regmap_volatile_accesses[] = {
+ {
+ .yes_ranges = inv_icm42600_regmap_volatile_yes_ranges,
+ .n_yes_ranges = ARRAY_SIZE(inv_icm42600_regmap_volatile_yes_ranges),
+ .no_ranges = inv_icm42600_regmap_volatile_no_ranges,
+ .n_no_ranges = ARRAY_SIZE(inv_icm42600_regmap_volatile_no_ranges),
+ },
+};
+
+static const struct regmap_range inv_icm42600_regmap_rd_noinc_no_ranges[] = {
+ regmap_reg_range(0x0000, INV_ICM42600_REG_FIFO_DATA - 1),
+ regmap_reg_range(INV_ICM42600_REG_FIFO_DATA + 1, 0x4FFF),
+};
+
+static const struct regmap_access_table inv_icm42600_regmap_rd_noinc_accesses[] = {
+ {
+ .no_ranges = inv_icm42600_regmap_rd_noinc_no_ranges,
+ .n_no_ranges = ARRAY_SIZE(inv_icm42600_regmap_rd_noinc_no_ranges),
+ },
+};
+
const struct regmap_config inv_icm42600_regmap_config = {
+ .name = "inv_icm42600",
.reg_bits = 8,
.val_bits = 8,
.max_register = 0x4FFF,
.ranges = inv_icm42600_regmap_ranges,
.num_ranges = ARRAY_SIZE(inv_icm42600_regmap_ranges),
+ .volatile_table = inv_icm42600_regmap_volatile_accesses,
+ .rd_noinc_table = inv_icm42600_regmap_rd_noinc_accesses,
+ .cache_type = REGCACHE_RBTREE,
};
EXPORT_SYMBOL_NS_GPL(inv_icm42600_regmap_config, IIO_ICM42600);
@@ -248,6 +292,23 @@ int inv_icm42600_set_accel_conf(struct inv_icm42600_state *st,
if (conf->filter < 0)
conf->filter = oldconf->filter;
+ /* force power mode against ODR when sensor is on */
+ switch (conf->mode) {
+ case INV_ICM42600_SENSOR_MODE_LOW_POWER:
+ case INV_ICM42600_SENSOR_MODE_LOW_NOISE:
+ if (conf->odr <= INV_ICM42600_ODR_1KHZ_LN) {
+ conf->mode = INV_ICM42600_SENSOR_MODE_LOW_NOISE;
+ conf->filter = INV_ICM42600_FILTER_BW_ODR_DIV_2;
+ } else if (conf->odr >= INV_ICM42600_ODR_6_25HZ_LP &&
+ conf->odr <= INV_ICM42600_ODR_1_5625HZ_LP) {
+ conf->mode = INV_ICM42600_SENSOR_MODE_LOW_POWER;
+ conf->filter = INV_ICM42600_FILTER_AVG_16X;
+ }
+ break;
+ default:
+ break;
+ }
+
/* set ACCEL_CONFIG0 register (accel fullscale & odr) */
if (conf->fs != oldconf->fs || conf->odr != oldconf->odr) {
val = INV_ICM42600_ACCEL_CONFIG0_FS(conf->fs) |
@@ -441,6 +502,16 @@ static int inv_icm42600_setup(struct inv_icm42600_state *st,
if (ret)
return ret;
+ /*
+ * Use RC clock for accel low-power to fix glitches when switching
+ * gyro on/off while accel low-power is on.
+ */
+ ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG1,
+ INV_ICM42600_INTF_CONFIG1_ACCEL_LP_CLK_RC,
+ INV_ICM42600_INTF_CONFIG1_ACCEL_LP_CLK_RC);
+ if (ret)
+ return ret;
+
return inv_icm42600_set_conf(st, hw->conf);
}
diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c
index 7d3e061f3046..d37eca5ef761 100644
--- a/drivers/iio/imu/kmx61.c
+++ b/drivers/iio/imu/kmx61.c
@@ -1505,7 +1505,7 @@ static const struct acpi_device_id kmx61_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, kmx61_acpi_match);
static const struct i2c_device_id kmx61_id[] = {
- {"kmx611021", 0},
+ { "kmx611021" },
{}
};
diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
index cec58a604d73..0138b21b244f 100644
--- a/drivers/iio/industrialio-buffer.c
+++ b/drivers/iio/industrialio-buffer.c
@@ -365,8 +365,16 @@ static ssize_t iio_show_fixed_type(struct device *dev,
struct device_attribute *attr,
char *buf)
{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
- u8 type = this_attr->c->scan_type.endianness;
+ const struct iio_scan_type *scan_type;
+ u8 type;
+
+ scan_type = iio_get_current_scan_type(indio_dev, this_attr->c);
+ if (IS_ERR(scan_type))
+ return PTR_ERR(scan_type);
+
+ type = scan_type->endianness;
if (type == IIO_CPU) {
#ifdef __LITTLE_ENDIAN
@@ -375,21 +383,21 @@ static ssize_t iio_show_fixed_type(struct device *dev,
type = IIO_BE;
#endif
}
- if (this_attr->c->scan_type.repeat > 1)
+ if (scan_type->repeat > 1)
return sysfs_emit(buf, "%s:%c%d/%dX%d>>%u\n",
iio_endian_prefix[type],
- this_attr->c->scan_type.sign,
- this_attr->c->scan_type.realbits,
- this_attr->c->scan_type.storagebits,
- this_attr->c->scan_type.repeat,
- this_attr->c->scan_type.shift);
+ scan_type->sign,
+ scan_type->realbits,
+ scan_type->storagebits,
+ scan_type->repeat,
+ scan_type->shift);
else
return sysfs_emit(buf, "%s:%c%d/%d>>%u\n",
iio_endian_prefix[type],
- this_attr->c->scan_type.sign,
- this_attr->c->scan_type.realbits,
- this_attr->c->scan_type.storagebits,
- this_attr->c->scan_type.shift);
+ scan_type->sign,
+ scan_type->realbits,
+ scan_type->storagebits,
+ scan_type->shift);
}
static ssize_t iio_scan_el_show(struct device *dev,
@@ -690,20 +698,27 @@ static ssize_t enable_show(struct device *dev, struct device_attribute *attr,
return sysfs_emit(buf, "%d\n", iio_buffer_is_active(buffer));
}
-static unsigned int iio_storage_bytes_for_si(struct iio_dev *indio_dev,
- unsigned int scan_index)
+static int iio_storage_bytes_for_si(struct iio_dev *indio_dev,
+ unsigned int scan_index)
{
const struct iio_chan_spec *ch;
+ const struct iio_scan_type *scan_type;
unsigned int bytes;
ch = iio_find_channel_from_si(indio_dev, scan_index);
- bytes = ch->scan_type.storagebits / 8;
- if (ch->scan_type.repeat > 1)
- bytes *= ch->scan_type.repeat;
+ scan_type = iio_get_current_scan_type(indio_dev, ch);
+ if (IS_ERR(scan_type))
+ return PTR_ERR(scan_type);
+
+ bytes = scan_type->storagebits / 8;
+
+ if (scan_type->repeat > 1)
+ bytes *= scan_type->repeat;
+
return bytes;
}
-static unsigned int iio_storage_bytes_for_timestamp(struct iio_dev *indio_dev)
+static int iio_storage_bytes_for_timestamp(struct iio_dev *indio_dev)
{
struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
@@ -721,6 +736,9 @@ static int iio_compute_scan_bytes(struct iio_dev *indio_dev,
for_each_set_bit(i, mask,
indio_dev->masklength) {
length = iio_storage_bytes_for_si(indio_dev, i);
+ if (length < 0)
+ return length;
+
bytes = ALIGN(bytes, length);
bytes += length;
largest = max(largest, length);
@@ -728,6 +746,9 @@ static int iio_compute_scan_bytes(struct iio_dev *indio_dev,
if (timestamp) {
length = iio_storage_bytes_for_timestamp(indio_dev);
+ if (length < 0)
+ return length;
+
bytes = ALIGN(bytes, length);
bytes += length;
largest = max(largest, length);
@@ -1007,14 +1028,22 @@ static int iio_buffer_update_demux(struct iio_dev *indio_dev,
indio_dev->masklength,
in_ind + 1);
while (in_ind != out_ind) {
- length = iio_storage_bytes_for_si(indio_dev, in_ind);
+ ret = iio_storage_bytes_for_si(indio_dev, in_ind);
+ if (ret < 0)
+ goto error_clear_mux_table;
+
+ length = ret;
/* Make sure we are aligned */
in_loc = roundup(in_loc, length) + length;
in_ind = find_next_bit(indio_dev->active_scan_mask,
indio_dev->masklength,
in_ind + 1);
}
- length = iio_storage_bytes_for_si(indio_dev, in_ind);
+ ret = iio_storage_bytes_for_si(indio_dev, in_ind);
+ if (ret < 0)
+ goto error_clear_mux_table;
+
+ length = ret;
out_loc = roundup(out_loc, length);
in_loc = roundup(in_loc, length);
ret = iio_buffer_add_demux(buffer, &p, in_loc, out_loc, length);
@@ -1025,7 +1054,11 @@ static int iio_buffer_update_demux(struct iio_dev *indio_dev,
}
/* Relies on scan_timestamp being last */
if (buffer->scan_timestamp) {
- length = iio_storage_bytes_for_timestamp(indio_dev);
+ ret = iio_storage_bytes_for_timestamp(indio_dev);
+ if (ret < 0)
+ goto error_clear_mux_table;
+
+ length = ret;
out_loc = roundup(out_loc, length);
in_loc = roundup(in_loc, length);
ret = iio_buffer_add_demux(buffer, &p, in_loc, out_loc, length);
@@ -1592,6 +1625,22 @@ static long iio_device_buffer_ioctl(struct iio_dev *indio_dev, struct file *filp
}
}
+static int iio_channel_validate_scan_type(struct device *dev, int ch,
+ const struct iio_scan_type *scan_type)
+{
+ /* Verify that sample bits fit into storage */
+ if (scan_type->storagebits < scan_type->realbits + scan_type->shift) {
+ dev_err(dev,
+ "Channel %d storagebits (%d) < shifted realbits (%d + %d)\n",
+ ch, scan_type->storagebits,
+ scan_type->realbits,
+ scan_type->shift);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer,
struct iio_dev *indio_dev,
int index)
@@ -1616,20 +1665,38 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer,
if (channels) {
/* new magic */
for (i = 0; i < indio_dev->num_channels; i++) {
+ const struct iio_scan_type *scan_type;
+
if (channels[i].scan_index < 0)
continue;
- /* Verify that sample bits fit into storage */
- if (channels[i].scan_type.storagebits <
- channels[i].scan_type.realbits +
- channels[i].scan_type.shift) {
- dev_err(&indio_dev->dev,
- "Channel %d storagebits (%d) < shifted realbits (%d + %d)\n",
- i, channels[i].scan_type.storagebits,
- channels[i].scan_type.realbits,
- channels[i].scan_type.shift);
- ret = -EINVAL;
- goto error_cleanup_dynamic;
+ if (channels[i].has_ext_scan_type) {
+ int j;
+
+ /*
+ * get_current_scan_type is required when using
+ * extended scan types.
+ */
+ if (!indio_dev->info->get_current_scan_type) {
+ ret = -EINVAL;
+ goto error_cleanup_dynamic;
+ }
+
+ for (j = 0; j < channels[i].num_ext_scan_type; j++) {
+ scan_type = &channels[i].ext_scan_type[j];
+
+ ret = iio_channel_validate_scan_type(
+ &indio_dev->dev, i, scan_type);
+ if (ret)
+ goto error_cleanup_dynamic;
+ }
+ } else {
+ scan_type = &channels[i].scan_type;
+
+ ret = iio_channel_validate_scan_type(
+ &indio_dev->dev, i, scan_type);
+ if (ret)
+ goto error_cleanup_dynamic;
}
ret = iio_buffer_add_channel_sysfs(indio_dev, buffer,
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index fa7cc051b4c4..2f185b386949 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -758,9 +758,11 @@ static ssize_t iio_read_channel_info(struct device *dev,
INDIO_MAX_RAW_ELEMENTS,
vals, &val_len,
this_attr->address);
- else
+ else if (indio_dev->info->read_raw)
ret = indio_dev->info->read_raw(indio_dev, this_attr->c,
&vals[0], &vals[1], this_attr->address);
+ else
+ return -EINVAL;
if (ret < 0)
return ret;
@@ -842,6 +844,9 @@ static ssize_t iio_read_channel_info_avail(struct device *dev,
int length;
int type;
+ if (!indio_dev->info->read_avail)
+ return -EINVAL;
+
ret = indio_dev->info->read_avail(indio_dev, this_attr->c,
&vals, &type, &length,
this_attr->address);
diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c
index 910c1f14abd5..db06501b0e61 100644
--- a/drivers/iio/industrialio-event.c
+++ b/drivers/iio/industrialio-event.c
@@ -285,6 +285,9 @@ static ssize_t iio_ev_state_store(struct device *dev,
if (ret < 0)
return ret;
+ if (!indio_dev->info->write_event_config)
+ return -EINVAL;
+
ret = indio_dev->info->write_event_config(indio_dev,
this_attr->c, iio_ev_attr_type(this_attr),
iio_ev_attr_dir(this_attr), val);
@@ -300,6 +303,9 @@ static ssize_t iio_ev_state_show(struct device *dev,
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int val;
+ if (!indio_dev->info->read_event_config)
+ return -EINVAL;
+
val = indio_dev->info->read_event_config(indio_dev,
this_attr->c, iio_ev_attr_type(this_attr),
iio_ev_attr_dir(this_attr));
@@ -318,6 +324,9 @@ static ssize_t iio_ev_value_show(struct device *dev,
int val, val2, val_arr[2];
int ret;
+ if (!indio_dev->info->read_event_value)
+ return -EINVAL;
+
ret = indio_dev->info->read_event_value(indio_dev,
this_attr->c, iio_ev_attr_type(this_attr),
iio_ev_attr_dir(this_attr), iio_ev_attr_info(this_attr),
@@ -572,8 +581,8 @@ int iio_device_register_eventset(struct iio_dev *indio_dev)
iio_check_for_dynamic_events(indio_dev)))
return 0;
- ev_int = kzalloc(sizeof(struct iio_event_interface), GFP_KERNEL);
- if (ev_int == NULL)
+ ev_int = kzalloc(sizeof(*ev_int), GFP_KERNEL);
+ if (!ev_int)
return -ENOMEM;
iio_dev_opaque->event_interface = ev_int;
diff --git a/drivers/iio/industrialio-gts-helper.c b/drivers/iio/industrialio-gts-helper.c
index b51eb6cb766f..59d7615c0f56 100644
--- a/drivers/iio/industrialio-gts-helper.c
+++ b/drivers/iio/industrialio-gts-helper.c
@@ -362,17 +362,20 @@ static int iio_gts_build_avail_time_table(struct iio_gts *gts)
for (i = gts->num_itime - 1; i >= 0; i--) {
int new = gts->itime_table[i].time_us;
- if (times[idx] < new) {
+ if (idx == 0 || times[idx - 1] < new) {
times[idx++] = new;
continue;
}
- for (j = 0; j <= idx; j++) {
+ for (j = 0; j < idx; j++) {
+ if (times[j] == new)
+ break;
if (times[j] > new) {
memmove(&times[j + 1], &times[j],
(idx - j) * sizeof(int));
times[j] = new;
idx++;
+ break;
}
}
}
diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
index 485e6fc44a04..39cf26d69d17 100644
--- a/drivers/iio/inkern.c
+++ b/drivers/iio/inkern.c
@@ -543,6 +543,7 @@ EXPORT_SYMBOL_GPL(devm_iio_channel_get_all);
static int iio_channel_read(struct iio_channel *chan, int *val, int *val2,
enum iio_chan_info_enum info)
{
+ const struct iio_info *iio_info = chan->indio_dev->info;
int unused;
int vals[INDIO_MAX_RAW_ELEMENTS];
int ret;
@@ -554,15 +555,18 @@ static int iio_channel_read(struct iio_channel *chan, int *val, int *val2,
if (!iio_channel_has_info(chan->channel, info))
return -EINVAL;
- if (chan->indio_dev->info->read_raw_multi) {
- ret = chan->indio_dev->info->read_raw_multi(chan->indio_dev,
- chan->channel, INDIO_MAX_RAW_ELEMENTS,
- vals, &val_len, info);
+ if (iio_info->read_raw_multi) {
+ ret = iio_info->read_raw_multi(chan->indio_dev,
+ chan->channel,
+ INDIO_MAX_RAW_ELEMENTS,
+ vals, &val_len, info);
*val = vals[0];
*val2 = vals[1];
+ } else if (iio_info->read_raw) {
+ ret = iio_info->read_raw(chan->indio_dev,
+ chan->channel, val, val2, info);
} else {
- ret = chan->indio_dev->info->read_raw(chan->indio_dev,
- chan->channel, val, val2, info);
+ return -EINVAL;
}
return ret;
@@ -750,11 +754,15 @@ static int iio_channel_read_avail(struct iio_channel *chan,
const int **vals, int *type, int *length,
enum iio_chan_info_enum info)
{
+ const struct iio_info *iio_info = chan->indio_dev->info;
+
if (!iio_channel_has_available(chan->channel, info))
return -EINVAL;
- return chan->indio_dev->info->read_avail(chan->indio_dev, chan->channel,
- vals, type, length, info);
+ if (iio_info->read_avail)
+ return iio_info->read_avail(chan->indio_dev, chan->channel,
+ vals, type, length, info);
+ return -EINVAL;
}
int iio_read_avail_channel_attribute(struct iio_channel *chan,
@@ -917,8 +925,12 @@ EXPORT_SYMBOL_GPL(iio_get_channel_type);
static int iio_channel_write(struct iio_channel *chan, int val, int val2,
enum iio_chan_info_enum info)
{
- return chan->indio_dev->info->write_raw(chan->indio_dev,
- chan->channel, val, val2, info);
+ const struct iio_info *iio_info = chan->indio_dev->info;
+
+ if (iio_info->write_raw)
+ return iio_info->write_raw(chan->indio_dev,
+ chan->channel, val, val2, info);
+ return -EINVAL;
}
int iio_write_channel_attribute(struct iio_channel *chan, int val, int val2,
diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig
index 9a587d403118..b68dcc1fbaca 100644
--- a/drivers/iio/light/Kconfig
+++ b/drivers/iio/light/Kconfig
@@ -666,6 +666,17 @@ config VEML6030
To compile this driver as a module, choose M here: the
module will be called veml6030.
+config VEML6040
+ tristate "VEML6040 RGBW light sensor"
+ select REGMAP_I2C
+ depends on I2C
+ help
+ Say Y here if you want to build a driver for the Vishay VEML6040
+ RGBW light sensor.
+
+ To compile this driver as a module, choose M here: the
+ module will be called veml6040.
+
config VEML6070
tristate "VEML6070 UV A light sensor"
depends on I2C
diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile
index a30f906e91ba..1a071a8e9f8e 100644
--- a/drivers/iio/light/Makefile
+++ b/drivers/iio/light/Makefile
@@ -62,6 +62,7 @@ obj-$(CONFIG_US5182D) += us5182d.o
obj-$(CONFIG_VCNL4000) += vcnl4000.o
obj-$(CONFIG_VCNL4035) += vcnl4035.o
obj-$(CONFIG_VEML6030) += veml6030.o
+obj-$(CONFIG_VEML6040) += veml6040.o
obj-$(CONFIG_VEML6070) += veml6070.o
obj-$(CONFIG_VEML6075) += veml6075.o
obj-$(CONFIG_VL6180) += vl6180.o
diff --git a/drivers/iio/light/adjd_s311.c b/drivers/iio/light/adjd_s311.c
index 5fd775a20176..5169f12c3eba 100644
--- a/drivers/iio/light/adjd_s311.c
+++ b/drivers/iio/light/adjd_s311.c
@@ -261,7 +261,7 @@ static int adjd_s311_probe(struct i2c_client *client)
}
static const struct i2c_device_id adjd_s311_id[] = {
- { "adjd_s311", 0 },
+ { "adjd_s311" },
{ }
};
MODULE_DEVICE_TABLE(i2c, adjd_s311_id);
diff --git a/drivers/iio/light/adux1020.c b/drivers/iio/light/adux1020.c
index aa4a6c78f0aa..d4eb938c3bf5 100644
--- a/drivers/iio/light/adux1020.c
+++ b/drivers/iio/light/adux1020.c
@@ -821,7 +821,7 @@ static int adux1020_probe(struct i2c_client *client)
}
static const struct i2c_device_id adux1020_id[] = {
- { "adux1020", 0 },
+ { "adux1020" },
{}
};
MODULE_DEVICE_TABLE(i2c, adux1020_id);
diff --git a/drivers/iio/light/al3320a.c b/drivers/iio/light/al3320a.c
index 105f379b9b41..497ea3fe3377 100644
--- a/drivers/iio/light/al3320a.c
+++ b/drivers/iio/light/al3320a.c
@@ -236,7 +236,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(al3320a_pm_ops, al3320a_suspend,
al3320a_resume);
static const struct i2c_device_id al3320a_id[] = {
- {"al3320a", 0},
+ { "al3320a" },
{}
};
MODULE_DEVICE_TABLE(i2c, al3320a_id);
diff --git a/drivers/iio/light/apds9300.c b/drivers/iio/light/apds9300.c
index 0f978b30a232..11f2ab4ca261 100644
--- a/drivers/iio/light/apds9300.c
+++ b/drivers/iio/light/apds9300.c
@@ -493,7 +493,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(apds9300_pm_ops, apds9300_suspend,
apds9300_resume);
static const struct i2c_device_id apds9300_id[] = {
- { APDS9300_DRV_NAME, 0 },
+ { APDS9300_DRV_NAME },
{ }
};
diff --git a/drivers/iio/light/apds9960.c b/drivers/iio/light/apds9960.c
index 1065a340b12b..e9e65130b6f9 100644
--- a/drivers/iio/light/apds9960.c
+++ b/drivers/iio/light/apds9960.c
@@ -1107,7 +1107,7 @@ static const struct dev_pm_ops apds9960_pm_ops = {
};
static const struct i2c_device_id apds9960_id[] = {
- { "apds9960", 0 },
+ { "apds9960" },
{}
};
MODULE_DEVICE_TABLE(i2c, apds9960_id);
diff --git a/drivers/iio/light/bh1780.c b/drivers/iio/light/bh1780.c
index b84166c5fa06..475f44954f61 100644
--- a/drivers/iio/light/bh1780.c
+++ b/drivers/iio/light/bh1780.c
@@ -256,8 +256,8 @@ static DEFINE_RUNTIME_DEV_PM_OPS(bh1780_dev_pm_ops, bh1780_runtime_suspend,
bh1780_runtime_resume, NULL);
static const struct i2c_device_id bh1780_id[] = {
- { "bh1780", 0 },
- { },
+ { "bh1780" },
+ { }
};
MODULE_DEVICE_TABLE(i2c, bh1780_id);
diff --git a/drivers/iio/light/cm3232.c b/drivers/iio/light/cm3232.c
index d48a70efca69..b6288dd25bbf 100644
--- a/drivers/iio/light/cm3232.c
+++ b/drivers/iio/light/cm3232.c
@@ -368,7 +368,7 @@ static void cm3232_remove(struct i2c_client *client)
}
static const struct i2c_device_id cm3232_id[] = {
- {"cm3232", 0},
+ { "cm3232" },
{}
};
diff --git a/drivers/iio/light/cm3323.c b/drivers/iio/light/cm3323.c
index 35d20207a648..79a64e2ff812 100644
--- a/drivers/iio/light/cm3323.c
+++ b/drivers/iio/light/cm3323.c
@@ -250,7 +250,7 @@ static int cm3323_probe(struct i2c_client *client)
}
static const struct i2c_device_id cm3323_id[] = {
- {"cm3323", 0},
+ { "cm3323" },
{}
};
MODULE_DEVICE_TABLE(i2c, cm3323_id);
diff --git a/drivers/iio/light/cm36651.c b/drivers/iio/light/cm36651.c
index 97e559acba2b..a4a1505534c0 100644
--- a/drivers/iio/light/cm36651.c
+++ b/drivers/iio/light/cm36651.c
@@ -713,7 +713,7 @@ static void cm36651_remove(struct i2c_client *client)
}
static const struct i2c_device_id cm36651_id[] = {
- { "cm36651", 0 },
+ { "cm36651" },
{ }
};
diff --git a/drivers/iio/light/gp2ap002.c b/drivers/iio/light/gp2ap002.c
index fec10d5e037e..7125e011a38a 100644
--- a/drivers/iio/light/gp2ap002.c
+++ b/drivers/iio/light/gp2ap002.c
@@ -692,8 +692,8 @@ static DEFINE_RUNTIME_DEV_PM_OPS(gp2ap002_dev_pm_ops, gp2ap002_runtime_suspend,
gp2ap002_runtime_resume, NULL);
static const struct i2c_device_id gp2ap002_id_table[] = {
- { "gp2ap002", 0 },
- { },
+ { "gp2ap002" },
+ { }
};
MODULE_DEVICE_TABLE(i2c, gp2ap002_id_table);
diff --git a/drivers/iio/light/gp2ap020a00f.c b/drivers/iio/light/gp2ap020a00f.c
index 9f41724819b6..757383456da6 100644
--- a/drivers/iio/light/gp2ap020a00f.c
+++ b/drivers/iio/light/gp2ap020a00f.c
@@ -237,7 +237,6 @@ enum gp2ap020a00f_thresh_val_id {
};
struct gp2ap020a00f_data {
- const struct gp2ap020a00f_platform_data *pdata;
struct i2c_client *client;
struct mutex lock;
char *buffer;
@@ -1592,7 +1591,7 @@ static void gp2ap020a00f_remove(struct i2c_client *client)
}
static const struct i2c_device_id gp2ap020a00f_id[] = {
- { GP2A_I2C_NAME, 0 },
+ { GP2A_I2C_NAME },
{ }
};
diff --git a/drivers/iio/light/isl29028.c b/drivers/iio/light/isl29028.c
index 5694683389be..95bfb3ffa519 100644
--- a/drivers/iio/light/isl29028.c
+++ b/drivers/iio/light/isl29028.c
@@ -678,8 +678,8 @@ static DEFINE_RUNTIME_DEV_PM_OPS(isl29028_pm_ops, isl29028_suspend,
isl29028_resume, NULL);
static const struct i2c_device_id isl29028_id[] = {
- {"isl29028", 0},
- {"isl29030", 0},
+ { "isl29028" },
+ { "isl29030" },
{}
};
MODULE_DEVICE_TABLE(i2c, isl29028_id);
diff --git a/drivers/iio/light/isl29125.c b/drivers/iio/light/isl29125.c
index f1d3356d3369..59329546df58 100644
--- a/drivers/iio/light/isl29125.c
+++ b/drivers/iio/light/isl29125.c
@@ -327,7 +327,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(isl29125_pm_ops, isl29125_suspend,
isl29125_resume);
static const struct i2c_device_id isl29125_id[] = {
- { "isl29125", 0 },
+ { "isl29125" },
{ }
};
MODULE_DEVICE_TABLE(i2c, isl29125_id);
diff --git a/drivers/iio/light/jsa1212.c b/drivers/iio/light/jsa1212.c
index 869196746045..e7ba934c8e69 100644
--- a/drivers/iio/light/jsa1212.c
+++ b/drivers/iio/light/jsa1212.c
@@ -429,7 +429,7 @@ static const struct acpi_device_id jsa1212_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, jsa1212_acpi_match);
static const struct i2c_device_id jsa1212_id[] = {
- { JSA1212_DRIVER_NAME, 0 },
+ { JSA1212_DRIVER_NAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, jsa1212_id);
diff --git a/drivers/iio/light/lv0104cs.c b/drivers/iio/light/lv0104cs.c
index a5445d58fddf..916109ec3217 100644
--- a/drivers/iio/light/lv0104cs.c
+++ b/drivers/iio/light/lv0104cs.c
@@ -510,7 +510,7 @@ static int lv0104cs_probe(struct i2c_client *client)
}
static const struct i2c_device_id lv0104cs_id[] = {
- { "lv0104cs", 0 },
+ { "lv0104cs" },
{ }
};
MODULE_DEVICE_TABLE(i2c, lv0104cs_id);
diff --git a/drivers/iio/light/max44000.c b/drivers/iio/light/max44000.c
index 26b464b1b650..b935976871a6 100644
--- a/drivers/iio/light/max44000.c
+++ b/drivers/iio/light/max44000.c
@@ -598,7 +598,7 @@ static int max44000_probe(struct i2c_client *client)
}
static const struct i2c_device_id max44000_id[] = {
- {"max44000", 0},
+ { "max44000" },
{ }
};
MODULE_DEVICE_TABLE(i2c, max44000_id);
diff --git a/drivers/iio/light/max44009.c b/drivers/iio/light/max44009.c
index 61ce276e86f7..3b92362675dc 100644
--- a/drivers/iio/light/max44009.c
+++ b/drivers/iio/light/max44009.c
@@ -534,7 +534,7 @@ static const struct of_device_id max44009_of_match[] = {
MODULE_DEVICE_TABLE(of, max44009_of_match);
static const struct i2c_device_id max44009_id[] = {
- { "max44009", 0 },
+ { "max44009" },
{ }
};
MODULE_DEVICE_TABLE(i2c, max44009_id);
diff --git a/drivers/iio/light/noa1305.c b/drivers/iio/light/noa1305.c
index 1574310020e3..596cc48c4c34 100644
--- a/drivers/iio/light/noa1305.c
+++ b/drivers/iio/light/noa1305.c
@@ -268,7 +268,7 @@ static const struct of_device_id noa1305_of_match[] = {
MODULE_DEVICE_TABLE(of, noa1305_of_match);
static const struct i2c_device_id noa1305_ids[] = {
- { "noa1305", 0 },
+ { "noa1305" },
{ }
};
MODULE_DEVICE_TABLE(i2c, noa1305_ids);
diff --git a/drivers/iio/light/opt3001.c b/drivers/iio/light/opt3001.c
index cb41e5ee8ec1..887c4b776a86 100644
--- a/drivers/iio/light/opt3001.c
+++ b/drivers/iio/light/opt3001.c
@@ -822,7 +822,7 @@ static void opt3001_remove(struct i2c_client *client)
}
static const struct i2c_device_id opt3001_id[] = {
- { "opt3001", 0 },
+ { "opt3001" },
{ } /* Terminating Entry */
};
MODULE_DEVICE_TABLE(i2c, opt3001_id);
diff --git a/drivers/iio/light/pa12203001.c b/drivers/iio/light/pa12203001.c
index 636432c45651..b920bf82c102 100644
--- a/drivers/iio/light/pa12203001.c
+++ b/drivers/iio/light/pa12203001.c
@@ -462,7 +462,7 @@ static const struct acpi_device_id pa12203001_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, pa12203001_acpi_match);
static const struct i2c_device_id pa12203001_id[] = {
- { "txcpa122", 0 },
+ { "txcpa122" },
{}
};
diff --git a/drivers/iio/light/rohm-bu27034.c b/drivers/iio/light/rohm-bu27034.c
index bf3de853a811..4937bf6fa046 100644
--- a/drivers/iio/light/rohm-bu27034.c
+++ b/drivers/iio/light/rohm-bu27034.c
@@ -223,12 +223,6 @@ struct bu27034_data {
} scan;
};
-struct bu27034_result {
- u16 ch0;
- u16 ch1;
- u16 ch2;
-};
-
static const struct regmap_range bu27034_volatile_ranges[] = {
{
.range_min = BU27034_REG_SYSTEM_CONTROL,
diff --git a/drivers/iio/light/rpr0521.c b/drivers/iio/light/rpr0521.c
index 40d5732b5e32..78c08e0bd077 100644
--- a/drivers/iio/light/rpr0521.c
+++ b/drivers/iio/light/rpr0521.c
@@ -1109,7 +1109,7 @@ static const struct acpi_device_id rpr0521_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, rpr0521_acpi_match);
static const struct i2c_device_id rpr0521_id[] = {
- {"rpr0521", 0},
+ { "rpr0521" },
{ }
};
diff --git a/drivers/iio/light/si1133.c b/drivers/iio/light/si1133.c
index ea2c437199c0..eeff6cc792f2 100644
--- a/drivers/iio/light/si1133.c
+++ b/drivers/iio/light/si1133.c
@@ -1055,7 +1055,7 @@ static int si1133_probe(struct i2c_client *client)
}
static const struct i2c_device_id si1133_ids[] = {
- { "si1133", 0 },
+ { "si1133" },
{ }
};
MODULE_DEVICE_TABLE(i2c, si1133_ids);
diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c
index 08d471438175..e3470d6743ef 100644
--- a/drivers/iio/light/stk3310.c
+++ b/drivers/iio/light/stk3310.c
@@ -37,6 +37,8 @@
#define STK3310_CHIP_ID_VAL 0x13
#define STK3311_CHIP_ID_VAL 0x1D
+#define STK3311A_CHIP_ID_VAL 0x15
+#define STK3311S34_CHIP_ID_VAL 0x1E
#define STK3311X_CHIP_ID_VAL 0x12
#define STK3335_CHIP_ID_VAL 0x51
#define STK3310_PSINT_EN 0x01
@@ -81,6 +83,15 @@ static const struct reg_field stk3310_reg_field_flag_psint =
static const struct reg_field stk3310_reg_field_flag_nf =
REG_FIELD(STK3310_REG_FLAG, 0, 0);
+static const u8 stk3310_chip_ids[] = {
+ STK3310_CHIP_ID_VAL,
+ STK3311A_CHIP_ID_VAL,
+ STK3311S34_CHIP_ID_VAL,
+ STK3311X_CHIP_ID_VAL,
+ STK3311_CHIP_ID_VAL,
+ STK3335_CHIP_ID_VAL,
+};
+
/* Estimate maximum proximity values with regard to measurement scale. */
static const int stk3310_ps_max[4] = {
STK3310_PS_MAX_VAL / 640,
@@ -197,6 +208,16 @@ static const struct attribute_group stk3310_attribute_group = {
.attrs = stk3310_attributes
};
+static int stk3310_check_chip_id(const u8 chip_id)
+{
+ for (int i = 0; i < ARRAY_SIZE(stk3310_chip_ids); i++) {
+ if (chip_id == stk3310_chip_ids[i])
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
static int stk3310_get_index(const int table[][2], int table_size,
int val, int val2)
{
@@ -473,13 +494,9 @@ static int stk3310_init(struct iio_dev *indio_dev)
if (ret < 0)
return ret;
- if (chipid != STK3310_CHIP_ID_VAL &&
- chipid != STK3311_CHIP_ID_VAL &&
- chipid != STK3311X_CHIP_ID_VAL &&
- chipid != STK3335_CHIP_ID_VAL) {
- dev_err(&client->dev, "invalid chip id: 0x%x\n", chipid);
- return -ENODEV;
- }
+ ret = stk3310_check_chip_id(chipid);
+ if (ret < 0)
+ dev_warn(&client->dev, "unknown chip id: 0x%x\n", chipid);
state = STK3310_STATE_EN_ALS | STK3310_STATE_EN_PS;
ret = stk3310_set_state(data, state);
@@ -683,9 +700,9 @@ static DEFINE_SIMPLE_DEV_PM_OPS(stk3310_pm_ops, stk3310_suspend,
stk3310_resume);
static const struct i2c_device_id stk3310_i2c_id[] = {
- {"STK3310", 0},
- {"STK3311", 0},
- {"STK3335", 0},
+ { "STK3310" },
+ { "STK3311" },
+ { "STK3335" },
{}
};
MODULE_DEVICE_TABLE(i2c, stk3310_i2c_id);
diff --git a/drivers/iio/light/tcs3414.c b/drivers/iio/light/tcs3414.c
index dcdd85b006be..c9566615b964 100644
--- a/drivers/iio/light/tcs3414.c
+++ b/drivers/iio/light/tcs3414.c
@@ -363,7 +363,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(tcs3414_pm_ops, tcs3414_suspend,
tcs3414_resume);
static const struct i2c_device_id tcs3414_id[] = {
- { "tcs3414", 0 },
+ { "tcs3414" },
{ }
};
MODULE_DEVICE_TABLE(i2c, tcs3414_id);
diff --git a/drivers/iio/light/tcs3472.c b/drivers/iio/light/tcs3472.c
index 75fcf2c93717..89384dba83dd 100644
--- a/drivers/iio/light/tcs3472.c
+++ b/drivers/iio/light/tcs3472.c
@@ -599,7 +599,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(tcs3472_pm_ops, tcs3472_suspend,
tcs3472_resume);
static const struct i2c_device_id tcs3472_id[] = {
- { "tcs3472", 0 },
+ { "tcs3472" },
{ }
};
MODULE_DEVICE_TABLE(i2c, tcs3472_id);
diff --git a/drivers/iio/light/tsl4531.c b/drivers/iio/light/tsl4531.c
index 4da7d78906d4..a5788c09ad02 100644
--- a/drivers/iio/light/tsl4531.c
+++ b/drivers/iio/light/tsl4531.c
@@ -227,7 +227,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(tsl4531_pm_ops, tsl4531_suspend,
tsl4531_resume);
static const struct i2c_device_id tsl4531_id[] = {
- { "tsl4531", 0 },
+ { "tsl4531" },
{ }
};
MODULE_DEVICE_TABLE(i2c, tsl4531_id);
diff --git a/drivers/iio/light/us5182d.c b/drivers/iio/light/us5182d.c
index 9189a1d4d7e1..de6967ac3b0b 100644
--- a/drivers/iio/light/us5182d.c
+++ b/drivers/iio/light/us5182d.c
@@ -955,7 +955,7 @@ static const struct acpi_device_id us5182d_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, us5182d_acpi_match);
static const struct i2c_device_id us5182d_id[] = {
- { "usd5182", 0 },
+ { "usd5182" },
{}
};
diff --git a/drivers/iio/light/vcnl4035.c b/drivers/iio/light/vcnl4035.c
index 56bbefbc0ae6..337a1332c2c6 100644
--- a/drivers/iio/light/vcnl4035.c
+++ b/drivers/iio/light/vcnl4035.c
@@ -653,7 +653,7 @@ static DEFINE_RUNTIME_DEV_PM_OPS(vcnl4035_pm_ops, vcnl4035_runtime_suspend,
vcnl4035_runtime_resume, NULL);
static const struct i2c_device_id vcnl4035_id[] = {
- { "vcnl4035", 0 },
+ { "vcnl4035" },
{ }
};
MODULE_DEVICE_TABLE(i2c, vcnl4035_id);
diff --git a/drivers/iio/light/veml6030.c b/drivers/iio/light/veml6030.c
index 043f233d9bdb..4be151308574 100644
--- a/drivers/iio/light/veml6030.c
+++ b/drivers/iio/light/veml6030.c
@@ -881,7 +881,7 @@ static const struct of_device_id veml6030_of_match[] = {
MODULE_DEVICE_TABLE(of, veml6030_of_match);
static const struct i2c_device_id veml6030_id[] = {
- { "veml6030", 0 },
+ { "veml6030" },
{ }
};
MODULE_DEVICE_TABLE(i2c, veml6030_id);
diff --git a/drivers/iio/light/veml6040.c b/drivers/iio/light/veml6040.c
new file mode 100644
index 000000000000..216e271001a8
--- /dev/null
+++ b/drivers/iio/light/veml6040.c
@@ -0,0 +1,281 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Vishay VEML6040 RGBW light sensor driver
+ *
+ * Copyright (C) 2024 Sentec AG
+ * Author: Arthur Becker <arthur.becker@sentec.com>
+ *
+ */
+
+#include <linux/bitfield.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+/* VEML6040 Configuration Registers
+ *
+ * SD: Shutdown
+ * AF: Auto / Force Mode (Auto Measurements On:0, Off:1)
+ * TR: Trigger Measurement (when AF Bit is set)
+ * IT: Integration Time
+ */
+#define VEML6040_CONF_REG 0x000
+#define VEML6040_CONF_SD_MSK BIT(0)
+#define VEML6040_CONF_AF_MSK BIT(1)
+#define VEML6040_CONF_TR_MSK BIT(2)
+#define VEML6040_CONF_IT_MSK GENMASK(6, 4)
+#define VEML6040_CONF_IT_40_MS 0
+#define VEML6040_CONF_IT_80_MS 1
+#define VEML6040_CONF_IT_160_MS 2
+#define VEML6040_CONF_IT_320_MS 3
+#define VEML6040_CONF_IT_640_MS 4
+#define VEML6040_CONF_IT_1280_MS 5
+
+/* VEML6040 Read Only Registers */
+#define VEML6040_REG_R 0x08
+#define VEML6040_REG_G 0x09
+#define VEML6040_REG_B 0x0A
+#define VEML6040_REG_W 0x0B
+
+static const int veml6040_it_ms[] = { 40, 80, 160, 320, 640, 1280 };
+
+enum veml6040_chan {
+ CH_RED,
+ CH_GREEN,
+ CH_BLUE,
+ CH_WHITE,
+};
+
+struct veml6040_data {
+ struct i2c_client *client;
+ struct regmap *regmap;
+};
+
+static const struct regmap_config veml6040_regmap_config = {
+ .name = "veml6040_regmap",
+ .reg_bits = 8,
+ .val_bits = 16,
+ .max_register = VEML6040_REG_W,
+ .val_format_endian = REGMAP_ENDIAN_LITTLE,
+};
+
+static int veml6040_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ int ret, reg, it_index;
+ struct veml6040_data *data = iio_priv(indio_dev);
+ struct regmap *regmap = data->regmap;
+ struct device *dev = &data->client->dev;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = regmap_read(regmap, chan->address, &reg);
+ if (ret) {
+ dev_err(dev, "Data read failed: %d\n", ret);
+ return ret;
+ }
+ *val = reg;
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_INT_TIME:
+ ret = regmap_read(regmap, VEML6040_CONF_REG, &reg);
+ if (ret) {
+ dev_err(dev, "Data read failed: %d\n", ret);
+ return ret;
+ }
+ it_index = FIELD_GET(VEML6040_CONF_IT_MSK, reg);
+ if (it_index >= ARRAY_SIZE(veml6040_it_ms)) {
+ dev_err(dev, "Invalid Integration Time Set");
+ return -EINVAL;
+ }
+ *val = veml6040_it_ms[it_index];
+ return IIO_VAL_INT;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int veml6040_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val,
+ int val2, long mask)
+{
+ struct veml6040_data *data = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_INT_TIME:
+ for (int i = 0; i < ARRAY_SIZE(veml6040_it_ms); i++) {
+ if (veml6040_it_ms[i] != val)
+ continue;
+
+ return regmap_update_bits(data->regmap,
+ VEML6040_CONF_REG,
+ VEML6040_CONF_IT_MSK,
+ FIELD_PREP(VEML6040_CONF_IT_MSK, i));
+ }
+ return -EINVAL;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int veml6040_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long mask)
+{
+ switch (mask) {
+ case IIO_CHAN_INFO_INT_TIME:
+ *length = ARRAY_SIZE(veml6040_it_ms);
+ *vals = veml6040_it_ms;
+ *type = IIO_VAL_INT;
+ return IIO_AVAIL_LIST;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info veml6040_info = {
+ .read_raw = veml6040_read_raw,
+ .write_raw = veml6040_write_raw,
+ .read_avail = veml6040_read_avail,
+};
+
+static const struct iio_chan_spec veml6040_channels[] = {
+ {
+ .type = IIO_INTENSITY,
+ .address = VEML6040_REG_R,
+ .channel = CH_RED,
+ .channel2 = IIO_MOD_LIGHT_RED,
+ .modified = 1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_INT_TIME),
+ .info_mask_shared_by_type_available =
+ BIT(IIO_CHAN_INFO_INT_TIME),
+ },
+ {
+ .type = IIO_INTENSITY,
+ .address = VEML6040_REG_G,
+ .channel = CH_GREEN,
+ .channel2 = IIO_MOD_LIGHT_GREEN,
+ .modified = 1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_INT_TIME),
+ .info_mask_shared_by_type_available =
+ BIT(IIO_CHAN_INFO_INT_TIME),
+ },
+ {
+ .type = IIO_INTENSITY,
+ .address = VEML6040_REG_B,
+ .channel = CH_BLUE,
+ .channel2 = IIO_MOD_LIGHT_BLUE,
+ .modified = 1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_INT_TIME),
+ .info_mask_shared_by_type_available =
+ BIT(IIO_CHAN_INFO_INT_TIME),
+ },
+ {
+ .type = IIO_INTENSITY,
+ .address = VEML6040_REG_W,
+ .channel = CH_WHITE,
+ .channel2 = IIO_MOD_LIGHT_CLEAR,
+ .modified = 1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_INT_TIME),
+ .info_mask_shared_by_type_available =
+ BIT(IIO_CHAN_INFO_INT_TIME),
+ }
+};
+
+static void veml6040_shutdown_action(void *data)
+{
+ struct veml6040_data *veml6040_data = data;
+
+ regmap_update_bits(veml6040_data->regmap, VEML6040_CONF_REG,
+ VEML6040_CONF_SD_MSK, VEML6040_CONF_SD_MSK);
+}
+
+static int veml6040_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct veml6040_data *data;
+ struct iio_dev *indio_dev;
+ struct regmap *regmap;
+ const int init_config =
+ FIELD_PREP(VEML6040_CONF_IT_MSK, VEML6040_CONF_IT_40_MS) |
+ FIELD_PREP(VEML6040_CONF_AF_MSK, 0) |
+ FIELD_PREP(VEML6040_CONF_SD_MSK, 0);
+ int ret;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+ return dev_err_probe(dev, -EOPNOTSUPP,
+ "I2C adapter doesn't support plain I2C\n");
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+ if (!indio_dev)
+ return dev_err_probe(dev, -ENOMEM,
+ "IIO device allocation failed\n");
+
+ regmap = devm_regmap_init_i2c(client, &veml6040_regmap_config);
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap),
+ "Regmap setup failed\n");
+
+ data = iio_priv(indio_dev);
+ i2c_set_clientdata(client, indio_dev);
+ data->client = client;
+ data->regmap = regmap;
+
+ indio_dev->name = "veml6040";
+ indio_dev->info = &veml6040_info;
+ indio_dev->channels = veml6040_channels;
+ indio_dev->num_channels = ARRAY_SIZE(veml6040_channels);
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = devm_regulator_get_enable(dev, "vdd");
+ if (ret)
+ return ret;
+
+ ret = regmap_write(regmap, VEML6040_CONF_REG, init_config);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Could not set initial config\n");
+
+ ret = devm_add_action_or_reset(dev, veml6040_shutdown_action, data);
+ if (ret)
+ return ret;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct i2c_device_id veml6040_id_table[] = {
+ {"veml6040"},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, veml6040_id_table);
+
+static const struct of_device_id veml6040_of_match[] = {
+ {.compatible = "vishay,veml6040"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, veml6040_of_match);
+
+static struct i2c_driver veml6040_driver = {
+ .probe = veml6040_probe,
+ .id_table = veml6040_id_table,
+ .driver = {
+ .name = "veml6040",
+ .of_match_table = veml6040_of_match,
+ },
+};
+module_i2c_driver(veml6040_driver);
+
+MODULE_DESCRIPTION("veml6040 RGBW light sensor driver");
+MODULE_AUTHOR("Arthur Becker <arthur.becker@sentec.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/light/veml6070.c b/drivers/iio/light/veml6070.c
index d99bf3ae0fe8..f8321d346d77 100644
--- a/drivers/iio/light/veml6070.c
+++ b/drivers/iio/light/veml6070.c
@@ -189,7 +189,7 @@ static void veml6070_remove(struct i2c_client *client)
}
static const struct i2c_device_id veml6070_id[] = {
- { "veml6070", 0 },
+ { "veml6070" },
{ }
};
MODULE_DEVICE_TABLE(i2c, veml6070_id);
diff --git a/drivers/iio/light/vl6180.c b/drivers/iio/light/vl6180.c
index dcadf6428a87..a1b2b3c0b4c8 100644
--- a/drivers/iio/light/vl6180.c
+++ b/drivers/iio/light/vl6180.c
@@ -527,7 +527,7 @@ static const struct of_device_id vl6180_of_match[] = {
MODULE_DEVICE_TABLE(of, vl6180_of_match);
static const struct i2c_device_id vl6180_id[] = {
- { "vl6180", 0 },
+ { "vl6180" },
{ }
};
MODULE_DEVICE_TABLE(i2c, vl6180_id);
diff --git a/drivers/iio/light/zopt2201.c b/drivers/iio/light/zopt2201.c
index d370193a4742..327f94e447af 100644
--- a/drivers/iio/light/zopt2201.c
+++ b/drivers/iio/light/zopt2201.c
@@ -545,7 +545,7 @@ static int zopt2201_probe(struct i2c_client *client)
}
static const struct i2c_device_id zopt2201_id[] = {
- { "zopt2201", 0 },
+ { "zopt2201" },
{ }
};
MODULE_DEVICE_TABLE(i2c, zopt2201_id);
diff --git a/drivers/iio/magnetometer/af8133j.c b/drivers/iio/magnetometer/af8133j.c
index 742bbdf25f08..d81d89af6283 100644
--- a/drivers/iio/magnetometer/af8133j.c
+++ b/drivers/iio/magnetometer/af8133j.c
@@ -505,7 +505,7 @@ static const struct of_device_id af8133j_of_match[] = {
MODULE_DEVICE_TABLE(of, af8133j_of_match);
static const struct i2c_device_id af8133j_id[] = {
- { "af8133j", 0 },
+ { "af8133j" },
{ }
};
MODULE_DEVICE_TABLE(i2c, af8133j_id);
diff --git a/drivers/iio/magnetometer/ak8974.c b/drivers/iio/magnetometer/ak8974.c
index c74d11943ec7..d802034c5402 100644
--- a/drivers/iio/magnetometer/ak8974.c
+++ b/drivers/iio/magnetometer/ak8974.c
@@ -1025,10 +1025,10 @@ static DEFINE_RUNTIME_DEV_PM_OPS(ak8974_dev_pm_ops, ak8974_runtime_suspend,
ak8974_runtime_resume, NULL);
static const struct i2c_device_id ak8974_id[] = {
- {"ami305", 0 },
- {"ami306", 0 },
- {"ak8974", 0 },
- {"hscdtd008a", 0 },
+ { "ami305" },
+ { "ami306" },
+ { "ak8974" },
+ { "hscdtd008a" },
{}
};
MODULE_DEVICE_TABLE(i2c, ak8974_id);
diff --git a/drivers/iio/magnetometer/bmc150_magn_i2c.c b/drivers/iio/magnetometer/bmc150_magn_i2c.c
index 48d9c698f520..a28d46d59875 100644
--- a/drivers/iio/magnetometer/bmc150_magn_i2c.c
+++ b/drivers/iio/magnetometer/bmc150_magn_i2c.c
@@ -47,9 +47,9 @@ static const struct acpi_device_id bmc150_magn_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, bmc150_magn_acpi_match);
static const struct i2c_device_id bmc150_magn_i2c_id[] = {
- {"bmc150_magn", 0},
- {"bmc156_magn", 0},
- {"bmm150_magn", 0},
+ { "bmc150_magn" },
+ { "bmc156_magn" },
+ { "bmm150_magn" },
{}
};
MODULE_DEVICE_TABLE(i2c, bmc150_magn_i2c_id);
diff --git a/drivers/iio/magnetometer/mag3110.c b/drivers/iio/magnetometer/mag3110.c
index deffe3ca9004..5295dc0100e4 100644
--- a/drivers/iio/magnetometer/mag3110.c
+++ b/drivers/iio/magnetometer/mag3110.c
@@ -624,7 +624,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(mag3110_pm_ops, mag3110_suspend,
mag3110_resume);
static const struct i2c_device_id mag3110_id[] = {
- { "mag3110", 0 },
+ { "mag3110" },
{ }
};
MODULE_DEVICE_TABLE(i2c, mag3110_id);
diff --git a/drivers/iio/magnetometer/mmc35240.c b/drivers/iio/magnetometer/mmc35240.c
index 6b9f4b056191..c57932db455f 100644
--- a/drivers/iio/magnetometer/mmc35240.c
+++ b/drivers/iio/magnetometer/mmc35240.c
@@ -563,7 +563,7 @@ static const struct acpi_device_id mmc35240_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, mmc35240_acpi_match);
static const struct i2c_device_id mmc35240_id[] = {
- {"mmc35240", 0},
+ { "mmc35240" },
{}
};
MODULE_DEVICE_TABLE(i2c, mmc35240_id);
diff --git a/drivers/iio/magnetometer/tmag5273.c b/drivers/iio/magnetometer/tmag5273.c
index 218b1ce076c1..4187abe12784 100644
--- a/drivers/iio/magnetometer/tmag5273.c
+++ b/drivers/iio/magnetometer/tmag5273.c
@@ -118,11 +118,9 @@ struct tmag5273_data {
unsigned int version;
char name[16];
unsigned int conv_avg;
- unsigned int scale;
enum tmag5273_scale_index scale_index;
unsigned int angle_measurement;
struct regmap *map;
- struct regulator *vcc;
/*
* Locks the sensor for exclusive use during a measurement (which
diff --git a/drivers/iio/multiplexer/iio-mux.c b/drivers/iio/multiplexer/iio-mux.c
index edd8c69f6d2e..2953403bef53 100644
--- a/drivers/iio/multiplexer/iio-mux.c
+++ b/drivers/iio/multiplexer/iio-mux.c
@@ -30,7 +30,6 @@ struct mux {
int cached_state;
struct mux_control *control;
struct iio_channel *parent;
- struct iio_dev *indio_dev;
struct iio_chan_spec *chan;
struct iio_chan_spec_ext_info *ext_info;
struct mux_child *child;
diff --git a/drivers/iio/potentiostat/lmp91000.c b/drivers/iio/potentiostat/lmp91000.c
index bd0f2c3bf2f2..c2c6b2b29867 100644
--- a/drivers/iio/potentiostat/lmp91000.c
+++ b/drivers/iio/potentiostat/lmp91000.c
@@ -405,8 +405,8 @@ static const struct of_device_id lmp91000_of_match[] = {
MODULE_DEVICE_TABLE(of, lmp91000_of_match);
static const struct i2c_device_id lmp91000_id[] = {
- { "lmp91000", 0 },
- { "lmp91002", 0 },
+ { "lmp91000" },
+ { "lmp91002" },
{}
};
MODULE_DEVICE_TABLE(i2c, lmp91000_id);
diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
index 221fa2c552ae..50d71ad83f37 100644
--- a/drivers/iio/pressure/bmp280-core.c
+++ b/drivers/iio/pressure/bmp280-core.c
@@ -27,6 +27,7 @@
#include <linux/bitops.h>
#include <linux/bitfield.h>
+#include <linux/cleanup.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/device.h>
@@ -52,7 +53,6 @@
*/
enum { AC1, AC2, AC3, AC4, AC5, AC6, B1, B2, MB, MC, MD };
-
enum bmp380_odr {
BMP380_ODR_200HZ,
BMP380_ODR_100HZ,
@@ -181,18 +181,19 @@ static int bmp280_read_calib(struct bmp280_data *data)
struct bmp280_calib *calib = &data->calib.bmp280;
int ret;
-
/* Read temperature and pressure calibration values. */
ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_TEMP_START,
- data->bmp280_cal_buf, sizeof(data->bmp280_cal_buf));
- if (ret < 0) {
+ data->bmp280_cal_buf,
+ sizeof(data->bmp280_cal_buf));
+ if (ret) {
dev_err(data->dev,
- "failed to read temperature and pressure calibration parameters\n");
+ "failed to read calibration parameters\n");
return ret;
}
- /* Toss the temperature and pressure calibration data into the entropy pool */
- add_device_randomness(data->bmp280_cal_buf, sizeof(data->bmp280_cal_buf));
+ /* Toss calibration data into the entropy pool */
+ add_device_randomness(data->bmp280_cal_buf,
+ sizeof(data->bmp280_cal_buf));
/* Parse temperature calibration values. */
calib->T1 = le16_to_cpu(data->bmp280_cal_buf[T1]);
@@ -222,10 +223,8 @@ static int bme280_read_calib(struct bmp280_data *data)
/* Load shared calibration params with bmp280 first */
ret = bmp280_read_calib(data);
- if (ret < 0) {
- dev_err(dev, "failed to read common bmp280 calibration parameters\n");
+ if (ret)
return ret;
- }
/*
* Read humidity calibration values.
@@ -235,47 +234,47 @@ static int bme280_read_calib(struct bmp280_data *data)
* Humidity data is only available on BME280.
*/
- ret = regmap_read(data->regmap, BMP280_REG_COMP_H1, &tmp);
- if (ret < 0) {
+ ret = regmap_read(data->regmap, BME280_REG_COMP_H1, &tmp);
+ if (ret) {
dev_err(dev, "failed to read H1 comp value\n");
return ret;
}
calib->H1 = tmp;
- ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_H2,
+ ret = regmap_bulk_read(data->regmap, BME280_REG_COMP_H2,
&data->le16, sizeof(data->le16));
- if (ret < 0) {
+ if (ret) {
dev_err(dev, "failed to read H2 comp value\n");
return ret;
}
calib->H2 = sign_extend32(le16_to_cpu(data->le16), 15);
- ret = regmap_read(data->regmap, BMP280_REG_COMP_H3, &tmp);
- if (ret < 0) {
+ ret = regmap_read(data->regmap, BME280_REG_COMP_H3, &tmp);
+ if (ret) {
dev_err(dev, "failed to read H3 comp value\n");
return ret;
}
calib->H3 = tmp;
- ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_H4,
+ ret = regmap_bulk_read(data->regmap, BME280_REG_COMP_H4,
&data->be16, sizeof(data->be16));
- if (ret < 0) {
+ if (ret) {
dev_err(dev, "failed to read H4 comp value\n");
return ret;
}
calib->H4 = sign_extend32(((be16_to_cpu(data->be16) >> 4) & 0xff0) |
(be16_to_cpu(data->be16) & 0xf), 11);
- ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_H5,
+ ret = regmap_bulk_read(data->regmap, BME280_REG_COMP_H5,
&data->le16, sizeof(data->le16));
- if (ret < 0) {
+ if (ret) {
dev_err(dev, "failed to read H5 comp value\n");
return ret;
}
- calib->H5 = sign_extend32(FIELD_GET(BMP280_COMP_H5_MASK, le16_to_cpu(data->le16)), 11);
+ calib->H5 = sign_extend32(FIELD_GET(BME280_COMP_H5_MASK, le16_to_cpu(data->le16)), 11);
- ret = regmap_read(data->regmap, BMP280_REG_COMP_H6, &tmp);
- if (ret < 0) {
+ ret = regmap_read(data->regmap, BME280_REG_COMP_H6, &tmp);
+ if (ret) {
dev_err(dev, "failed to read H6 comp value\n");
return ret;
}
@@ -283,20 +282,43 @@ static int bme280_read_calib(struct bmp280_data *data)
return 0;
}
+
+static int bme280_read_humid_adc(struct bmp280_data *data, u16 *adc_humidity)
+{
+ u16 value_humidity;
+ int ret;
+
+ ret = regmap_bulk_read(data->regmap, BME280_REG_HUMIDITY_MSB,
+ &data->be16, sizeof(data->be16));
+ if (ret) {
+ dev_err(data->dev, "failed to read humidity\n");
+ return ret;
+ }
+
+ value_humidity = be16_to_cpu(data->be16);
+ if (value_humidity == BMP280_HUMIDITY_SKIPPED) {
+ dev_err(data->dev, "reading humidity skipped\n");
+ return -EIO;
+ }
+ *adc_humidity = value_humidity;
+
+ return 0;
+}
+
/*
* Returns humidity in percent, resolution is 0.01 percent. Output value of
* "47445" represents 47445/1024 = 46.333 %RH.
*
* Taken from BME280 datasheet, Section 4.2.3, "Compensation formula".
*/
-static u32 bmp280_compensate_humidity(struct bmp280_data *data,
- s32 adc_humidity)
+static u32 bme280_compensate_humidity(struct bmp280_data *data,
+ u16 adc_humidity, s32 t_fine)
{
struct bmp280_calib *calib = &data->calib.bmp280;
s32 var;
- var = ((s32)data->t_fine) - (s32)76800;
- var = ((((adc_humidity << 14) - (calib->H4 << 20) - (calib->H5 * var))
+ var = t_fine - (s32)76800;
+ var = (((((s32)adc_humidity << 14) - (calib->H4 << 20) - (calib->H5 * var))
+ (s32)16384) >> 15) * (((((((var * calib->H6) >> 10)
* (((var * (s32)calib->H3) >> 11) + (s32)32768)) >> 10)
+ (s32)2097152) * calib->H2 + 8192) >> 14);
@@ -305,7 +327,29 @@ static u32 bmp280_compensate_humidity(struct bmp280_data *data,
var = clamp_val(var, 0, 419430400);
return var >> 12;
-};
+}
+
+static int bmp280_read_temp_adc(struct bmp280_data *data, u32 *adc_temp)
+{
+ u32 value_temp;
+ int ret;
+
+ ret = regmap_bulk_read(data->regmap, BMP280_REG_TEMP_MSB,
+ data->buf, sizeof(data->buf));
+ if (ret) {
+ dev_err(data->dev, "failed to read temperature\n");
+ return ret;
+ }
+
+ value_temp = FIELD_GET(BMP280_MEAS_TRIM_MASK, get_unaligned_be24(data->buf));
+ if (value_temp == BMP280_TEMP_SKIPPED) {
+ dev_err(data->dev, "reading temperature skipped\n");
+ return -EIO;
+ }
+ *adc_temp = value_temp;
+
+ return 0;
+}
/*
* Returns temperature in DegC, resolution is 0.01 DegC. Output value of
@@ -314,20 +358,58 @@ static u32 bmp280_compensate_humidity(struct bmp280_data *data,
*
* Taken from datasheet, Section 3.11.3, "Compensation formula".
*/
-static s32 bmp280_compensate_temp(struct bmp280_data *data,
- s32 adc_temp)
+static s32 bmp280_calc_t_fine(struct bmp280_data *data, u32 adc_temp)
{
struct bmp280_calib *calib = &data->calib.bmp280;
s32 var1, var2;
- var1 = (((adc_temp >> 3) - ((s32)calib->T1 << 1)) *
+ var1 = (((((s32)adc_temp) >> 3) - ((s32)calib->T1 << 1)) *
((s32)calib->T2)) >> 11;
- var2 = (((((adc_temp >> 4) - ((s32)calib->T1)) *
- ((adc_temp >> 4) - ((s32)calib->T1))) >> 12) *
- ((s32)calib->T3)) >> 14;
- data->t_fine = var1 + var2;
+ var2 = (((((((s32)adc_temp) >> 4) - ((s32)calib->T1)) *
+ ((((s32)adc_temp >> 4) - ((s32)calib->T1))) >> 12) *
+ ((s32)calib->T3))) >> 14;
+ return var1 + var2; /* t_fine = var1 + var2 */
+}
+
+static int bmp280_get_t_fine(struct bmp280_data *data, s32 *t_fine)
+{
+ u32 adc_temp;
+ int ret;
+
+ ret = bmp280_read_temp_adc(data, &adc_temp);
+ if (ret)
+ return ret;
+
+ *t_fine = bmp280_calc_t_fine(data, adc_temp);
+
+ return 0;
+}
+
+static s32 bmp280_compensate_temp(struct bmp280_data *data, u32 adc_temp)
+{
+ return (bmp280_calc_t_fine(data, adc_temp) * 5 + 128) / 256;
+}
+
+static int bmp280_read_press_adc(struct bmp280_data *data, u32 *adc_press)
+{
+ u32 value_press;
+ int ret;
- return (data->t_fine * 5 + 128) >> 8;
+ ret = regmap_bulk_read(data->regmap, BMP280_REG_PRESS_MSB,
+ data->buf, sizeof(data->buf));
+ if (ret) {
+ dev_err(data->dev, "failed to read pressure\n");
+ return ret;
+ }
+
+ value_press = FIELD_GET(BMP280_MEAS_TRIM_MASK, get_unaligned_be24(data->buf));
+ if (value_press == BMP280_PRESS_SKIPPED) {
+ dev_err(data->dev, "reading pressure skipped\n");
+ return -EIO;
+ }
+ *adc_press = value_press;
+
+ return 0;
}
/*
@@ -338,12 +420,12 @@ static s32 bmp280_compensate_temp(struct bmp280_data *data,
* Taken from datasheet, Section 3.11.3, "Compensation formula".
*/
static u32 bmp280_compensate_press(struct bmp280_data *data,
- s32 adc_press)
+ u32 adc_press, s32 t_fine)
{
struct bmp280_calib *calib = &data->calib.bmp280;
s64 var1, var2, p;
- var1 = ((s64)data->t_fine) - 128000;
+ var1 = ((s64)t_fine) - 128000;
var2 = var1 * var1 * (s64)calib->P6;
var2 += (var1 * (s64)calib->P5) << 17;
var2 += ((s64)calib->P4) << 35;
@@ -354,7 +436,7 @@ static u32 bmp280_compensate_press(struct bmp280_data *data,
if (var1 == 0)
return 0;
- p = ((((s64)1048576 - adc_press) << 31) - var2) * 3125;
+ p = ((((s64)1048576 - (s32)adc_press) << 31) - var2) * 3125;
p = div64_s64(p, var1);
var1 = (((s64)calib->P9) * (p >> 13) * (p >> 13)) >> 25;
var2 = ((s64)(calib->P8) * p) >> 19;
@@ -366,62 +448,35 @@ static u32 bmp280_compensate_press(struct bmp280_data *data,
static int bmp280_read_temp(struct bmp280_data *data,
int *val, int *val2)
{
- s32 adc_temp, comp_temp;
+ s32 comp_temp;
+ u32 adc_temp;
int ret;
- ret = regmap_bulk_read(data->regmap, BMP280_REG_TEMP_MSB,
- data->buf, sizeof(data->buf));
- if (ret < 0) {
- dev_err(data->dev, "failed to read temperature\n");
+ ret = bmp280_read_temp_adc(data, &adc_temp);
+ if (ret)
return ret;
- }
- adc_temp = FIELD_GET(BMP280_MEAS_TRIM_MASK, get_unaligned_be24(data->buf));
- if (adc_temp == BMP280_TEMP_SKIPPED) {
- /* reading was skipped */
- dev_err(data->dev, "reading temperature skipped\n");
- return -EIO;
- }
comp_temp = bmp280_compensate_temp(data, adc_temp);
- /*
- * val might be NULL if we're called by the read_press routine,
- * who only cares about the carry over t_fine value.
- */
- if (val) {
- *val = comp_temp * 10;
- return IIO_VAL_INT;
- }
-
- return 0;
+ *val = comp_temp * 10;
+ return IIO_VAL_INT;
}
static int bmp280_read_press(struct bmp280_data *data,
int *val, int *val2)
{
- u32 comp_press;
- s32 adc_press;
+ u32 comp_press, adc_press, t_fine;
int ret;
- /* Read and compensate temperature so we get a reading of t_fine. */
- ret = bmp280_read_temp(data, NULL, NULL);
- if (ret < 0)
+ ret = bmp280_get_t_fine(data, &t_fine);
+ if (ret)
return ret;
- ret = regmap_bulk_read(data->regmap, BMP280_REG_PRESS_MSB,
- data->buf, sizeof(data->buf));
- if (ret < 0) {
- dev_err(data->dev, "failed to read pressure\n");
+ ret = bmp280_read_press_adc(data, &adc_press);
+ if (ret)
return ret;
- }
- adc_press = FIELD_GET(BMP280_MEAS_TRIM_MASK, get_unaligned_be24(data->buf));
- if (adc_press == BMP280_PRESS_SKIPPED) {
- /* reading was skipped */
- dev_err(data->dev, "reading pressure skipped\n");
- return -EIO;
- }
- comp_press = bmp280_compensate_press(data, adc_press);
+ comp_press = bmp280_compensate_press(data, adc_press, t_fine);
*val = comp_press;
*val2 = 256000;
@@ -429,116 +484,97 @@ static int bmp280_read_press(struct bmp280_data *data,
return IIO_VAL_FRACTIONAL;
}
-static int bmp280_read_humid(struct bmp280_data *data, int *val, int *val2)
+static int bme280_read_humid(struct bmp280_data *data, int *val, int *val2)
{
u32 comp_humidity;
- s32 adc_humidity;
+ u16 adc_humidity;
+ s32 t_fine;
int ret;
- /* Read and compensate temperature so we get a reading of t_fine. */
- ret = bmp280_read_temp(data, NULL, NULL);
- if (ret < 0)
+ ret = bmp280_get_t_fine(data, &t_fine);
+ if (ret)
return ret;
- ret = regmap_bulk_read(data->regmap, BMP280_REG_HUMIDITY_MSB,
- &data->be16, sizeof(data->be16));
- if (ret < 0) {
- dev_err(data->dev, "failed to read humidity\n");
+ ret = bme280_read_humid_adc(data, &adc_humidity);
+ if (ret)
return ret;
- }
- adc_humidity = be16_to_cpu(data->be16);
- if (adc_humidity == BMP280_HUMIDITY_SKIPPED) {
- /* reading was skipped */
- dev_err(data->dev, "reading humidity skipped\n");
- return -EIO;
- }
- comp_humidity = bmp280_compensate_humidity(data, adc_humidity);
+ comp_humidity = bme280_compensate_humidity(data, adc_humidity, t_fine);
*val = comp_humidity * 1000 / 1024;
return IIO_VAL_INT;
}
-static int bmp280_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int *val, int *val2, long mask)
+static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
{
struct bmp280_data *data = iio_priv(indio_dev);
- int ret;
- pm_runtime_get_sync(data->dev);
- mutex_lock(&data->lock);
+ guard(mutex)(&data->lock);
switch (mask) {
case IIO_CHAN_INFO_PROCESSED:
switch (chan->type) {
case IIO_HUMIDITYRELATIVE:
- ret = data->chip_info->read_humid(data, val, val2);
- break;
+ return data->chip_info->read_humid(data, val, val2);
case IIO_PRESSURE:
- ret = data->chip_info->read_press(data, val, val2);
- break;
+ return data->chip_info->read_press(data, val, val2);
case IIO_TEMP:
- ret = data->chip_info->read_temp(data, val, val2);
- break;
+ return data->chip_info->read_temp(data, val, val2);
default:
- ret = -EINVAL;
- break;
+ return -EINVAL;
}
- break;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
switch (chan->type) {
case IIO_HUMIDITYRELATIVE:
*val = 1 << data->oversampling_humid;
- ret = IIO_VAL_INT;
- break;
+ return IIO_VAL_INT;
case IIO_PRESSURE:
*val = 1 << data->oversampling_press;
- ret = IIO_VAL_INT;
- break;
+ return IIO_VAL_INT;
case IIO_TEMP:
*val = 1 << data->oversampling_temp;
- ret = IIO_VAL_INT;
- break;
+ return IIO_VAL_INT;
default:
- ret = -EINVAL;
- break;
+ return -EINVAL;
}
- break;
case IIO_CHAN_INFO_SAMP_FREQ:
- if (!data->chip_info->sampling_freq_avail) {
- ret = -EINVAL;
- break;
- }
+ if (!data->chip_info->sampling_freq_avail)
+ return -EINVAL;
*val = data->chip_info->sampling_freq_avail[data->sampling_freq][0];
*val2 = data->chip_info->sampling_freq_avail[data->sampling_freq][1];
- ret = IIO_VAL_INT_PLUS_MICRO;
- break;
+ return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
- if (!data->chip_info->iir_filter_coeffs_avail) {
- ret = -EINVAL;
- break;
- }
+ if (!data->chip_info->iir_filter_coeffs_avail)
+ return -EINVAL;
*val = (1 << data->iir_filter_coeff) - 1;
- ret = IIO_VAL_INT;
- break;
+ return IIO_VAL_INT;
default:
- ret = -EINVAL;
- break;
+ return -EINVAL;
}
+}
- mutex_unlock(&data->lock);
+static int bmp280_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct bmp280_data *data = iio_priv(indio_dev);
+ int ret;
+
+ pm_runtime_get_sync(data->dev);
+ ret = bmp280_read_raw_impl(indio_dev, chan, val, val2, mask);
pm_runtime_mark_last_busy(data->dev);
pm_runtime_put_autosuspend(data->dev);
return ret;
}
-static int bmp280_write_oversampling_ratio_humid(struct bmp280_data *data,
- int val)
+static int bme280_write_oversampling_ratio_humid(struct bmp280_data *data,
+ int val)
{
const int *avail = data->chip_info->oversampling_humid_avail;
const int n = data->chip_info->num_oversampling_humid_avail;
@@ -563,7 +599,7 @@ static int bmp280_write_oversampling_ratio_humid(struct bmp280_data *data,
}
static int bmp280_write_oversampling_ratio_temp(struct bmp280_data *data,
- int val)
+ int val)
{
const int *avail = data->chip_info->oversampling_temp_avail;
const int n = data->chip_info->num_oversampling_temp_avail;
@@ -588,7 +624,7 @@ static int bmp280_write_oversampling_ratio_temp(struct bmp280_data *data,
}
static int bmp280_write_oversampling_ratio_press(struct bmp280_data *data,
- int val)
+ int val)
{
const int *avail = data->chip_info->oversampling_press_avail;
const int n = data->chip_info->num_oversampling_press_avail;
@@ -662,12 +698,13 @@ static int bmp280_write_iir_filter_coeffs(struct bmp280_data *data, int val)
return -EINVAL;
}
-static int bmp280_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int val, int val2, long mask)
+static int bmp280_write_raw_impl(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
{
struct bmp280_data *data = iio_priv(indio_dev);
- int ret = 0;
+
+ guard(mutex)(&data->lock);
/*
* Helper functions to update sensor running configuration.
@@ -677,45 +714,36 @@ static int bmp280_write_raw(struct iio_dev *indio_dev,
*/
switch (mask) {
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
- pm_runtime_get_sync(data->dev);
- mutex_lock(&data->lock);
switch (chan->type) {
case IIO_HUMIDITYRELATIVE:
- ret = bmp280_write_oversampling_ratio_humid(data, val);
- break;
+ return bme280_write_oversampling_ratio_humid(data, val);
case IIO_PRESSURE:
- ret = bmp280_write_oversampling_ratio_press(data, val);
- break;
+ return bmp280_write_oversampling_ratio_press(data, val);
case IIO_TEMP:
- ret = bmp280_write_oversampling_ratio_temp(data, val);
- break;
+ return bmp280_write_oversampling_ratio_temp(data, val);
default:
- ret = -EINVAL;
- break;
+ return -EINVAL;
}
- mutex_unlock(&data->lock);
- pm_runtime_mark_last_busy(data->dev);
- pm_runtime_put_autosuspend(data->dev);
- break;
case IIO_CHAN_INFO_SAMP_FREQ:
- pm_runtime_get_sync(data->dev);
- mutex_lock(&data->lock);
- ret = bmp280_write_sampling_frequency(data, val, val2);
- mutex_unlock(&data->lock);
- pm_runtime_mark_last_busy(data->dev);
- pm_runtime_put_autosuspend(data->dev);
- break;
+ return bmp280_write_sampling_frequency(data, val, val2);
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
- pm_runtime_get_sync(data->dev);
- mutex_lock(&data->lock);
- ret = bmp280_write_iir_filter_coeffs(data, val);
- mutex_unlock(&data->lock);
- pm_runtime_mark_last_busy(data->dev);
- pm_runtime_put_autosuspend(data->dev);
- break;
+ return bmp280_write_iir_filter_coeffs(data, val);
default:
return -EINVAL;
}
+}
+
+static int bmp280_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct bmp280_data *data = iio_priv(indio_dev);
+ int ret;
+
+ pm_runtime_get_sync(data->dev);
+ ret = bmp280_write_raw_impl(indio_dev, chan, val, val2, mask);
+ pm_runtime_mark_last_busy(data->dev);
+ pm_runtime_put_autosuspend(data->dev);
return ret;
}
@@ -772,22 +800,20 @@ static int bmp280_chip_config(struct bmp280_data *data)
int ret;
ret = regmap_write_bits(data->regmap, BMP280_REG_CTRL_MEAS,
- BMP280_OSRS_TEMP_MASK |
- BMP280_OSRS_PRESS_MASK |
- BMP280_MODE_MASK,
- osrs | BMP280_MODE_NORMAL);
- if (ret < 0) {
- dev_err(data->dev,
- "failed to write ctrl_meas register\n");
+ BMP280_OSRS_TEMP_MASK |
+ BMP280_OSRS_PRESS_MASK |
+ BMP280_MODE_MASK,
+ osrs | BMP280_MODE_NORMAL);
+ if (ret) {
+ dev_err(data->dev, "failed to write ctrl_meas register\n");
return ret;
}
ret = regmap_update_bits(data->regmap, BMP280_REG_CONFIG,
BMP280_FILTER_MASK,
BMP280_FILTER_4X);
- if (ret < 0) {
- dev_err(data->dev,
- "failed to write config register\n");
+ if (ret) {
+ dev_err(data->dev, "failed to write config register\n");
return ret;
}
@@ -833,18 +859,19 @@ EXPORT_SYMBOL_NS(bmp280_chip_info, IIO_BMP280);
static int bme280_chip_config(struct bmp280_data *data)
{
- u8 osrs = FIELD_PREP(BMP280_OSRS_HUMIDITY_MASK, data->oversampling_humid + 1);
+ u8 osrs = FIELD_PREP(BME280_OSRS_HUMIDITY_MASK, data->oversampling_humid + 1);
int ret;
/*
* Oversampling of humidity must be set before oversampling of
* temperature/pressure is set to become effective.
*/
- ret = regmap_update_bits(data->regmap, BMP280_REG_CTRL_HUMIDITY,
- BMP280_OSRS_HUMIDITY_MASK, osrs);
-
- if (ret < 0)
+ ret = regmap_update_bits(data->regmap, BME280_REG_CTRL_HUMIDITY,
+ BME280_OSRS_HUMIDITY_MASK, osrs);
+ if (ret) {
+ dev_err(data->dev, "failed to set humidity oversampling");
return ret;
+ }
return bmp280_chip_config(data);
}
@@ -870,12 +897,12 @@ const struct bmp280_chip_info bme280_chip_info = {
.oversampling_humid_avail = bmp280_oversampling_avail,
.num_oversampling_humid_avail = ARRAY_SIZE(bmp280_oversampling_avail),
- .oversampling_humid_default = BMP280_OSRS_HUMIDITY_16X - 1,
+ .oversampling_humid_default = BME280_OSRS_HUMIDITY_16X - 1,
.chip_config = bme280_chip_config,
.read_temp = bmp280_read_temp,
.read_press = bmp280_read_press,
- .read_humid = bmp280_read_humid,
+ .read_humid = bme280_read_humid,
.read_calib = bme280_read_calib,
};
EXPORT_SYMBOL_NS(bme280_chip_info, IIO_BMP280);
@@ -925,16 +952,38 @@ static int bmp380_cmd(struct bmp280_data *data, u8 cmd)
return 0;
}
+static int bmp380_read_temp_adc(struct bmp280_data *data, u32 *adc_temp)
+{
+ u32 value_temp;
+ int ret;
+
+ ret = regmap_bulk_read(data->regmap, BMP380_REG_TEMP_XLSB,
+ data->buf, sizeof(data->buf));
+ if (ret) {
+ dev_err(data->dev, "failed to read temperature\n");
+ return ret;
+ }
+
+ value_temp = get_unaligned_le24(data->buf);
+ if (value_temp == BMP380_TEMP_SKIPPED) {
+ dev_err(data->dev, "reading temperature skipped\n");
+ return -EIO;
+ }
+ *adc_temp = value_temp;
+
+ return 0;
+}
+
/*
- * Returns temperature in Celsius degrees, resolution is 0.01º C. Output value of
- * "5123" equals 51.2º C. t_fine carries fine temperature as global value.
+ * Returns temperature in Celsius degrees, resolution is 0.01º C. Output value
+ * of "5123" equals 51.2º C. t_fine carries fine temperature as global value.
*
* Taken from datasheet, Section Appendix 9, "Compensation formula" and repo
* https://github.com/BoschSensortec/BMP3-Sensor-API.
*/
-static s32 bmp380_compensate_temp(struct bmp280_data *data, u32 adc_temp)
+static s32 bmp380_calc_t_fine(struct bmp280_data *data, u32 adc_temp)
{
- s64 var1, var2, var3, var4, var5, var6, comp_temp;
+ s64 var1, var2, var3, var4, var5, var6;
struct bmp380_calib *calib = &data->calib.bmp380;
var1 = ((s64) adc_temp) - (((s64) calib->T1) << 8);
@@ -943,13 +992,57 @@ static s32 bmp380_compensate_temp(struct bmp280_data *data, u32 adc_temp)
var4 = var3 * ((s64) calib->T3);
var5 = (var2 << 18) + var4;
var6 = var5 >> 32;
- data->t_fine = (s32) var6;
+ return (s32)var6; /* t_fine = var6 */
+}
+
+static int bmp380_get_t_fine(struct bmp280_data *data, s32 *t_fine)
+{
+ s32 adc_temp;
+ int ret;
+
+ ret = bmp380_read_temp_adc(data, &adc_temp);
+ if (ret)
+ return ret;
+
+ *t_fine = bmp380_calc_t_fine(data, adc_temp);
+
+ return 0;
+}
+
+static int bmp380_compensate_temp(struct bmp280_data *data, u32 adc_temp)
+{
+ s64 comp_temp;
+ s32 var6;
+
+ var6 = bmp380_calc_t_fine(data, adc_temp);
comp_temp = (var6 * 25) >> 14;
comp_temp = clamp_val(comp_temp, BMP380_MIN_TEMP, BMP380_MAX_TEMP);
return (s32) comp_temp;
}
+static int bmp380_read_press_adc(struct bmp280_data *data, u32 *adc_press)
+{
+ u32 value_press;
+ int ret;
+
+ ret = regmap_bulk_read(data->regmap, BMP380_REG_PRESS_XLSB,
+ data->buf, sizeof(data->buf));
+ if (ret) {
+ dev_err(data->dev, "failed to read pressure\n");
+ return ret;
+ }
+
+ value_press = get_unaligned_le24(data->buf);
+ if (value_press == BMP380_PRESS_SKIPPED) {
+ dev_err(data->dev, "reading pressure skipped\n");
+ return -EIO;
+ }
+ *adc_press = value_press;
+
+ return 0;
+}
+
/*
* Returns pressure in Pa as an unsigned 32 bit integer in fractional Pascal.
* Output value of "9528709" represents 9528709/100 = 95287.09 Pa = 952.8709 hPa.
@@ -957,27 +1050,28 @@ static s32 bmp380_compensate_temp(struct bmp280_data *data, u32 adc_temp)
* Taken from datasheet, Section 9.3. "Pressure compensation" and repository
* https://github.com/BoschSensortec/BMP3-Sensor-API.
*/
-static u32 bmp380_compensate_press(struct bmp280_data *data, u32 adc_press)
+static u32 bmp380_compensate_press(struct bmp280_data *data,
+ u32 adc_press, s32 t_fine)
{
s64 var1, var2, var3, var4, var5, var6, offset, sensitivity;
struct bmp380_calib *calib = &data->calib.bmp380;
u32 comp_press;
- var1 = (s64)data->t_fine * (s64)data->t_fine;
+ var1 = (s64)t_fine * (s64)t_fine;
var2 = var1 >> 6;
- var3 = (var2 * ((s64) data->t_fine)) >> 8;
+ var3 = (var2 * ((s64)t_fine)) >> 8;
var4 = ((s64)calib->P8 * var3) >> 5;
var5 = ((s64)calib->P7 * var1) << 4;
- var6 = ((s64)calib->P6 * (s64)data->t_fine) << 22;
+ var6 = ((s64)calib->P6 * (s64)t_fine) << 22;
offset = ((s64)calib->P5 << 47) + var4 + var5 + var6;
var2 = ((s64)calib->P4 * var3) >> 5;
var4 = ((s64)calib->P3 * var1) << 2;
var5 = ((s64)calib->P2 - ((s64)1 << 14)) *
- ((s64)data->t_fine << 21);
+ ((s64)t_fine << 21);
sensitivity = (((s64) calib->P1 - ((s64) 1 << 14)) << 46) +
var2 + var4 + var5;
var1 = (sensitivity >> 24) * (s64)adc_press;
- var2 = (s64)calib->P10 * (s64)data->t_fine;
+ var2 = (s64)calib->P10 * (s64)t_fine;
var3 = var2 + ((s64)calib->P9 << 16);
var4 = (var3 * (s64)adc_press) >> 13;
@@ -1003,60 +1097,32 @@ static int bmp380_read_temp(struct bmp280_data *data, int *val, int *val2)
u32 adc_temp;
int ret;
- ret = regmap_bulk_read(data->regmap, BMP380_REG_TEMP_XLSB,
- data->buf, sizeof(data->buf));
- if (ret) {
- dev_err(data->dev, "failed to read temperature\n");
+ ret = bmp380_read_temp_adc(data, &adc_temp);
+ if (ret)
return ret;
- }
- adc_temp = get_unaligned_le24(data->buf);
- if (adc_temp == BMP380_TEMP_SKIPPED) {
- dev_err(data->dev, "reading temperature skipped\n");
- return -EIO;
- }
comp_temp = bmp380_compensate_temp(data, adc_temp);
- /*
- * Val might be NULL if we're called by the read_press routine,
- * who only cares about the carry over t_fine value.
- */
- if (val) {
- /* IIO reports temperatures in milli Celsius */
- *val = comp_temp * 10;
- return IIO_VAL_INT;
- }
-
- return 0;
+ *val = comp_temp * 10;
+ return IIO_VAL_INT;
}
static int bmp380_read_press(struct bmp280_data *data, int *val, int *val2)
{
- s32 comp_press;
- u32 adc_press;
+ u32 adc_press, comp_press, t_fine;
int ret;
- /* Read and compensate for temperature so we get a reading of t_fine */
- ret = bmp380_read_temp(data, NULL, NULL);
+ ret = bmp380_get_t_fine(data, &t_fine);
if (ret)
return ret;
- ret = regmap_bulk_read(data->regmap, BMP380_REG_PRESS_XLSB,
- data->buf, sizeof(data->buf));
- if (ret) {
- dev_err(data->dev, "failed to read pressure\n");
+ ret = bmp380_read_press_adc(data, &adc_press);
+ if (ret)
return ret;
- }
- adc_press = get_unaligned_le24(data->buf);
- if (adc_press == BMP380_PRESS_SKIPPED) {
- dev_err(data->dev, "reading pressure skipped\n");
- return -EIO;
- }
- comp_press = bmp380_compensate_press(data, adc_press);
+ comp_press = bmp380_compensate_press(data, adc_press, t_fine);
*val = comp_press;
- /* Compensated pressure is in cPa (centipascals) */
*val2 = 100000;
return IIO_VAL_FRACTIONAL;
@@ -1069,15 +1135,17 @@ static int bmp380_read_calib(struct bmp280_data *data)
/* Read temperature and pressure calibration data */
ret = regmap_bulk_read(data->regmap, BMP380_REG_CALIB_TEMP_START,
- data->bmp380_cal_buf, sizeof(data->bmp380_cal_buf));
+ data->bmp380_cal_buf,
+ sizeof(data->bmp380_cal_buf));
if (ret) {
dev_err(data->dev,
- "failed to read temperature calibration parameters\n");
+ "failed to read calibration parameters\n");
return ret;
}
/* Toss the temperature calibration data into the entropy pool */
- add_device_randomness(data->bmp380_cal_buf, sizeof(data->bmp380_cal_buf));
+ add_device_randomness(data->bmp380_cal_buf,
+ sizeof(data->bmp380_cal_buf));
/* Parse calibration values */
calib->T1 = get_unaligned_le16(&data->bmp380_cal_buf[BMP380_T1]);
@@ -1159,7 +1227,8 @@ static int bmp380_chip_config(struct bmp280_data *data)
/* Configure output data rate */
ret = regmap_update_bits_check(data->regmap, BMP380_REG_ODR,
- BMP380_ODRS_MASK, data->sampling_freq, &aux);
+ BMP380_ODRS_MASK, data->sampling_freq,
+ &aux);
if (ret) {
dev_err(data->dev, "failed to write ODR selection register\n");
return ret;
@@ -1178,12 +1247,13 @@ static int bmp380_chip_config(struct bmp280_data *data)
if (change) {
/*
- * The configurations errors are detected on the fly during a measurement
- * cycle. If the sampling frequency is too low, it's faster to reset
- * the measurement loop than wait until the next measurement is due.
+ * The configurations errors are detected on the fly during a
+ * measurement cycle. If the sampling frequency is too low, it's
+ * faster to reset the measurement loop than wait until the next
+ * measurement is due.
*
- * Resets sensor measurement loop toggling between sleep and normal
- * operating modes.
+ * Resets sensor measurement loop toggling between sleep and
+ * normal operating modes.
*/
ret = regmap_write_bits(data->regmap, BMP380_REG_POWER_CONTROL,
BMP380_MODE_MASK,
@@ -1201,22 +1271,21 @@ static int bmp380_chip_config(struct bmp280_data *data)
return ret;
}
/*
- * Waits for measurement before checking configuration error flag.
- * Selected longest measure time indicated in section 3.9.1
- * in the datasheet.
+ * Waits for measurement before checking configuration error
+ * flag. Selected longest measure time indicated in
+ * section 3.9.1 in the datasheet.
*/
msleep(80);
/* Check config error flag */
ret = regmap_read(data->regmap, BMP380_REG_ERROR, &tmp);
if (ret) {
- dev_err(data->dev,
- "failed to read error register\n");
+ dev_err(data->dev, "failed to read error register\n");
return ret;
}
if (tmp & BMP380_ERR_CONF_MASK) {
dev_warn(data->dev,
- "sensor flagged configuration as incompatible\n");
+ "sensor flagged configuration as incompatible\n");
return -EINVAL;
}
}
@@ -1317,9 +1386,11 @@ static int bmp580_nvm_operation(struct bmp280_data *data, bool is_write)
}
/* Start NVM operation sequence */
- ret = regmap_write(data->regmap, BMP580_REG_CMD, BMP580_CMD_NVM_OP_SEQ_0);
+ ret = regmap_write(data->regmap, BMP580_REG_CMD,
+ BMP580_CMD_NVM_OP_SEQ_0);
if (ret) {
- dev_err(data->dev, "failed to send nvm operation's first sequence\n");
+ dev_err(data->dev,
+ "failed to send nvm operation's first sequence\n");
return ret;
}
if (is_write) {
@@ -1327,7 +1398,8 @@ static int bmp580_nvm_operation(struct bmp280_data *data, bool is_write)
ret = regmap_write(data->regmap, BMP580_REG_CMD,
BMP580_CMD_NVM_WRITE_SEQ_1);
if (ret) {
- dev_err(data->dev, "failed to send nvm write sequence\n");
+ dev_err(data->dev,
+ "failed to send nvm write sequence\n");
return ret;
}
/* Datasheet says on 4.8.1.2 it takes approximately 10ms */
@@ -1338,17 +1410,14 @@ static int bmp580_nvm_operation(struct bmp280_data *data, bool is_write)
ret = regmap_write(data->regmap, BMP580_REG_CMD,
BMP580_CMD_NVM_READ_SEQ_1);
if (ret) {
- dev_err(data->dev, "failed to send nvm read sequence\n");
+ dev_err(data->dev,
+ "failed to send nvm read sequence\n");
return ret;
}
/* Datasheet says on 4.8.1.1 it takes approximately 200us */
poll = 50;
timeout = 400;
}
- if (ret) {
- dev_err(data->dev, "failed to write command sequence\n");
- return -EIO;
- }
/* Wait until NVM is ready again */
ret = regmap_read_poll_timeout(data->regmap, BMP580_REG_STATUS, reg,
@@ -1465,15 +1534,14 @@ static const int bmp580_odr_table[][2] = {
static const int bmp580_nvmem_addrs[] = { 0x20, 0x21, 0x22 };
-static int bmp580_nvmem_read(void *priv, unsigned int offset, void *val,
- size_t bytes)
+static int bmp580_nvmem_read_impl(void *priv, unsigned int offset, void *val,
+ size_t bytes)
{
struct bmp280_data *data = priv;
u16 *dst = val;
int ret, addr;
- pm_runtime_get_sync(data->dev);
- mutex_lock(&data->lock);
+ guard(mutex)(&data->lock);
/* Set sensor in standby mode */
ret = regmap_update_bits(data->regmap, BMP580_REG_ODR_CONFIG,
@@ -1501,8 +1569,8 @@ static int bmp580_nvmem_read(void *priv, unsigned int offset, void *val,
if (ret)
goto exit;
- ret = regmap_bulk_read(data->regmap, BMP580_REG_NVM_DATA_LSB, &data->le16,
- sizeof(data->le16));
+ ret = regmap_bulk_read(data->regmap, BMP580_REG_NVM_DATA_LSB,
+ &data->le16, sizeof(data->le16));
if (ret) {
dev_err(data->dev, "error reading nvm data regs\n");
goto exit;
@@ -1515,21 +1583,31 @@ static int bmp580_nvmem_read(void *priv, unsigned int offset, void *val,
exit:
/* Restore chip config */
data->chip_info->chip_config(data);
- mutex_unlock(&data->lock);
+ return ret;
+}
+
+static int bmp580_nvmem_read(void *priv, unsigned int offset, void *val,
+ size_t bytes)
+{
+ struct bmp280_data *data = priv;
+ int ret;
+
+ pm_runtime_get_sync(data->dev);
+ ret = bmp580_nvmem_read_impl(priv, offset, val, bytes);
pm_runtime_mark_last_busy(data->dev);
pm_runtime_put_autosuspend(data->dev);
+
return ret;
}
-static int bmp580_nvmem_write(void *priv, unsigned int offset, void *val,
- size_t bytes)
+static int bmp580_nvmem_write_impl(void *priv, unsigned int offset, void *val,
+ size_t bytes)
{
struct bmp280_data *data = priv;
u16 *buf = val;
int ret, addr;
- pm_runtime_get_sync(data->dev);
- mutex_lock(&data->lock);
+ guard(mutex)(&data->lock);
/* Set sensor in standby mode */
ret = regmap_update_bits(data->regmap, BMP580_REG_ODR_CONFIG,
@@ -1546,7 +1624,8 @@ static int bmp580_nvmem_write(void *priv, unsigned int offset, void *val,
while (bytes >= sizeof(*buf)) {
addr = bmp580_nvmem_addrs[offset / sizeof(*buf)];
- ret = regmap_write(data->regmap, BMP580_REG_NVM_ADDR, BMP580_NVM_PROG_EN |
+ ret = regmap_write(data->regmap, BMP580_REG_NVM_ADDR,
+ BMP580_NVM_PROG_EN |
FIELD_PREP(BMP580_NVM_ROW_ADDR_MASK, addr));
if (ret) {
dev_err(data->dev, "error writing nvm address\n");
@@ -1554,8 +1633,8 @@ static int bmp580_nvmem_write(void *priv, unsigned int offset, void *val,
}
data->le16 = cpu_to_le16(*buf++);
- ret = regmap_bulk_write(data->regmap, BMP580_REG_NVM_DATA_LSB, &data->le16,
- sizeof(data->le16));
+ ret = regmap_bulk_write(data->regmap, BMP580_REG_NVM_DATA_LSB,
+ &data->le16, sizeof(data->le16));
if (ret) {
dev_err(data->dev, "error writing LSB NVM data regs\n");
goto exit;
@@ -1579,9 +1658,20 @@ static int bmp580_nvmem_write(void *priv, unsigned int offset, void *val,
exit:
/* Restore chip config */
data->chip_info->chip_config(data);
- mutex_unlock(&data->lock);
+ return ret;
+}
+
+static int bmp580_nvmem_write(void *priv, unsigned int offset, void *val,
+ size_t bytes)
+{
+ struct bmp280_data *data = priv;
+ int ret;
+
+ pm_runtime_get_sync(data->dev);
+ ret = bmp580_nvmem_write_impl(priv, offset, val, bytes);
pm_runtime_mark_last_busy(data->dev);
pm_runtime_put_autosuspend(data->dev);
+
return ret;
}
@@ -1607,20 +1697,24 @@ static int bmp580_preinit(struct bmp280_data *data)
/* Post powerup sequence */
ret = regmap_read(data->regmap, BMP580_REG_CHIP_ID, &reg);
- if (ret)
+ if (ret) {
+ dev_err(data->dev, "failed to establish comms with the chip\n");
return ret;
+ }
/* Print warn message if we don't know the chip id */
if (reg != BMP580_CHIP_ID && reg != BMP580_CHIP_ID_ALT)
- dev_warn(data->dev, "preinit: unexpected chip_id\n");
+ dev_warn(data->dev, "unexpected chip_id\n");
ret = regmap_read(data->regmap, BMP580_REG_STATUS, &reg);
- if (ret)
+ if (ret) {
+ dev_err(data->dev, "failed to read nvm status\n");
return ret;
+ }
/* Check nvm status */
if (!(reg & BMP580_STATUS_NVM_RDY_MASK) || (reg & BMP580_STATUS_NVM_ERR_MASK)) {
- dev_err(data->dev, "preinit: nvm error on powerup sequence\n");
+ dev_err(data->dev, "nvm error on powerup sequence\n");
return -EIO;
}
@@ -1655,6 +1749,10 @@ static int bmp580_chip_config(struct bmp280_data *data)
BMP580_DSP_COMP_MASK |
BMP580_DSP_SHDW_IIR_TEMP_EN |
BMP580_DSP_SHDW_IIR_PRESS_EN, reg_val);
+ if (ret) {
+ dev_err(data->dev, "failed to change DSP mode settings\n");
+ return ret;
+ }
/* Configure oversampling */
reg_val = FIELD_PREP(BMP580_OSR_TEMP_MASK, data->oversampling_temp) |
@@ -1662,7 +1760,8 @@ static int bmp580_chip_config(struct bmp280_data *data)
BMP580_OSR_PRESS_EN;
ret = regmap_update_bits_check(data->regmap, BMP580_REG_OSR_CONFIG,
- BMP580_OSR_TEMP_MASK | BMP580_OSR_PRESS_MASK |
+ BMP580_OSR_TEMP_MASK |
+ BMP580_OSR_PRESS_MASK |
BMP580_OSR_PRESS_EN,
reg_val, &aux);
if (ret) {
@@ -1713,7 +1812,8 @@ static int bmp580_chip_config(struct bmp280_data *data)
*/
ret = regmap_read(data->regmap, BMP580_REG_EFF_OSR, &tmp);
if (ret) {
- dev_err(data->dev, "error reading effective OSR register\n");
+ dev_err(data->dev,
+ "error reading effective OSR register\n");
return ret;
}
if (!(tmp & BMP580_EFF_OSR_VALID_ODR)) {
@@ -1763,7 +1863,7 @@ const struct bmp280_chip_info bmp580_chip_info = {
};
EXPORT_SYMBOL_NS(bmp580_chip_info, IIO_BMP280);
-static int bmp180_measure(struct bmp280_data *data, u8 ctrl_meas)
+static int bmp180_wait_for_eoc(struct bmp280_data *data, u8 ctrl_meas)
{
const int conversion_time_max[] = { 4500, 7500, 13500, 25500 };
unsigned int delay_us;
@@ -1774,8 +1874,10 @@ static int bmp180_measure(struct bmp280_data *data, u8 ctrl_meas)
reinit_completion(&data->done);
ret = regmap_write(data->regmap, BMP280_REG_CTRL_MEAS, ctrl_meas);
- if (ret)
+ if (ret) {
+ dev_err(data->dev, "failed to write crtl_meas register\n");
return ret;
+ }
if (data->use_eoc) {
/*
@@ -1798,32 +1900,38 @@ static int bmp180_measure(struct bmp280_data *data, u8 ctrl_meas)
}
ret = regmap_read(data->regmap, BMP280_REG_CTRL_MEAS, &ctrl);
- if (ret)
+ if (ret) {
+ dev_err(data->dev, "failed to read ctrl_meas register\n");
return ret;
+ }
/* The value of this bit reset to "0" after conversion is complete */
- if (ctrl & BMP180_MEAS_SCO)
+ if (ctrl & BMP180_MEAS_SCO) {
+ dev_err(data->dev, "conversion didn't complete\n");
return -EIO;
+ }
return 0;
}
-static int bmp180_read_adc_temp(struct bmp280_data *data, int *val)
+static int bmp180_read_temp_adc(struct bmp280_data *data, u32 *adc_temp)
{
int ret;
- ret = bmp180_measure(data,
- FIELD_PREP(BMP180_MEAS_CTRL_MASK, BMP180_MEAS_TEMP) |
- BMP180_MEAS_SCO);
+ ret = bmp180_wait_for_eoc(data,
+ FIELD_PREP(BMP180_MEAS_CTRL_MASK, BMP180_MEAS_TEMP) |
+ BMP180_MEAS_SCO);
if (ret)
return ret;
ret = regmap_bulk_read(data->regmap, BMP180_REG_OUT_MSB,
&data->be16, sizeof(data->be16));
- if (ret)
+ if (ret) {
+ dev_err(data->dev, "failed to read temperature\n");
return ret;
+ }
- *val = be16_to_cpu(data->be16);
+ *adc_temp = be16_to_cpu(data->be16);
return 0;
}
@@ -1836,9 +1944,10 @@ static int bmp180_read_calib(struct bmp280_data *data)
ret = regmap_bulk_read(data->regmap, BMP180_REG_CALIB_START,
data->bmp180_cal_buf, sizeof(data->bmp180_cal_buf));
-
- if (ret < 0)
+ if (ret) {
+ dev_err(data->dev, "failed to read calibration parameters\n");
return ret;
+ }
/* None of the words has the value 0 or 0xFFFF */
for (i = 0; i < ARRAY_SIZE(data->bmp180_cal_buf); i++) {
@@ -1848,7 +1957,8 @@ static int bmp180_read_calib(struct bmp280_data *data)
}
/* Toss the calibration data into the entropy pool */
- add_device_randomness(data->bmp180_cal_buf, sizeof(data->bmp180_cal_buf));
+ add_device_randomness(data->bmp180_cal_buf,
+ sizeof(data->bmp180_cal_buf));
calib->AC1 = be16_to_cpu(data->bmp180_cal_buf[AC1]);
calib->AC2 = be16_to_cpu(data->bmp180_cal_buf[AC2]);
@@ -1871,59 +1981,72 @@ static int bmp180_read_calib(struct bmp280_data *data)
*
* Taken from datasheet, Section 3.5, "Calculating pressure and temperature".
*/
-static s32 bmp180_compensate_temp(struct bmp280_data *data, s32 adc_temp)
+
+static s32 bmp180_calc_t_fine(struct bmp280_data *data, u32 adc_temp)
{
struct bmp180_calib *calib = &data->calib.bmp180;
s32 x1, x2;
- x1 = ((adc_temp - calib->AC6) * calib->AC5) >> 15;
+ x1 = ((((s32)adc_temp) - calib->AC6) * calib->AC5) >> 15;
x2 = (calib->MC << 11) / (x1 + calib->MD);
- data->t_fine = x1 + x2;
+ return x1 + x2; /* t_fine = x1 + x2; */
+}
+
+static int bmp180_get_t_fine(struct bmp280_data *data, s32 *t_fine)
+{
+ s32 adc_temp;
+ int ret;
+
+ ret = bmp180_read_temp_adc(data, &adc_temp);
+ if (ret)
+ return ret;
+
+ *t_fine = bmp180_calc_t_fine(data, adc_temp);
+
+ return 0;
+}
- return (data->t_fine + 8) >> 4;
+static s32 bmp180_compensate_temp(struct bmp280_data *data, u32 adc_temp)
+{
+ return (bmp180_calc_t_fine(data, adc_temp) + 8) / 16;
}
static int bmp180_read_temp(struct bmp280_data *data, int *val, int *val2)
{
- s32 adc_temp, comp_temp;
+ s32 comp_temp;
+ u32 adc_temp;
int ret;
- ret = bmp180_read_adc_temp(data, &adc_temp);
+ ret = bmp180_read_temp_adc(data, &adc_temp);
if (ret)
return ret;
comp_temp = bmp180_compensate_temp(data, adc_temp);
- /*
- * val might be NULL if we're called by the read_press routine,
- * who only cares about the carry over t_fine value.
- */
- if (val) {
- *val = comp_temp * 100;
- return IIO_VAL_INT;
- }
-
- return 0;
+ *val = comp_temp * 100;
+ return IIO_VAL_INT;
}
-static int bmp180_read_adc_press(struct bmp280_data *data, int *val)
+static int bmp180_read_press_adc(struct bmp280_data *data, u32 *adc_press)
{
u8 oss = data->oversampling_press;
int ret;
- ret = bmp180_measure(data,
- FIELD_PREP(BMP180_MEAS_CTRL_MASK, BMP180_MEAS_PRESS) |
- FIELD_PREP(BMP180_OSRS_PRESS_MASK, oss) |
- BMP180_MEAS_SCO);
+ ret = bmp180_wait_for_eoc(data,
+ FIELD_PREP(BMP180_MEAS_CTRL_MASK, BMP180_MEAS_PRESS) |
+ FIELD_PREP(BMP180_OSRS_PRESS_MASK, oss) |
+ BMP180_MEAS_SCO);
if (ret)
return ret;
ret = regmap_bulk_read(data->regmap, BMP180_REG_OUT_MSB,
data->buf, sizeof(data->buf));
- if (ret)
+ if (ret) {
+ dev_err(data->dev, "failed to read pressure\n");
return ret;
+ }
- *val = get_unaligned_be24(data->buf) >> (8 - oss);
+ *adc_press = get_unaligned_be24(data->buf) >> (8 - oss);
return 0;
}
@@ -1933,7 +2056,8 @@ static int bmp180_read_adc_press(struct bmp280_data *data, int *val)
*
* Taken from datasheet, Section 3.5, "Calculating pressure and temperature".
*/
-static u32 bmp180_compensate_press(struct bmp280_data *data, s32 adc_press)
+static u32 bmp180_compensate_press(struct bmp280_data *data, u32 adc_press,
+ s32 t_fine)
{
struct bmp180_calib *calib = &data->calib.bmp180;
s32 oss = data->oversampling_press;
@@ -1941,7 +2065,7 @@ static u32 bmp180_compensate_press(struct bmp280_data *data, s32 adc_press)
s32 b3, b6;
u32 b4, b7;
- b6 = data->t_fine - 4000;
+ b6 = t_fine - 4000;
x1 = (calib->B2 * (b6 * b6 >> 12)) >> 11;
x2 = calib->AC2 * b6 >> 11;
x3 = x1 + x2;
@@ -1950,7 +2074,7 @@ static u32 bmp180_compensate_press(struct bmp280_data *data, s32 adc_press)
x2 = (calib->B1 * ((b6 * b6) >> 12)) >> 16;
x3 = (x1 + x2 + 2) >> 2;
b4 = calib->AC4 * (u32)(x3 + 32768) >> 15;
- b7 = ((u32)adc_press - b3) * (50000 >> oss);
+ b7 = (adc_press - b3) * (50000 >> oss);
if (b7 < 0x80000000)
p = (b7 * 2) / b4;
else
@@ -1963,23 +2087,21 @@ static u32 bmp180_compensate_press(struct bmp280_data *data, s32 adc_press)
return p + ((x1 + x2 + 3791) >> 4);
}
-static int bmp180_read_press(struct bmp280_data *data,
- int *val, int *val2)
+static int bmp180_read_press(struct bmp280_data *data, int *val, int *val2)
{
- u32 comp_press;
- s32 adc_press;
+ u32 comp_press, adc_press;
+ s32 t_fine;
int ret;
- /* Read and compensate temperature so we get a reading of t_fine. */
- ret = bmp180_read_temp(data, NULL, NULL);
+ ret = bmp180_get_t_fine(data, &t_fine);
if (ret)
return ret;
- ret = bmp180_read_adc_press(data, &adc_press);
+ ret = bmp180_read_press_adc(data, &adc_press);
if (ret)
return ret;
- comp_press = bmp180_compensate_press(data, adc_press);
+ comp_press = bmp180_compensate_press(data, adc_press, t_fine);
*val = comp_press;
*val2 = 1000;
@@ -2154,8 +2276,10 @@ int bmp280_common_probe(struct device *dev,
data->regmap = regmap;
ret = regmap_read(regmap, data->chip_info->id_reg, &chip_id);
- if (ret < 0)
+ if (ret) {
+ dev_err(data->dev, "failed to read chip id\n");
return ret;
+ }
for (i = 0; i < data->chip_info->num_chip_id; i++) {
if (chip_id == data->chip_info->chip_id[i]) {
@@ -2175,7 +2299,7 @@ int bmp280_common_probe(struct device *dev,
}
ret = data->chip_info->chip_config(data);
- if (ret < 0)
+ if (ret)
return ret;
dev_set_drvdata(dev, indio_dev);
@@ -2188,7 +2312,7 @@ int bmp280_common_probe(struct device *dev,
if (data->chip_info->read_calib) {
ret = data->chip_info->read_calib(data);
- if (ret < 0)
+ if (ret)
return dev_err_probe(data->dev, ret,
"failed to read calibration coefficients\n");
}
@@ -2241,6 +2365,7 @@ static int bmp280_runtime_resume(struct device *dev)
ret = regulator_bulk_enable(BMP280_NUM_SUPPLIES, data->supplies);
if (ret)
return ret;
+
usleep_range(data->start_up_time, data->start_up_time + 100);
return data->chip_info->chip_config(data);
}
diff --git a/drivers/iio/pressure/bmp280-regmap.c b/drivers/iio/pressure/bmp280-regmap.c
index 3ee56720428c..fa52839474b1 100644
--- a/drivers/iio/pressure/bmp280-regmap.c
+++ b/drivers/iio/pressure/bmp280-regmap.c
@@ -45,7 +45,7 @@ static bool bmp280_is_writeable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case BMP280_REG_CONFIG:
- case BMP280_REG_CTRL_HUMIDITY:
+ case BME280_REG_CTRL_HUMIDITY:
case BMP280_REG_CTRL_MEAS:
case BMP280_REG_RESET:
return true;
@@ -57,8 +57,8 @@ static bool bmp280_is_writeable_reg(struct device *dev, unsigned int reg)
static bool bmp280_is_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
- case BMP280_REG_HUMIDITY_LSB:
- case BMP280_REG_HUMIDITY_MSB:
+ case BME280_REG_HUMIDITY_LSB:
+ case BME280_REG_HUMIDITY_MSB:
case BMP280_REG_TEMP_XLSB:
case BMP280_REG_TEMP_LSB:
case BMP280_REG_TEMP_MSB:
@@ -167,7 +167,7 @@ const struct regmap_config bmp280_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
- .max_register = BMP280_REG_HUMIDITY_LSB,
+ .max_register = BME280_REG_HUMIDITY_LSB,
.cache_type = REGCACHE_RBTREE,
.writeable_reg = bmp280_is_writeable_reg,
diff --git a/drivers/iio/pressure/bmp280-spi.c b/drivers/iio/pressure/bmp280-spi.c
index 4e19ea0b4d39..62b4e58104cf 100644
--- a/drivers/iio/pressure/bmp280-spi.c
+++ b/drivers/iio/pressure/bmp280-spi.c
@@ -13,7 +13,7 @@
#include "bmp280.h"
static int bmp280_regmap_spi_write(void *context, const void *data,
- size_t count)
+ size_t count)
{
struct spi_device *spi = to_spi_device(context);
u8 buf[2];
@@ -29,7 +29,7 @@ static int bmp280_regmap_spi_write(void *context, const void *data,
}
static int bmp280_regmap_spi_read(void *context, const void *reg,
- size_t reg_size, void *val, size_t val_size)
+ size_t reg_size, void *val, size_t val_size)
{
struct spi_device *spi = to_spi_device(context);
diff --git a/drivers/iio/pressure/bmp280.h b/drivers/iio/pressure/bmp280.h
index 5812a344ed8e..7c30e4d523be 100644
--- a/drivers/iio/pressure/bmp280.h
+++ b/drivers/iio/pressure/bmp280.h
@@ -192,8 +192,6 @@
#define BMP380_PRESS_SKIPPED 0x800000
/* BMP280 specific registers */
-#define BMP280_REG_HUMIDITY_LSB 0xFE
-#define BMP280_REG_HUMIDITY_MSB 0xFD
#define BMP280_REG_TEMP_XLSB 0xFC
#define BMP280_REG_TEMP_LSB 0xFB
#define BMP280_REG_TEMP_MSB 0xFA
@@ -207,15 +205,6 @@
#define BMP280_REG_CONFIG 0xF5
#define BMP280_REG_CTRL_MEAS 0xF4
#define BMP280_REG_STATUS 0xF3
-#define BMP280_REG_CTRL_HUMIDITY 0xF2
-
-/* Due to non linear mapping, and data sizes we can't do a bulk read */
-#define BMP280_REG_COMP_H1 0xA1
-#define BMP280_REG_COMP_H2 0xE1
-#define BMP280_REG_COMP_H3 0xE3
-#define BMP280_REG_COMP_H4 0xE4
-#define BMP280_REG_COMP_H5 0xE5
-#define BMP280_REG_COMP_H6 0xE7
#define BMP280_REG_COMP_TEMP_START 0x88
#define BMP280_COMP_TEMP_REG_COUNT 6
@@ -223,8 +212,6 @@
#define BMP280_REG_COMP_PRESS_START 0x8E
#define BMP280_COMP_PRESS_REG_COUNT 18
-#define BMP280_COMP_H5_MASK GENMASK(15, 4)
-
#define BMP280_CONTIGUOUS_CALIB_REGS (BMP280_COMP_TEMP_REG_COUNT + \
BMP280_COMP_PRESS_REG_COUNT)
@@ -235,14 +222,6 @@
#define BMP280_FILTER_8X 3
#define BMP280_FILTER_16X 4
-#define BMP280_OSRS_HUMIDITY_MASK GENMASK(2, 0)
-#define BMP280_OSRS_HUMIDITY_SKIP 0
-#define BMP280_OSRS_HUMIDITY_1X 1
-#define BMP280_OSRS_HUMIDITY_2X 2
-#define BMP280_OSRS_HUMIDITY_4X 3
-#define BMP280_OSRS_HUMIDITY_8X 4
-#define BMP280_OSRS_HUMIDITY_16X 5
-
#define BMP280_OSRS_TEMP_MASK GENMASK(7, 5)
#define BMP280_OSRS_TEMP_SKIP 0
#define BMP280_OSRS_TEMP_1X 1
@@ -264,6 +243,30 @@
#define BMP280_MODE_FORCED 1
#define BMP280_MODE_NORMAL 3
+/* BME280 specific registers */
+#define BME280_REG_HUMIDITY_LSB 0xFE
+#define BME280_REG_HUMIDITY_MSB 0xFD
+
+#define BME280_REG_CTRL_HUMIDITY 0xF2
+
+/* Due to non linear mapping, and data sizes we can't do a bulk read */
+#define BME280_REG_COMP_H1 0xA1
+#define BME280_REG_COMP_H2 0xE1
+#define BME280_REG_COMP_H3 0xE3
+#define BME280_REG_COMP_H4 0xE4
+#define BME280_REG_COMP_H5 0xE5
+#define BME280_REG_COMP_H6 0xE7
+
+#define BME280_COMP_H5_MASK GENMASK(15, 4)
+
+#define BME280_OSRS_HUMIDITY_MASK GENMASK(2, 0)
+#define BME280_OSRS_HUMIDITY_SKIP 0
+#define BME280_OSRS_HUMIDITY_1X 1
+#define BME280_OSRS_HUMIDITY_2X 2
+#define BME280_OSRS_HUMIDITY_4X 3
+#define BME280_OSRS_HUMIDITY_8X 4
+#define BME280_OSRS_HUMIDITY_16X 5
+
/* BMP180 specific registers */
#define BMP180_REG_OUT_XLSB 0xF8
#define BMP180_REG_OUT_LSB 0xF7
@@ -395,12 +398,6 @@ struct bmp280_data {
int sampling_freq;
/*
- * Carryover value from temperature conversion, used in pressure
- * calculation.
- */
- s32 t_fine;
-
- /*
* DMA (thus cache coherency maintenance) may require the
* transfer buffers to live in their own cache lines.
*/
@@ -449,12 +446,12 @@ struct bmp280_chip_info {
int num_sampling_freq_avail;
int sampling_freq_default;
- int (*chip_config)(struct bmp280_data *);
- int (*read_temp)(struct bmp280_data *, int *, int *);
- int (*read_press)(struct bmp280_data *, int *, int *);
- int (*read_humid)(struct bmp280_data *, int *, int *);
- int (*read_calib)(struct bmp280_data *);
- int (*preinit)(struct bmp280_data *);
+ int (*chip_config)(struct bmp280_data *data);
+ int (*read_temp)(struct bmp280_data *data, int *val, int *val2);
+ int (*read_press)(struct bmp280_data *data, int *val, int *val2);
+ int (*read_humid)(struct bmp280_data *data, int *val, int *val2);
+ int (*read_calib)(struct bmp280_data *data);
+ int (*preinit)(struct bmp280_data *data);
};
/* Chip infos for each variant */
@@ -473,7 +470,7 @@ extern const struct regmap_config bmp580_regmap_config;
/* Probe called from different transports */
int bmp280_common_probe(struct device *dev,
struct regmap *regmap,
- const struct bmp280_chip_info *,
+ const struct bmp280_chip_info *chip_info,
const char *name,
int irq);
diff --git a/drivers/iio/pressure/dps310.c b/drivers/iio/pressure/dps310.c
index 7d882e15e556..c6f44f0f4d2e 100644
--- a/drivers/iio/pressure/dps310.c
+++ b/drivers/iio/pressure/dps310.c
@@ -887,7 +887,7 @@ static int dps310_probe(struct i2c_client *client)
}
static const struct i2c_device_id dps310_id[] = {
- { DPS310_DEV_NAME, 0 },
+ { DPS310_DEV_NAME },
{}
};
MODULE_DEVICE_TABLE(i2c, dps310_id);
diff --git a/drivers/iio/pressure/hp03.c b/drivers/iio/pressure/hp03.c
index 8bdb279129fa..6f7a16787143 100644
--- a/drivers/iio/pressure/hp03.c
+++ b/drivers/iio/pressure/hp03.c
@@ -266,8 +266,8 @@ static int hp03_probe(struct i2c_client *client)
}
static const struct i2c_device_id hp03_id[] = {
- { "hp03", 0 },
- { },
+ { "hp03" },
+ { }
};
MODULE_DEVICE_TABLE(i2c, hp03_id);
diff --git a/drivers/iio/pressure/icp10100.c b/drivers/iio/pressure/icp10100.c
index 2086f3ef338f..3e0bf5d31ad7 100644
--- a/drivers/iio/pressure/icp10100.c
+++ b/drivers/iio/pressure/icp10100.c
@@ -637,7 +637,7 @@ static const struct of_device_id icp10100_of_match[] = {
MODULE_DEVICE_TABLE(of, icp10100_of_match);
static const struct i2c_device_id icp10100_id[] = {
- { "icp10100", 0 },
+ { "icp10100" },
{ }
};
MODULE_DEVICE_TABLE(i2c, icp10100_id);
diff --git a/drivers/iio/pressure/mpl115_i2c.c b/drivers/iio/pressure/mpl115_i2c.c
index fcbdadf4a511..0c51dc02478e 100644
--- a/drivers/iio/pressure/mpl115_i2c.c
+++ b/drivers/iio/pressure/mpl115_i2c.c
@@ -45,7 +45,7 @@ static int mpl115_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id mpl115_i2c_id[] = {
- { "mpl115", 0 },
+ { "mpl115" },
{ }
};
MODULE_DEVICE_TABLE(i2c, mpl115_i2c_id);
diff --git a/drivers/iio/pressure/mpl3115.c b/drivers/iio/pressure/mpl3115.c
index 7aa19584c340..71ded2eee060 100644
--- a/drivers/iio/pressure/mpl3115.c
+++ b/drivers/iio/pressure/mpl3115.c
@@ -318,7 +318,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(mpl3115_pm_ops, mpl3115_suspend,
mpl3115_resume);
static const struct i2c_device_id mpl3115_id[] = {
- { "mpl3115", 0 },
+ { "mpl3115" },
{ }
};
MODULE_DEVICE_TABLE(i2c, mpl3115_id);
diff --git a/drivers/iio/pressure/t5403.c b/drivers/iio/pressure/t5403.c
index a6463c06975e..c7cb0fd816d3 100644
--- a/drivers/iio/pressure/t5403.c
+++ b/drivers/iio/pressure/t5403.c
@@ -251,7 +251,7 @@ static int t5403_probe(struct i2c_client *client)
}
static const struct i2c_device_id t5403_id[] = {
- { "t5403", 0 },
+ { "t5403" },
{ }
};
MODULE_DEVICE_TABLE(i2c, t5403_id);
diff --git a/drivers/iio/pressure/zpa2326_i2c.c b/drivers/iio/pressure/zpa2326_i2c.c
index c7fffbe7c788..4833e525c393 100644
--- a/drivers/iio/pressure/zpa2326_i2c.c
+++ b/drivers/iio/pressure/zpa2326_i2c.c
@@ -59,8 +59,8 @@ static void zpa2326_remove_i2c(struct i2c_client *client)
}
static const struct i2c_device_id zpa2326_i2c_ids[] = {
- { "zpa2326", 0 },
- { },
+ { "zpa2326" },
+ { }
};
MODULE_DEVICE_TABLE(i2c, zpa2326_i2c_ids);
diff --git a/drivers/iio/proximity/isl29501.c b/drivers/iio/proximity/isl29501.c
index 4982686fb4c3..dc66ca9bba6b 100644
--- a/drivers/iio/proximity/isl29501.c
+++ b/drivers/iio/proximity/isl29501.c
@@ -989,7 +989,7 @@ static int isl29501_probe(struct i2c_client *client)
}
static const struct i2c_device_id isl29501_id[] = {
- {"isl29501", 0},
+ { "isl29501" },
{}
};
diff --git a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
index 2913d5e0fe4f..5c959730aecd 100644
--- a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
+++ b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
@@ -322,9 +322,9 @@ static void lidar_remove(struct i2c_client *client)
}
static const struct i2c_device_id lidar_id[] = {
- {"lidar-lite-v2", 0},
- {"lidar-lite-v3", 0},
- { },
+ { "lidar-lite-v2" },
+ { "lidar-lite-v3" },
+ { }
};
MODULE_DEVICE_TABLE(i2c, lidar_id);
diff --git a/drivers/iio/proximity/rfd77402.c b/drivers/iio/proximity/rfd77402.c
index f02e83e3f15f..aff60a3c1a6f 100644
--- a/drivers/iio/proximity/rfd77402.c
+++ b/drivers/iio/proximity/rfd77402.c
@@ -308,7 +308,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(rfd77402_pm_ops, rfd77402_suspend,
rfd77402_resume);
static const struct i2c_device_id rfd77402_id[] = {
- { "rfd77402", 0 },
+ { "rfd77402" },
{ }
};
MODULE_DEVICE_TABLE(i2c, rfd77402_id);
diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c
index 550e7d3cd5ee..b89d49defd7a 100644
--- a/drivers/iio/proximity/sx9500.c
+++ b/drivers/iio/proximity/sx9500.c
@@ -1043,8 +1043,8 @@ static const struct of_device_id sx9500_of_match[] = {
MODULE_DEVICE_TABLE(of, sx9500_of_match);
static const struct i2c_device_id sx9500_id[] = {
- {"sx9500", 0},
- { },
+ { "sx9500" },
+ { }
};
MODULE_DEVICE_TABLE(i2c, sx9500_id);
diff --git a/drivers/iio/proximity/vl53l0x-i2c.c b/drivers/iio/proximity/vl53l0x-i2c.c
index 2cea64bea909..8d4f3f849fe2 100644
--- a/drivers/iio/proximity/vl53l0x-i2c.c
+++ b/drivers/iio/proximity/vl53l0x-i2c.c
@@ -278,7 +278,7 @@ static int vl53l0x_probe(struct i2c_client *client)
}
static const struct i2c_device_id vl53l0x_id[] = {
- { "vl53l0x", 0 },
+ { "vl53l0x" },
{ }
};
MODULE_DEVICE_TABLE(i2c, vl53l0x_id);
diff --git a/drivers/iio/temperature/max30208.c b/drivers/iio/temperature/max30208.c
index 48be03852cd8..720469f9dc36 100644
--- a/drivers/iio/temperature/max30208.c
+++ b/drivers/iio/temperature/max30208.c
@@ -34,7 +34,6 @@
struct max30208_data {
struct i2c_client *client;
- struct iio_dev *indio_dev;
struct mutex lock; /* Lock to prevent concurrent reads of temperature readings */
};
diff --git a/drivers/iio/temperature/mcp9600.c b/drivers/iio/temperature/mcp9600.c
index 7a3eef5d5e75..f1bb0976273d 100644
--- a/drivers/iio/temperature/mcp9600.c
+++ b/drivers/iio/temperature/mcp9600.c
@@ -6,39 +6,123 @@
* Author: <andrew.hepp@ahepp.dev>
*/
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/bits.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/math.h>
+#include <linux/minmax.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
+#include <linux/iio/events.h>
#include <linux/iio/iio.h>
/* MCP9600 registers */
#define MCP9600_HOT_JUNCTION 0x0
#define MCP9600_COLD_JUNCTION 0x2
+#define MCP9600_STATUS 0x4
+#define MCP9600_STATUS_ALERT(x) BIT(x)
+#define MCP9600_ALERT_CFG1 0x8
+#define MCP9600_ALERT_CFG(x) (MCP9600_ALERT_CFG1 + (x - 1))
+#define MCP9600_ALERT_CFG_ENABLE BIT(0)
+#define MCP9600_ALERT_CFG_ACTIVE_HIGH BIT(2)
+#define MCP9600_ALERT_CFG_FALLING BIT(3)
+#define MCP9600_ALERT_CFG_COLD_JUNCTION BIT(4)
+#define MCP9600_ALERT_HYSTERESIS1 0xc
+#define MCP9600_ALERT_HYSTERESIS(x) (MCP9600_ALERT_HYSTERESIS1 + (x - 1))
+#define MCP9600_ALERT_LIMIT1 0x10
+#define MCP9600_ALERT_LIMIT(x) (MCP9600_ALERT_LIMIT1 + (x - 1))
+#define MCP9600_ALERT_LIMIT_MASK GENMASK(15, 2)
#define MCP9600_DEVICE_ID 0x20
/* MCP9600 device id value */
#define MCP9600_DEVICE_ID_MCP9600 0x40
-static const struct iio_chan_spec mcp9600_channels[] = {
+#define MCP9600_ALERT_COUNT 4
+
+#define MCP9600_MIN_TEMP_HOT_JUNCTION_MICRO -200000000
+#define MCP9600_MAX_TEMP_HOT_JUNCTION_MICRO 1800000000
+
+#define MCP9600_MIN_TEMP_COLD_JUNCTION_MICRO -40000000
+#define MCP9600_MAX_TEMP_COLD_JUNCTION_MICRO 125000000
+
+enum mcp9600_alert {
+ MCP9600_ALERT1,
+ MCP9600_ALERT2,
+ MCP9600_ALERT3,
+ MCP9600_ALERT4
+};
+
+static const char * const mcp9600_alert_name[MCP9600_ALERT_COUNT] = {
+ [MCP9600_ALERT1] = "alert1",
+ [MCP9600_ALERT2] = "alert2",
+ [MCP9600_ALERT3] = "alert3",
+ [MCP9600_ALERT4] = "alert4",
+};
+
+static const struct iio_event_spec mcp9600_events[] = {
{
- .type = IIO_TEMP,
- .address = MCP9600_HOT_JUNCTION,
- .info_mask_separate =
- BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_RISING,
+ .mask_separate = BIT(IIO_EV_INFO_ENABLE) |
+ BIT(IIO_EV_INFO_VALUE) |
+ BIT(IIO_EV_INFO_HYSTERESIS),
},
{
- .type = IIO_TEMP,
- .address = MCP9600_COLD_JUNCTION,
- .channel2 = IIO_MOD_TEMP_AMBIENT,
- .modified = 1,
- .info_mask_separate =
- BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_FALLING,
+ .mask_separate = BIT(IIO_EV_INFO_ENABLE) |
+ BIT(IIO_EV_INFO_VALUE) |
+ BIT(IIO_EV_INFO_HYSTERESIS),
},
};
+#define MCP9600_CHANNELS(hj_num_ev, hj_ev_spec_off, cj_num_ev, cj_ev_spec_off) \
+ { \
+ { \
+ .type = IIO_TEMP, \
+ .address = MCP9600_HOT_JUNCTION, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
+ .event_spec = &mcp9600_events[hj_ev_spec_off], \
+ .num_event_specs = hj_num_ev, \
+ }, \
+ { \
+ .type = IIO_TEMP, \
+ .address = MCP9600_COLD_JUNCTION, \
+ .channel2 = IIO_MOD_TEMP_AMBIENT, \
+ .modified = 1, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
+ .event_spec = &mcp9600_events[cj_ev_spec_off], \
+ .num_event_specs = cj_num_ev, \
+ }, \
+ }
+
+static const struct iio_chan_spec mcp9600_channels[][2] = {
+ MCP9600_CHANNELS(0, 0, 0, 0), /* Alerts: - - - - */
+ MCP9600_CHANNELS(1, 0, 0, 0), /* Alerts: 1 - - - */
+ MCP9600_CHANNELS(1, 1, 0, 0), /* Alerts: - 2 - - */
+ MCP9600_CHANNELS(2, 0, 0, 0), /* Alerts: 1 2 - - */
+ MCP9600_CHANNELS(0, 0, 1, 0), /* Alerts: - - 3 - */
+ MCP9600_CHANNELS(1, 0, 1, 0), /* Alerts: 1 - 3 - */
+ MCP9600_CHANNELS(1, 1, 1, 0), /* Alerts: - 2 3 - */
+ MCP9600_CHANNELS(2, 0, 1, 0), /* Alerts: 1 2 3 - */
+ MCP9600_CHANNELS(0, 0, 1, 1), /* Alerts: - - - 4 */
+ MCP9600_CHANNELS(1, 0, 1, 1), /* Alerts: 1 - - 4 */
+ MCP9600_CHANNELS(1, 1, 1, 1), /* Alerts: - 2 - 4 */
+ MCP9600_CHANNELS(2, 0, 1, 1), /* Alerts: 1 2 - 4 */
+ MCP9600_CHANNELS(0, 0, 2, 0), /* Alerts: - - 3 4 */
+ MCP9600_CHANNELS(1, 0, 2, 0), /* Alerts: 1 - 3 4 */
+ MCP9600_CHANNELS(1, 1, 2, 0), /* Alerts: - 2 3 4 */
+ MCP9600_CHANNELS(2, 0, 2, 0), /* Alerts: 1 2 3 4 */
+};
+
struct mcp9600_data {
struct i2c_client *client;
};
@@ -80,15 +164,261 @@ static int mcp9600_read_raw(struct iio_dev *indio_dev,
}
}
+static int mcp9600_get_alert_index(int channel2, enum iio_event_direction dir)
+{
+ if (channel2 == IIO_MOD_TEMP_AMBIENT) {
+ if (dir == IIO_EV_DIR_RISING)
+ return MCP9600_ALERT3;
+ else
+ return MCP9600_ALERT4;
+ } else {
+ if (dir == IIO_EV_DIR_RISING)
+ return MCP9600_ALERT1;
+ else
+ return MCP9600_ALERT2;
+ }
+}
+
+static int mcp9600_read_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir)
+{
+ struct mcp9600_data *data = iio_priv(indio_dev);
+ struct i2c_client *client = data->client;
+ int i, ret;
+
+ i = mcp9600_get_alert_index(chan->channel2, dir);
+ ret = i2c_smbus_read_byte_data(client, MCP9600_ALERT_CFG(i + 1));
+ if (ret < 0)
+ return ret;
+
+ return FIELD_GET(MCP9600_ALERT_CFG_ENABLE, ret);
+}
+
+static int mcp9600_write_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ int state)
+{
+ struct mcp9600_data *data = iio_priv(indio_dev);
+ struct i2c_client *client = data->client;
+ int i, ret;
+
+ i = mcp9600_get_alert_index(chan->channel2, dir);
+ ret = i2c_smbus_read_byte_data(client, MCP9600_ALERT_CFG(i + 1));
+ if (ret < 0)
+ return ret;
+
+ if (state)
+ ret |= MCP9600_ALERT_CFG_ENABLE;
+ else
+ ret &= ~MCP9600_ALERT_CFG_ENABLE;
+
+ return i2c_smbus_write_byte_data(client, MCP9600_ALERT_CFG(i + 1), ret);
+}
+
+static int mcp9600_read_thresh(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info, int *val, int *val2)
+{
+ struct mcp9600_data *data = iio_priv(indio_dev);
+ struct i2c_client *client = data->client;
+ s32 ret;
+ int i;
+
+ i = mcp9600_get_alert_index(chan->channel2, dir);
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ ret = i2c_smbus_read_word_swapped(client, MCP9600_ALERT_LIMIT(i + 1));
+ if (ret < 0)
+ return ret;
+ /*
+ * Temperature is stored in two’s complement format in
+ * bits(15:2), LSB is 0.25 degree celsius.
+ */
+ *val = sign_extend32(FIELD_GET(MCP9600_ALERT_LIMIT_MASK, ret), 13);
+ *val2 = 4;
+ return IIO_VAL_FRACTIONAL;
+ case IIO_EV_INFO_HYSTERESIS:
+ ret = i2c_smbus_read_byte_data(client, MCP9600_ALERT_HYSTERESIS(i + 1));
+ if (ret < 0)
+ return ret;
+
+ *val = ret;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int mcp9600_write_thresh(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info, int val, int val2)
+{
+ struct mcp9600_data *data = iio_priv(indio_dev);
+ struct i2c_client *client = data->client;
+ int s_val, i;
+ s16 thresh;
+ u8 hyst;
+
+ i = mcp9600_get_alert_index(chan->channel2, dir);
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ /* Scale value to include decimal part into calculations */
+ s_val = (val < 0) ? ((val * 1000000) - val2) :
+ ((val * 1000000) + val2);
+ if (chan->channel2 == IIO_MOD_TEMP_AMBIENT) {
+ s_val = max(s_val, MCP9600_MIN_TEMP_COLD_JUNCTION_MICRO);
+ s_val = min(s_val, MCP9600_MAX_TEMP_COLD_JUNCTION_MICRO);
+ } else {
+ s_val = max(s_val, MCP9600_MIN_TEMP_HOT_JUNCTION_MICRO);
+ s_val = min(s_val, MCP9600_MAX_TEMP_HOT_JUNCTION_MICRO);
+ }
+
+ /*
+ * Shift length 4 bits = 2(15:2) + 2(0.25 LSB), temperature is
+ * stored in two’s complement format.
+ */
+ thresh = (s16)(s_val / (1000000 >> 4));
+ return i2c_smbus_write_word_swapped(client,
+ MCP9600_ALERT_LIMIT(i + 1),
+ thresh);
+ case IIO_EV_INFO_HYSTERESIS:
+ hyst = min(abs(val), 255);
+ return i2c_smbus_write_byte_data(client,
+ MCP9600_ALERT_HYSTERESIS(i + 1),
+ hyst);
+ default:
+ return -EINVAL;
+ }
+}
+
static const struct iio_info mcp9600_info = {
.read_raw = mcp9600_read_raw,
+ .read_event_config = mcp9600_read_event_config,
+ .write_event_config = mcp9600_write_event_config,
+ .read_event_value = mcp9600_read_thresh,
+ .write_event_value = mcp9600_write_thresh,
};
+static irqreturn_t mcp9600_alert_handler(void *private,
+ enum mcp9600_alert alert,
+ enum iio_modifier mod,
+ enum iio_event_direction dir)
+{
+ struct iio_dev *indio_dev = private;
+ struct mcp9600_data *data = iio_priv(indio_dev);
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(data->client, MCP9600_STATUS);
+ if (ret < 0)
+ return IRQ_HANDLED;
+
+ if (!(ret & MCP9600_STATUS_ALERT(alert)))
+ return IRQ_NONE;
+
+ iio_push_event(indio_dev,
+ IIO_MOD_EVENT_CODE(IIO_TEMP, 0, mod, IIO_EV_TYPE_THRESH,
+ dir),
+ iio_get_time_ns(indio_dev));
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t mcp9600_alert1_handler(int irq, void *private)
+{
+ return mcp9600_alert_handler(private, MCP9600_ALERT1, IIO_NO_MOD,
+ IIO_EV_DIR_RISING);
+}
+
+static irqreturn_t mcp9600_alert2_handler(int irq, void *private)
+{
+ return mcp9600_alert_handler(private, MCP9600_ALERT2, IIO_NO_MOD,
+ IIO_EV_DIR_FALLING);
+}
+
+static irqreturn_t mcp9600_alert3_handler(int irq, void *private)
+{
+ return mcp9600_alert_handler(private, MCP9600_ALERT3,
+ IIO_MOD_TEMP_AMBIENT, IIO_EV_DIR_RISING);
+}
+
+static irqreturn_t mcp9600_alert4_handler(int irq, void *private)
+{
+ return mcp9600_alert_handler(private, MCP9600_ALERT4,
+ IIO_MOD_TEMP_AMBIENT, IIO_EV_DIR_FALLING);
+}
+
+static irqreturn_t (*mcp9600_alert_handler_func[MCP9600_ALERT_COUNT]) (int, void *) = {
+ mcp9600_alert1_handler,
+ mcp9600_alert2_handler,
+ mcp9600_alert3_handler,
+ mcp9600_alert4_handler,
+};
+
+static int mcp9600_probe_alerts(struct iio_dev *indio_dev)
+{
+ struct mcp9600_data *data = iio_priv(indio_dev);
+ struct i2c_client *client = data->client;
+ struct device *dev = &client->dev;
+ struct fwnode_handle *fwnode = dev_fwnode(dev);
+ unsigned int irq_type;
+ int ret, irq, i;
+ u8 val, ch_sel;
+
+ /*
+ * alert1: hot junction, rising temperature
+ * alert2: hot junction, falling temperature
+ * alert3: cold junction, rising temperature
+ * alert4: cold junction, falling temperature
+ */
+ ch_sel = 0;
+ for (i = 0; i < MCP9600_ALERT_COUNT; i++) {
+ irq = fwnode_irq_get_byname(fwnode, mcp9600_alert_name[i]);
+ if (irq <= 0)
+ continue;
+
+ val = 0;
+ irq_type = irq_get_trigger_type(irq);
+ if (irq_type == IRQ_TYPE_EDGE_RISING)
+ val |= MCP9600_ALERT_CFG_ACTIVE_HIGH;
+
+ if (i == MCP9600_ALERT2 || i == MCP9600_ALERT4)
+ val |= MCP9600_ALERT_CFG_FALLING;
+
+ if (i == MCP9600_ALERT3 || i == MCP9600_ALERT4)
+ val |= MCP9600_ALERT_CFG_COLD_JUNCTION;
+
+ ret = i2c_smbus_write_byte_data(client,
+ MCP9600_ALERT_CFG(i + 1),
+ val);
+ if (ret < 0)
+ return ret;
+
+ ret = devm_request_threaded_irq(dev, irq, NULL,
+ mcp9600_alert_handler_func[i],
+ IRQF_ONESHOT, "mcp9600",
+ indio_dev);
+ if (ret)
+ return ret;
+
+ ch_sel |= BIT(i);
+ }
+
+ return ch_sel;
+}
+
static int mcp9600_probe(struct i2c_client *client)
{
struct iio_dev *indio_dev;
struct mcp9600_data *data;
- int ret;
+ int ret, ch_sel;
ret = i2c_smbus_read_byte_data(client, MCP9600_DEVICE_ID);
if (ret < 0)
@@ -104,11 +434,15 @@ static int mcp9600_probe(struct i2c_client *client)
data = iio_priv(indio_dev);
data->client = client;
+ ch_sel = mcp9600_probe_alerts(indio_dev);
+ if (ch_sel < 0)
+ return ch_sel;
+
indio_dev->info = &mcp9600_info;
indio_dev->name = "mcp9600";
indio_dev->modes = INDIO_DIRECT_MODE;
- indio_dev->channels = mcp9600_channels;
- indio_dev->num_channels = ARRAY_SIZE(mcp9600_channels);
+ indio_dev->channels = mcp9600_channels[ch_sel];
+ indio_dev->num_channels = ARRAY_SIZE(mcp9600_channels[ch_sel]);
return devm_iio_device_register(&client->dev, indio_dev);
}
@@ -135,6 +469,7 @@ static struct i2c_driver mcp9600_driver = {
};
module_i2c_driver(mcp9600_driver);
+MODULE_AUTHOR("Dimitri Fedrau <dima.fedrau@gmail.com>");
MODULE_AUTHOR("Andrew Hepp <andrew.hepp@ahepp.dev>");
MODULE_DESCRIPTION("Microchip MCP9600 thermocouple EMF converter driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/iio/temperature/mlx90632.c b/drivers/iio/temperature/mlx90632.c
index 8a57be108620..4676e0edde4a 100644
--- a/drivers/iio/temperature/mlx90632.c
+++ b/drivers/iio/temperature/mlx90632.c
@@ -1279,7 +1279,7 @@ static int mlx90632_probe(struct i2c_client *client)
}
static const struct i2c_device_id mlx90632_id[] = {
- { "mlx90632", 0 },
+ { "mlx90632" },
{ }
};
MODULE_DEVICE_TABLE(i2c, mlx90632_id);
diff --git a/drivers/iio/temperature/tmp006.c b/drivers/iio/temperature/tmp006.c
index 3a3904fe138c..6d8d661f0c82 100644
--- a/drivers/iio/temperature/tmp006.c
+++ b/drivers/iio/temperature/tmp006.c
@@ -280,7 +280,7 @@ static const struct of_device_id tmp006_of_match[] = {
MODULE_DEVICE_TABLE(of, tmp006_of_match);
static const struct i2c_device_id tmp006_id[] = {
- { "tmp006", 0 },
+ { "tmp006" },
{ }
};
MODULE_DEVICE_TABLE(i2c, tmp006_id);
diff --git a/drivers/iio/temperature/tmp007.c b/drivers/iio/temperature/tmp007.c
index decef6896362..9bdfa9423492 100644
--- a/drivers/iio/temperature/tmp007.c
+++ b/drivers/iio/temperature/tmp007.c
@@ -563,7 +563,7 @@ static const struct of_device_id tmp007_of_match[] = {
MODULE_DEVICE_TABLE(of, tmp007_of_match);
static const struct i2c_device_id tmp007_id[] = {
- { "tmp007", 0 },
+ { "tmp007" },
{ }
};
MODULE_DEVICE_TABLE(i2c, tmp007_id);
diff --git a/drivers/iio/temperature/tsys01.c b/drivers/iio/temperature/tsys01.c
index 53ef56fbfe1d..9213761c5d18 100644
--- a/drivers/iio/temperature/tsys01.c
+++ b/drivers/iio/temperature/tsys01.c
@@ -206,7 +206,7 @@ static int tsys01_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id tsys01_id[] = {
- {"tsys01", 0},
+ { "tsys01" },
{}
};
MODULE_DEVICE_TABLE(i2c, tsys01_id);
diff --git a/drivers/iio/temperature/tsys02d.c b/drivers/iio/temperature/tsys02d.c
index 6191db92ef9a..2b4959d6e467 100644
--- a/drivers/iio/temperature/tsys02d.c
+++ b/drivers/iio/temperature/tsys02d.c
@@ -168,7 +168,7 @@ static int tsys02d_probe(struct i2c_client *client)
}
static const struct i2c_device_id tsys02d_id[] = {
- {"tsys02d", 0},
+ { "tsys02d" },
{}
};
MODULE_DEVICE_TABLE(i2c, tsys02d_id);
diff --git a/drivers/iio/test/iio-test-gts.c b/drivers/iio/test/iio-test-gts.c
index cf7ab773ea0b..5f16a7b5e6d4 100644
--- a/drivers/iio/test/iio-test-gts.c
+++ b/drivers/iio/test/iio-test-gts.c
@@ -70,6 +70,7 @@
*/
static struct iio_gts gts;
+/* Keep the gain and time tables unsorted to test the sorting */
static const struct iio_gain_sel_pair gts_test_gains[] = {
GAIN_SCALE_GAIN(1, TEST_GSEL_1),
GAIN_SCALE_GAIN(4, TEST_GSEL_4),
@@ -79,16 +80,17 @@ static const struct iio_gain_sel_pair gts_test_gains[] = {
GAIN_SCALE_GAIN(256, TEST_GSEL_256),
GAIN_SCALE_GAIN(512, TEST_GSEL_512),
GAIN_SCALE_GAIN(1024, TEST_GSEL_1024),
- GAIN_SCALE_GAIN(2048, TEST_GSEL_2048),
GAIN_SCALE_GAIN(4096, TEST_GSEL_4096),
+ GAIN_SCALE_GAIN(2048, TEST_GSEL_2048),
#define HWGAIN_MAX 4096
};
static const struct iio_itime_sel_mul gts_test_itimes[] = {
- GAIN_SCALE_ITIME_US(400 * 1000, TEST_TSEL_400, 8),
- GAIN_SCALE_ITIME_US(200 * 1000, TEST_TSEL_200, 4),
GAIN_SCALE_ITIME_US(100 * 1000, TEST_TSEL_100, 2),
+ GAIN_SCALE_ITIME_US(400 * 1000, TEST_TSEL_400, 8),
+ GAIN_SCALE_ITIME_US(400 * 1000, TEST_TSEL_400, 8),
GAIN_SCALE_ITIME_US(50 * 1000, TEST_TSEL_50, 1),
+ GAIN_SCALE_ITIME_US(200 * 1000, TEST_TSEL_200, 4),
#define TIMEGAIN_MAX 8
};
#define TOTAL_GAIN_MAX (HWGAIN_MAX * TIMEGAIN_MAX)
diff --git a/drivers/mcb/mcb-pci.c b/drivers/mcb/mcb-pci.c
index 53d9202ff9a7..3b634ea318c7 100644
--- a/drivers/mcb/mcb-pci.c
+++ b/drivers/mcb/mcb-pci.c
@@ -45,6 +45,14 @@ static int mcb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
}
pci_set_master(pdev);
+ flags = pci_resource_flags(pdev, 0);
+ if (flags & IORESOURCE_IO) {
+ ret = -ENOTSUPP;
+ dev_err(&pdev->dev,
+ "IO mapped PCI devices are not supported\n");
+ goto out_disable;
+ }
+
priv->mapbase = pci_resource_start(pdev, 0);
if (!priv->mapbase) {
dev_err(&pdev->dev, "No PCI resource\n");
@@ -68,14 +76,6 @@ static int mcb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto out_disable;
}
- flags = pci_resource_flags(pdev, 0);
- if (flags & IORESOURCE_IO) {
- ret = -ENOTSUPP;
- dev_err(&pdev->dev,
- "IO mapped PCI devices are not supported\n");
- goto out_disable;
- }
-
pci_set_drvdata(pdev, priv);
priv->bus = mcb_alloc_bus(&pdev->dev);
diff --git a/drivers/misc/eeprom/digsy_mtc_eeprom.c b/drivers/misc/eeprom/digsy_mtc_eeprom.c
index f1f766b70965..88888485e6f8 100644
--- a/drivers/misc/eeprom/digsy_mtc_eeprom.c
+++ b/drivers/misc/eeprom/digsy_mtc_eeprom.c
@@ -14,13 +14,12 @@
* and delete this driver.
*/
-#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/init.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_gpio.h>
-#include <linux/eeprom_93xx46.h>
#define GPIO_EEPROM_CLK 216
#define GPIO_EEPROM_CS 210
@@ -29,22 +28,13 @@
#define GPIO_EEPROM_OE 255
#define EE_SPI_BUS_NUM 1
-static void digsy_mtc_op_prepare(void *p)
-{
- /* enable */
- gpio_set_value(GPIO_EEPROM_OE, 0);
-}
-
-static void digsy_mtc_op_finish(void *p)
-{
- /* disable */
- gpio_set_value(GPIO_EEPROM_OE, 1);
-}
+static const struct property_entry digsy_mtc_spi_properties[] = {
+ PROPERTY_ENTRY_U32("data-size", 8),
+ { }
+};
-struct eeprom_93xx46_platform_data digsy_mtc_eeprom_data = {
- .flags = EE_ADDR8,
- .prepare = digsy_mtc_op_prepare,
- .finish = digsy_mtc_op_finish,
+static const struct software_node digsy_mtc_spi_node = {
+ .properties = digsy_mtc_spi_properties,
};
static struct spi_gpio_platform_data eeprom_spi_gpio_data = {
@@ -70,18 +60,19 @@ static struct gpiod_lookup_table eeprom_spi_gpiod_table = {
"miso", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("gpio@b00", GPIO_EEPROM_CS,
"cs", GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP("gpio@b00", GPIO_EEPROM_OE,
+ "select", GPIO_ACTIVE_LOW),
{ },
},
};
static struct spi_board_info digsy_mtc_eeprom_info[] __initdata = {
{
- .modalias = "93xx46",
+ .modalias = "eeprom-93xx46",
.max_speed_hz = 1000000,
.bus_num = EE_SPI_BUS_NUM,
.chip_select = 0,
.mode = SPI_MODE_0,
- .platform_data = &digsy_mtc_eeprom_data,
},
};
@@ -89,15 +80,18 @@ static int __init digsy_mtc_eeprom_devices_init(void)
{
int ret;
- ret = gpio_request_one(GPIO_EEPROM_OE, GPIOF_OUT_INIT_HIGH,
- "93xx46 EEPROMs OE");
- if (ret) {
- pr_err("can't request gpio %d\n", GPIO_EEPROM_OE);
- return ret;
- }
gpiod_add_lookup_table(&eeprom_spi_gpiod_table);
spi_register_board_info(digsy_mtc_eeprom_info,
ARRAY_SIZE(digsy_mtc_eeprom_info));
- return platform_device_register(&digsy_mtc_eeprom);
+
+ ret = device_add_software_node(&digsy_mtc_eeprom.dev, &digsy_mtc_spi_node);
+ if (ret)
+ return ret;
+
+ ret = platform_device_register(&digsy_mtc_eeprom);
+ if (ret)
+ device_remove_software_node(&digsy_mtc_eeprom.dev);
+
+ return ret;
}
device_initcall(digsy_mtc_eeprom_devices_init);
diff --git a/drivers/misc/eeprom/ee1004.c b/drivers/misc/eeprom/ee1004.c
index 21feebc3044c..bf4f65dc6d9a 100644
--- a/drivers/misc/eeprom/ee1004.c
+++ b/drivers/misc/eeprom/ee1004.c
@@ -52,7 +52,7 @@ static struct ee1004_bus_data {
} ee1004_bus_data[EE1004_MAX_BUSSES];
static const struct i2c_device_id ee1004_ids[] = {
- { "ee1004", 0 },
+ { "ee1004" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ee1004_ids);
diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c
index 45c8ae0db8f9..e2221be88445 100644
--- a/drivers/misc/eeprom/eeprom_93xx46.c
+++ b/drivers/misc/eeprom/eeprom_93xx46.c
@@ -5,19 +5,42 @@
* (C) 2011 DENX Software Engineering, Anatolij Gustschin <agust@denx.de>
*/
+#include <linux/array_size.h>
+#include <linux/bits.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/gpio/consumer.h>
-#include <linux/kernel.h>
+#include <linux/kstrtox.h>
#include <linux/log2.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
+#include <linux/property.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
+#include <linux/string_choices.h>
+
#include <linux/nvmem-provider.h>
-#include <linux/eeprom_93xx46.h>
+
+struct eeprom_93xx46_platform_data {
+ unsigned char flags;
+#define EE_ADDR8 0x01 /* 8 bit addr. cfg */
+#define EE_ADDR16 0x02 /* 16 bit addr. cfg */
+#define EE_READONLY 0x08 /* forbid writing */
+#define EE_SIZE1K 0x10 /* 1 kb of data, that is a 93xx46 */
+#define EE_SIZE2K 0x20 /* 2 kb of data, that is a 93xx56 */
+#define EE_SIZE4K 0x40 /* 4 kb of data, that is a 93xx66 */
+
+ unsigned int quirks;
+/* Single word read transfers only; no sequential read. */
+#define EEPROM_93XX46_QUIRK_SINGLE_WORD_READ (1 << 0)
+/* Instructions such as EWEN are (addrlen + 2) in length. */
+#define EEPROM_93XX46_QUIRK_INSTRUCTION_LENGTH (1 << 1)
+/* Add extra cycle after address during a read */
+#define EEPROM_93XX46_QUIRK_EXTRA_READ_CYCLE BIT(2)
+
+ struct gpio_desc *select;
+};
#define OP_START 0x4
#define OP_WRITE (OP_START | 0x1)
@@ -96,15 +119,14 @@ static int eeprom_93xx46_read(void *priv, unsigned int off,
mutex_lock(&edev->lock);
- if (edev->pdata->prepare)
- edev->pdata->prepare(edev);
+ gpiod_set_value_cansleep(edev->pdata->select, 1);
/* The opcode in front of the address is three bits. */
bits = edev->addrlen + 3;
while (count) {
struct spi_message m;
- struct spi_transfer t[2] = { { 0 } };
+ struct spi_transfer t[2] = {};
u16 cmd_addr = OP_READ << edev->addrlen;
size_t nbytes = count;
@@ -126,25 +148,23 @@ static int eeprom_93xx46_read(void *priv, unsigned int off,
bits += 1;
}
- spi_message_init(&m);
-
t[0].tx_buf = (char *)&cmd_addr;
t[0].len = 2;
t[0].bits_per_word = bits;
- spi_message_add_tail(&t[0], &m);
t[1].rx_buf = buf;
t[1].len = count;
t[1].bits_per_word = 8;
- spi_message_add_tail(&t[1], &m);
+
+ spi_message_init_with_transfers(&m, t, ARRAY_SIZE(t));
err = spi_sync(edev->spi, &m);
/* have to wait at least Tcsl ns */
ndelay(250);
if (err) {
- dev_err(&edev->spi->dev, "read %zu bytes at %d: err. %d\n",
- nbytes, (int)off, err);
+ dev_err(&edev->spi->dev, "read %zu bytes at %u: err. %d\n",
+ nbytes, off, err);
break;
}
@@ -153,8 +173,7 @@ static int eeprom_93xx46_read(void *priv, unsigned int off,
count -= nbytes;
}
- if (edev->pdata->finish)
- edev->pdata->finish(edev);
+ gpiod_set_value_cansleep(edev->pdata->select, 0);
mutex_unlock(&edev->lock);
@@ -164,7 +183,7 @@ static int eeprom_93xx46_read(void *priv, unsigned int off,
static int eeprom_93xx46_ew(struct eeprom_93xx46_dev *edev, int is_on)
{
struct spi_message m;
- struct spi_transfer t;
+ struct spi_transfer t = {};
int bits, ret;
u16 cmd_addr;
@@ -182,31 +201,27 @@ static int eeprom_93xx46_ew(struct eeprom_93xx46_dev *edev, int is_on)
bits += 2;
}
- dev_dbg(&edev->spi->dev, "ew%s cmd 0x%04x, %d bits\n",
- is_on ? "en" : "ds", cmd_addr, bits);
-
- spi_message_init(&m);
- memset(&t, 0, sizeof(t));
+ dev_dbg(&edev->spi->dev, "ew %s cmd 0x%04x, %d bits\n",
+ str_enable_disable(is_on), cmd_addr, bits);
t.tx_buf = &cmd_addr;
t.len = 2;
t.bits_per_word = bits;
- spi_message_add_tail(&t, &m);
+
+ spi_message_init_with_transfers(&m, &t, 1);
mutex_lock(&edev->lock);
- if (edev->pdata->prepare)
- edev->pdata->prepare(edev);
+ gpiod_set_value_cansleep(edev->pdata->select, 1);
ret = spi_sync(edev->spi, &m);
/* have to wait at least Tcsl ns */
ndelay(250);
if (ret)
- dev_err(&edev->spi->dev, "erase/write %sable error %d\n",
- is_on ? "en" : "dis", ret);
+ dev_err(&edev->spi->dev, "erase/write %s error %d\n",
+ str_enable_disable(is_on), ret);
- if (edev->pdata->finish)
- edev->pdata->finish(edev);
+ gpiod_set_value_cansleep(edev->pdata->select, 0);
mutex_unlock(&edev->lock);
return ret;
@@ -217,7 +232,7 @@ eeprom_93xx46_write_word(struct eeprom_93xx46_dev *edev,
const char *buf, unsigned off)
{
struct spi_message m;
- struct spi_transfer t[2];
+ struct spi_transfer t[2] = {};
int bits, data_len, ret;
u16 cmd_addr;
@@ -239,18 +254,15 @@ eeprom_93xx46_write_word(struct eeprom_93xx46_dev *edev,
dev_dbg(&edev->spi->dev, "write cmd 0x%x\n", cmd_addr);
- spi_message_init(&m);
- memset(t, 0, sizeof(t));
-
t[0].tx_buf = (char *)&cmd_addr;
t[0].len = 2;
t[0].bits_per_word = bits;
- spi_message_add_tail(&t[0], &m);
t[1].tx_buf = buf;
t[1].len = data_len;
t[1].bits_per_word = 8;
- spi_message_add_tail(&t[1], &m);
+
+ spi_message_init_with_transfers(&m, t, ARRAY_SIZE(t));
ret = spi_sync(edev->spi, &m);
/* have to wait program cycle time Twc ms */
@@ -263,7 +275,8 @@ static int eeprom_93xx46_write(void *priv, unsigned int off,
{
struct eeprom_93xx46_dev *edev = priv;
char *buf = val;
- int i, ret, step = 1;
+ int ret, step = 1;
+ unsigned int i;
if (unlikely(off >= edev->size))
return -EFBIG;
@@ -285,20 +298,17 @@ static int eeprom_93xx46_write(void *priv, unsigned int off,
mutex_lock(&edev->lock);
- if (edev->pdata->prepare)
- edev->pdata->prepare(edev);
+ gpiod_set_value_cansleep(edev->pdata->select, 1);
for (i = 0; i < count; i += step) {
ret = eeprom_93xx46_write_word(edev, &buf[i], off + i);
if (ret) {
- dev_err(&edev->spi->dev, "write failed at %d: %d\n",
- (int)off + i, ret);
+ dev_err(&edev->spi->dev, "write failed at %u: %d\n", off + i, ret);
break;
}
}
- if (edev->pdata->finish)
- edev->pdata->finish(edev);
+ gpiod_set_value_cansleep(edev->pdata->select, 0);
mutex_unlock(&edev->lock);
@@ -309,9 +319,8 @@ static int eeprom_93xx46_write(void *priv, unsigned int off,
static int eeprom_93xx46_eral(struct eeprom_93xx46_dev *edev)
{
- struct eeprom_93xx46_platform_data *pd = edev->pdata;
struct spi_message m;
- struct spi_transfer t;
+ struct spi_transfer t = {};
int bits, ret;
u16 cmd_addr;
@@ -331,18 +340,15 @@ static int eeprom_93xx46_eral(struct eeprom_93xx46_dev *edev)
dev_dbg(&edev->spi->dev, "eral cmd 0x%04x, %d bits\n", cmd_addr, bits);
- spi_message_init(&m);
- memset(&t, 0, sizeof(t));
-
t.tx_buf = &cmd_addr;
t.len = 2;
t.bits_per_word = bits;
- spi_message_add_tail(&t, &m);
+
+ spi_message_init_with_transfers(&m, &t, 1);
mutex_lock(&edev->lock);
- if (edev->pdata->prepare)
- edev->pdata->prepare(edev);
+ gpiod_set_value_cansleep(edev->pdata->select, 1);
ret = spi_sync(edev->spi, &m);
if (ret)
@@ -350,21 +356,23 @@ static int eeprom_93xx46_eral(struct eeprom_93xx46_dev *edev)
/* have to wait erase cycle time Tec ms */
mdelay(6);
- if (pd->finish)
- pd->finish(edev);
+ gpiod_set_value_cansleep(edev->pdata->select, 0);
mutex_unlock(&edev->lock);
return ret;
}
-static ssize_t eeprom_93xx46_store_erase(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t erase_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct eeprom_93xx46_dev *edev = dev_get_drvdata(dev);
- int erase = 0, ret;
+ bool erase;
+ int ret;
+
+ ret = kstrtobool(buf, &erase);
+ if (ret)
+ return ret;
- sscanf(buf, "%d", &erase);
if (erase) {
ret = eeprom_93xx46_ew(edev, 1);
if (ret)
@@ -378,21 +386,7 @@ static ssize_t eeprom_93xx46_store_erase(struct device *dev,
}
return count;
}
-static DEVICE_ATTR(erase, S_IWUSR, NULL, eeprom_93xx46_store_erase);
-
-static void select_assert(void *context)
-{
- struct eeprom_93xx46_dev *edev = context;
-
- gpiod_set_value_cansleep(edev->pdata->select, 1);
-}
-
-static void select_deassert(void *context)
-{
- struct eeprom_93xx46_dev *edev = context;
-
- gpiod_set_value_cansleep(edev->pdata->select, 0);
-}
+static DEVICE_ATTR_WO(erase);
static const struct of_device_id eeprom_93xx46_of_table[] = {
{ .compatible = "eeprom-93xx46", .data = &at93c46_data, },
@@ -422,22 +416,20 @@ static const struct spi_device_id eeprom_93xx46_spi_ids[] = {
};
MODULE_DEVICE_TABLE(spi, eeprom_93xx46_spi_ids);
-static int eeprom_93xx46_probe_dt(struct spi_device *spi)
+static int eeprom_93xx46_probe_fw(struct device *dev)
{
- const struct of_device_id *of_id =
- of_match_device(eeprom_93xx46_of_table, &spi->dev);
- struct device_node *np = spi->dev.of_node;
+ const struct eeprom_93xx46_devtype_data *data;
struct eeprom_93xx46_platform_data *pd;
u32 tmp;
int ret;
- pd = devm_kzalloc(&spi->dev, sizeof(*pd), GFP_KERNEL);
+ pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
if (!pd)
return -ENOMEM;
- ret = of_property_read_u32(np, "data-size", &tmp);
+ ret = device_property_read_u32(dev, "data-size", &tmp);
if (ret < 0) {
- dev_err(&spi->dev, "data-size property not found\n");
+ dev_err(dev, "data-size property not found\n");
return ret;
}
@@ -446,30 +438,25 @@ static int eeprom_93xx46_probe_dt(struct spi_device *spi)
} else if (tmp == 16) {
pd->flags |= EE_ADDR16;
} else {
- dev_err(&spi->dev, "invalid data-size (%d)\n", tmp);
+ dev_err(dev, "invalid data-size (%d)\n", tmp);
return -EINVAL;
}
- if (of_property_read_bool(np, "read-only"))
+ if (device_property_read_bool(dev, "read-only"))
pd->flags |= EE_READONLY;
- pd->select = devm_gpiod_get_optional(&spi->dev, "select",
- GPIOD_OUT_LOW);
+ pd->select = devm_gpiod_get_optional(dev, "select", GPIOD_OUT_LOW);
if (IS_ERR(pd->select))
return PTR_ERR(pd->select);
+ gpiod_set_consumer_name(pd->select, "93xx46 EEPROMs OE");
- pd->prepare = select_assert;
- pd->finish = select_deassert;
- gpiod_direction_output(pd->select, 0);
-
- if (of_id->data) {
- const struct eeprom_93xx46_devtype_data *data = of_id->data;
-
+ data = spi_get_device_match_data(to_spi_device(dev));
+ if (data) {
pd->quirks = data->quirks;
pd->flags |= data->flags;
}
- spi->dev.platform_data = pd;
+ dev->platform_data = pd;
return 0;
}
@@ -478,13 +465,12 @@ static int eeprom_93xx46_probe(struct spi_device *spi)
{
struct eeprom_93xx46_platform_data *pd;
struct eeprom_93xx46_dev *edev;
+ struct device *dev = &spi->dev;
int err;
- if (spi->dev.of_node) {
- err = eeprom_93xx46_probe_dt(spi);
- if (err < 0)
- return err;
- }
+ err = eeprom_93xx46_probe_fw(dev);
+ if (err < 0)
+ return err;
pd = spi->dev.platform_data;
if (!pd) {
@@ -565,7 +551,7 @@ static void eeprom_93xx46_remove(struct spi_device *spi)
static struct spi_driver eeprom_93xx46_driver = {
.driver = {
.name = "93xx46",
- .of_match_table = of_match_ptr(eeprom_93xx46_of_table),
+ .of_match_table = eeprom_93xx46_of_table,
},
.probe = eeprom_93xx46_probe,
.remove = eeprom_93xx46_remove,
diff --git a/drivers/misc/eeprom/idt_89hpesx.c b/drivers/misc/eeprom/idt_89hpesx.c
index 327afb866b21..43421fe37d33 100644
--- a/drivers/misc/eeprom/idt_89hpesx.c
+++ b/drivers/misc/eeprom/idt_89hpesx.c
@@ -1426,58 +1426,58 @@ MODULE_DEVICE_TABLE(i2c, ee_ids);
* idt_ids - supported IDT 89HPESx devices
*/
static const struct i2c_device_id idt_ids[] = {
- { "89hpes8nt2", 0 },
- { "89hpes12nt3", 0 },
-
- { "89hpes24nt6ag2", 0 },
- { "89hpes32nt8ag2", 0 },
- { "89hpes32nt8bg2", 0 },
- { "89hpes12nt12g2", 0 },
- { "89hpes16nt16g2", 0 },
- { "89hpes24nt24g2", 0 },
- { "89hpes32nt24ag2", 0 },
- { "89hpes32nt24bg2", 0 },
-
- { "89hpes12n3", 0 },
- { "89hpes12n3a", 0 },
- { "89hpes24n3", 0 },
- { "89hpes24n3a", 0 },
-
- { "89hpes32h8", 0 },
- { "89hpes32h8g2", 0 },
- { "89hpes48h12", 0 },
- { "89hpes48h12g2", 0 },
- { "89hpes48h12ag2", 0 },
- { "89hpes16h16", 0 },
- { "89hpes22h16", 0 },
- { "89hpes22h16g2", 0 },
- { "89hpes34h16", 0 },
- { "89hpes34h16g2", 0 },
- { "89hpes64h16", 0 },
- { "89hpes64h16g2", 0 },
- { "89hpes64h16ag2", 0 },
-
- /* { "89hpes3t3", 0 }, // No SMBus-slave iface */
- { "89hpes12t3g2", 0 },
- { "89hpes24t3g2", 0 },
- /* { "89hpes4t4", 0 }, // No SMBus-slave iface */
- { "89hpes16t4", 0 },
- { "89hpes4t4g2", 0 },
- { "89hpes10t4g2", 0 },
- { "89hpes16t4g2", 0 },
- { "89hpes16t4ag2", 0 },
- { "89hpes5t5", 0 },
- { "89hpes6t5", 0 },
- { "89hpes8t5", 0 },
- { "89hpes8t5a", 0 },
- { "89hpes24t6", 0 },
- { "89hpes6t6g2", 0 },
- { "89hpes24t6g2", 0 },
- { "89hpes16t7", 0 },
- { "89hpes32t8", 0 },
- { "89hpes32t8g2", 0 },
- { "89hpes48t12", 0 },
- { "89hpes48t12g2", 0 },
+ { "89hpes8nt2" },
+ { "89hpes12nt3" },
+
+ { "89hpes24nt6ag2" },
+ { "89hpes32nt8ag2" },
+ { "89hpes32nt8bg2" },
+ { "89hpes12nt12g2" },
+ { "89hpes16nt16g2" },
+ { "89hpes24nt24g2" },
+ { "89hpes32nt24ag2" },
+ { "89hpes32nt24bg2" },
+
+ { "89hpes12n3" },
+ { "89hpes12n3a" },
+ { "89hpes24n3" },
+ { "89hpes24n3a" },
+
+ { "89hpes32h8" },
+ { "89hpes32h8g2" },
+ { "89hpes48h12" },
+ { "89hpes48h12g2" },
+ { "89hpes48h12ag2" },
+ { "89hpes16h16" },
+ { "89hpes22h16" },
+ { "89hpes22h16g2" },
+ { "89hpes34h16" },
+ { "89hpes34h16g2" },
+ { "89hpes64h16" },
+ { "89hpes64h16g2" },
+ { "89hpes64h16ag2" },
+
+ /* { "89hpes3t3" }, // No SMBus-slave iface */
+ { "89hpes12t3g2" },
+ { "89hpes24t3g2" },
+ /* { "89hpes4t4" }, // No SMBus-slave iface */
+ { "89hpes16t4" },
+ { "89hpes4t4g2" },
+ { "89hpes10t4g2" },
+ { "89hpes16t4g2" },
+ { "89hpes16t4ag2" },
+ { "89hpes5t5" },
+ { "89hpes6t5" },
+ { "89hpes8t5" },
+ { "89hpes8t5a" },
+ { "89hpes24t6" },
+ { "89hpes6t6g2" },
+ { "89hpes24t6g2" },
+ { "89hpes16t7" },
+ { "89hpes32t8" },
+ { "89hpes32t8g2" },
+ { "89hpes48t12" },
+ { "89hpes48t12g2" },
{ /* END OF LIST */ }
};
MODULE_DEVICE_TABLE(i2c, idt_ids);
diff --git a/drivers/misc/eeprom/max6875.c b/drivers/misc/eeprom/max6875.c
index cb6b1efeafe0..6fab2ffa736b 100644
--- a/drivers/misc/eeprom/max6875.c
+++ b/drivers/misc/eeprom/max6875.c
@@ -183,7 +183,7 @@ static void max6875_remove(struct i2c_client *client)
}
static const struct i2c_device_id max6875_id[] = {
- { "max6875", 0 },
+ { "max6875" },
{ }
};
MODULE_DEVICE_TABLE(i2c, max6875_id);
diff --git a/drivers/misc/open-dice.c b/drivers/misc/open-dice.c
index 1e3eb2aa44d9..e6a61e6d9427 100644
--- a/drivers/misc/open-dice.c
+++ b/drivers/misc/open-dice.c
@@ -201,5 +201,6 @@ static void __exit open_dice_exit(void)
module_init(open_dice_init);
module_exit(open_dice_exit);
+MODULE_DESCRIPTION("Driver for Open Profile for DICE.");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("David Brazdil <dbrazdil@google.com>");
diff --git a/drivers/parport/share.c b/drivers/parport/share.c
index 49c74ded8a53..b7148517e076 100644
--- a/drivers/parport/share.c
+++ b/drivers/parport/share.c
@@ -1219,4 +1219,5 @@ irqreturn_t parport_irq_handler(int irq, void *dev_id)
}
EXPORT_SYMBOL(parport_irq_handler);
+MODULE_DESCRIPTION("Parallel-port resource manager");
MODULE_LICENSE("GPL");
diff --git a/drivers/siox/siox-bus-gpio.c b/drivers/siox/siox-bus-gpio.c
index 9e01642e72de..d6f936464063 100644
--- a/drivers/siox/siox-bus-gpio.c
+++ b/drivers/siox/siox-bus-gpio.c
@@ -148,5 +148,6 @@ static struct platform_driver siox_gpio_driver = {
module_platform_driver(siox_gpio_driver);
MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
+MODULE_DESCRIPTION("SIOX GPIO bus driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/staging/iio/addac/adt7316-i2c.c b/drivers/staging/iio/addac/adt7316-i2c.c
index 6c1f91c859ca..e6ad088636f6 100644
--- a/drivers/staging/iio/addac/adt7316-i2c.c
+++ b/drivers/staging/iio/addac/adt7316-i2c.c
@@ -109,12 +109,12 @@ static int adt7316_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id adt7316_i2c_id[] = {
- { "adt7316", 0 },
- { "adt7317", 0 },
- { "adt7318", 0 },
- { "adt7516", 0 },
- { "adt7517", 0 },
- { "adt7519", 0 },
+ { "adt7316" },
+ { "adt7317" },
+ { "adt7318" },
+ { "adt7516" },
+ { "adt7517" },
+ { "adt7519" },
{ }
};
diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c
index 79467f056a05..f4260786d50a 100644
--- a/drivers/staging/iio/addac/adt7316.c
+++ b/drivers/staging/iio/addac/adt7316.c
@@ -209,15 +209,6 @@ struct adt7316_chip_info {
#define ADT7316_TEMP_AIN_INT_MASK \
(ADT7316_TEMP_INT_MASK)
-/*
- * struct adt7316_chip_info - chip specific information
- */
-
-struct adt7316_limit_regs {
- u16 data_high;
- u16 data_low;
-};
-
static ssize_t adt7316_show_enabled(struct device *dev,
struct device_attribute *attr,
char *buf)
diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c
index b7af5fe63e09..cd00d9607565 100644
--- a/drivers/staging/iio/impedance-analyzer/ad5933.c
+++ b/drivers/staging/iio/impedance-analyzer/ad5933.c
@@ -721,8 +721,8 @@ static int ad5933_probe(struct i2c_client *client)
}
static const struct i2c_device_id ad5933_id[] = {
- { "ad5933", 0 },
- { "ad5934", 0 },
+ { "ad5933" },
+ { "ad5934" },
{}
};
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
index 5ce429286ab0..20d2a55cb40b 100644
--- a/drivers/uio/uio.c
+++ b/drivers/uio/uio.c
@@ -1145,4 +1145,5 @@ static void __exit uio_exit(void)
module_init(uio_init)
module_exit(uio_exit)
+MODULE_DESCRIPTION("Userspace IO core module");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/uio/uio_aec.c b/drivers/uio/uio_aec.c
index 64eafd59e6e7..8c164e51ff9e 100644
--- a/drivers/uio/uio_aec.c
+++ b/drivers/uio/uio_aec.c
@@ -144,4 +144,5 @@ static struct pci_driver pci_driver = {
};
module_pci_driver(pci_driver);
+MODULE_DESCRIPTION("Adrienne Electronics Corp time code PCI device");
MODULE_LICENSE("GPL");
diff --git a/drivers/uio/uio_cif.c b/drivers/uio/uio_cif.c
index 653f842a1491..1cc3b8b5a345 100644
--- a/drivers/uio/uio_cif.c
+++ b/drivers/uio/uio_cif.c
@@ -130,5 +130,6 @@ static struct pci_driver hilscher_pci_driver = {
module_pci_driver(hilscher_pci_driver);
MODULE_DEVICE_TABLE(pci, hilscher_pci_ids);
+MODULE_DESCRIPTION("UIO Hilscher CIF card driver");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Hans J. Koch, Benedikt Spranger");
diff --git a/drivers/uio/uio_mf624.c b/drivers/uio/uio_mf624.c
index 5065c6a073a8..790412f8dfd5 100644
--- a/drivers/uio/uio_mf624.c
+++ b/drivers/uio/uio_mf624.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * UIO driver fo Humusoft MF624 DAQ card.
+ * UIO driver for Humusoft MF624 DAQ card.
* Copyright (C) 2011 Rostislav Lisovy <lisovy@gmail.com>,
* Czech Technical University in Prague
*/
@@ -221,5 +221,6 @@ static struct pci_driver mf624_pci_driver = {
MODULE_DEVICE_TABLE(pci, mf624_pci_id);
module_pci_driver(mf624_pci_driver);
+MODULE_DESCRIPTION("UIO driver for Humusoft MF624 DAQ card");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Rostislav Lisovy <lisovy@gmail.com>");
diff --git a/drivers/uio/uio_netx.c b/drivers/uio/uio_netx.c
index 2319d6de8d04..a1a58802c793 100644
--- a/drivers/uio/uio_netx.c
+++ b/drivers/uio/uio_netx.c
@@ -170,5 +170,6 @@ static struct pci_driver netx_pci_driver = {
module_pci_driver(netx_pci_driver);
MODULE_DEVICE_TABLE(pci, netx_pci_ids);
+MODULE_DESCRIPTION("UIO driver for Hilscher NetX based fieldbus cards");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Hans J. Koch, Manuel Traut");
diff --git a/include/linux/eeprom_93xx46.h b/include/linux/eeprom_93xx46.h
deleted file mode 100644
index 34c2175e6a1e..000000000000
--- a/include/linux/eeprom_93xx46.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Module: eeprom_93xx46
- * platform description for 93xx46 EEPROMs.
- */
-#include <linux/gpio/consumer.h>
-
-struct eeprom_93xx46_platform_data {
- unsigned char flags;
-#define EE_ADDR8 0x01 /* 8 bit addr. cfg */
-#define EE_ADDR16 0x02 /* 16 bit addr. cfg */
-#define EE_READONLY 0x08 /* forbid writing */
-#define EE_SIZE1K 0x10 /* 1 kb of data, that is a 93xx46 */
-#define EE_SIZE2K 0x20 /* 2 kb of data, that is a 93xx56 */
-#define EE_SIZE4K 0x40 /* 4 kb of data, that is a 93xx66 */
-
- unsigned int quirks;
-/* Single word read transfers only; no sequential read. */
-#define EEPROM_93XX46_QUIRK_SINGLE_WORD_READ (1 << 0)
-/* Instructions such as EWEN are (addrlen + 2) in length. */
-#define EEPROM_93XX46_QUIRK_INSTRUCTION_LENGTH (1 << 1)
-/* Add extra cycle after address during a read */
-#define EEPROM_93XX46_QUIRK_EXTRA_READ_CYCLE BIT(2)
-
- /*
- * optional hooks to control additional logic
- * before and after spi transfer.
- */
- void (*prepare)(void *);
- void (*finish)(void *);
- struct gpio_desc *select;
-};
diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
index 55e2b22086a1..894309294182 100644
--- a/include/linux/iio/iio.h
+++ b/include/linux/iio/iio.h
@@ -174,6 +174,27 @@ struct iio_event_spec {
};
/**
+ * struct iio_scan_type - specification for channel data format in buffer
+ * @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
+ */
+struct iio_scan_type {
+ char sign;
+ u8 realbits;
+ u8 storagebits;
+ u8 shift;
+ u8 repeat;
+ enum iio_endian endianness;
+};
+
+/**
* struct iio_chan_spec - specification of a single channel
* @type: What type of measurement is the channel making.
* @channel: What number do we wish to assign the channel.
@@ -183,18 +204,13 @@ struct iio_event_spec {
* @address: Driver specific identifier.
* @scan_index: Monotonic index to give ordering in scans when read
* from a buffer.
- * @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
+ * @scan_type: struct describing the scan type - mutually exclusive
+ * with ext_scan_type.
+ * @ext_scan_type: Used in rare cases where there is more than one scan
+ * format for a channel. When this is used, the flag
+ * has_ext_scan_type must be set and the driver must
+ * implement get_current_scan_type in struct iio_info.
+ * @num_ext_scan_type: Number of elements in ext_scan_type.
* @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
@@ -238,6 +254,7 @@ struct iio_event_spec {
* attributes but not for event codes.
* @output: Channel is output.
* @differential: Channel is differential.
+ * @has_ext_scan_type: True if ext_scan_type is used instead of scan_type.
*/
struct iio_chan_spec {
enum iio_chan_type type;
@@ -245,14 +262,13 @@ struct iio_chan_spec {
int channel2;
unsigned long address;
int scan_index;
- struct {
- char sign;
- u8 realbits;
- u8 storagebits;
- u8 shift;
- u8 repeat;
- enum iio_endian endianness;
- } scan_type;
+ union {
+ struct iio_scan_type scan_type;
+ struct {
+ const struct iio_scan_type *ext_scan_type;
+ unsigned int num_ext_scan_type;
+ };
+ };
long info_mask_separate;
long info_mask_separate_available;
long info_mask_shared_by_type;
@@ -270,6 +286,7 @@ struct iio_chan_spec {
unsigned indexed:1;
unsigned output:1;
unsigned differential:1;
+ unsigned has_ext_scan_type:1;
};
@@ -432,6 +449,9 @@ struct iio_trigger; /* forward declaration */
* for better event identification.
* @validate_trigger: function to validate the trigger when the
* current trigger gets changed.
+ * @get_current_scan_type: must be implemented by drivers that use ext_scan_type
+ * in the channel spec to return the index of the currently
+ * active ext_scan type for a channel.
* @update_scan_mode: function to configure device and scan buffer when
* channels have changed
* @debugfs_reg_access: function to read or write register value of device
@@ -516,6 +536,8 @@ struct iio_info {
int (*validate_trigger)(struct iio_dev *indio_dev,
struct iio_trigger *trig);
+ int (*get_current_scan_type)(const struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan);
int (*update_scan_mode)(struct iio_dev *indio_dev,
const unsigned long *scan_mask);
int (*debugfs_reg_access)(struct iio_dev *indio_dev,
@@ -801,6 +823,38 @@ static inline bool iio_read_acpi_mount_matrix(struct device *dev,
}
#endif
+/**
+ * iio_get_current_scan_type - Get the current scan type for a channel
+ * @indio_dev: the IIO device to get the scan type for
+ * @chan: the channel to get the scan type for
+ *
+ * Most devices only have one scan type per channel and can just access it
+ * directly without calling this function. Core IIO code and drivers that
+ * implement ext_scan_type in the channel spec should use this function to
+ * get the current scan type for a channel.
+ *
+ * Returns: the current scan type for the channel or error.
+ */
+static inline const struct iio_scan_type
+*iio_get_current_scan_type(const struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan)
+{
+ int ret;
+
+ if (chan->has_ext_scan_type) {
+ ret = indio_dev->info->get_current_scan_type(indio_dev, chan);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ if (ret >= chan->num_ext_scan_type)
+ return ERR_PTR(-EINVAL);
+
+ return &chan->ext_scan_type[ret];
+ }
+
+ return &chan->scan_type;
+}
+
ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals);
int iio_str_to_fixpoint(const char *str, int fract_mult, int *integer,
diff --git a/include/linux/iio/imu/adis.h b/include/linux/iio/imu/adis.h
index 8898966bc0f0..4bb0a53cf7ea 100644
--- a/include/linux/iio/imu/adis.h
+++ b/include/linux/iio/imu/adis.h
@@ -21,6 +21,7 @@
#define ADIS_REG_PAGE_ID 0x00
struct adis;
+struct iio_dev_attr;
/**
* struct adis_timeouts - ADIS chip variant timeouts
@@ -84,6 +85,7 @@ struct adis_data {
bool unmasked_drdy;
bool has_paging;
+ bool has_fifo;
unsigned int burst_reg_cmd;
unsigned int burst_len;
@@ -515,11 +517,19 @@ int adis_single_conversion(struct iio_dev *indio_dev,
#define ADIS_ROT_CHAN(mod, addr, si, info_sep, info_all, bits) \
ADIS_MOD_CHAN(IIO_ROT, mod, addr, si, info_sep, info_all, bits)
+#define devm_adis_setup_buffer_and_trigger(adis, indio_dev, trigger_handler) \
+ devm_adis_setup_buffer_and_trigger_with_attrs((adis), (indio_dev), \
+ (trigger_handler), NULL, \
+ NULL)
+
#ifdef CONFIG_IIO_ADIS_LIB_BUFFER
int
-devm_adis_setup_buffer_and_trigger(struct adis *adis, struct iio_dev *indio_dev,
- irq_handler_t trigger_handler);
+devm_adis_setup_buffer_and_trigger_with_attrs(struct adis *adis,
+ struct iio_dev *indio_dev,
+ irq_handler_t trigger_handler,
+ const struct iio_buffer_setup_ops *ops,
+ const struct iio_dev_attr **buffer_attrs);
int devm_adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev);
@@ -529,8 +539,11 @@ int adis_update_scan_mode(struct iio_dev *indio_dev,
#else /* CONFIG_IIO_BUFFER */
static inline int
-devm_adis_setup_buffer_and_trigger(struct adis *adis, struct iio_dev *indio_dev,
- irq_handler_t trigger_handler)
+devm_adis_setup_buffer_and_trigger_with_attrs(struct adis *adis,
+ struct iio_dev *indio_dev,
+ irq_handler_t trigger_handler,
+ const struct iio_buffer_setup_ops *ops,
+ const struct iio_dev_attr **buffer_attrs)
{
return 0;
}
diff --git a/lib/math/prime_numbers.c b/lib/math/prime_numbers.c
index d3b64b10da1c..9a17ee9af93a 100644
--- a/lib/math/prime_numbers.c
+++ b/lib/math/prime_numbers.c
@@ -311,4 +311,5 @@ module_exit(primes_exit);
module_param_named(selftest, selftest_max, ulong, 0400);
MODULE_AUTHOR("Intel Corporation");
+MODULE_DESCRIPTION("Prime number library");
MODULE_LICENSE("GPL");
diff --git a/lib/math/rational-test.c b/lib/math/rational-test.c
index 01611ddff420..47486a95f088 100644
--- a/lib/math/rational-test.c
+++ b/lib/math/rational-test.c
@@ -53,4 +53,5 @@ static struct kunit_suite rational_test_suite = {
kunit_test_suites(&rational_test_suite);
+MODULE_DESCRIPTION("Rational fractions unit test");
MODULE_LICENSE("GPL v2");
diff --git a/lib/test_dynamic_debug.c b/lib/test_dynamic_debug.c
index 8dd250ad022b..77c2a669b6af 100644
--- a/lib/test_dynamic_debug.c
+++ b/lib/test_dynamic_debug.c
@@ -162,4 +162,5 @@ module_init(test_dynamic_debug_init);
module_exit(test_dynamic_debug_exit);
MODULE_AUTHOR("Jim Cromie <jim.cromie@gmail.com>");
+MODULE_DESCRIPTION("Kernel module for testing dynamic_debug");
MODULE_LICENSE("GPL");