diff options
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, ®val); + 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(×[j + 1], ×[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, ®); + 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, ®); + 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, ®); - 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, ®); - 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"); |