diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2023-02-03 07:01:54 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2023-02-03 07:01:54 +0100 |
commit | 196db6bb44738b76d7401c33aadadcea307894c2 (patch) | |
tree | ae91c0ba288ce688e9554a3bfabc0f531b7df4c5 | |
parent | cbce3de28c37fdd7531526d8dbb0ae2187667dfe (diff) | |
parent | 4ae612e4af95d72e36f478cad66d47c06b86de68 (diff) |
Merge tag 'iio-for-6.3a' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into char-misc-next
Jonathan writes:
1st set of IIO new device support, features and cleanups for the 6.3 cycle
The usual mixed bag. So far this has been a quiet cycle for IIO.
New device support
* adi,ad8686
- Add support for the AD5337 DAC - ID and 8 bit channel support.
* maxim,max5522
- New driver for this 2 channel DAC.
* nxp,imx93-adc
- New driver for this SoC ADC which is a fresh IP that will probably
turn up in additional SoCs going forwards.
* st,magn
- Add support for magnetometer part of LSM303C which is very similar
to standalone LIS3MDL already supported.
* ti,ads7924
- New driver for this 4 channel, 12-bit I2C ADC.
* ti,lmp92064
- New driver for this 12 bit SPI ADC.
* ti,tmag5273
- New driver for this 3D Hall-Effect Sensor.
Features
* core
- Add a standard structure for the value pairs in IIO_VAL_INT_PLUS_MICRO
available attributes and similar.
* cirrus,ep93xx
- Add DT binding docs and convert driver to DT based probing.
- Enable testing building with CONFIG_COMPILE_TEST.
* st,stm32-dfsdm
- Enable ID register support for discovery of hardware capabilities on
some devices.
Cleanups and minor fixes
* core
- Drop the custom iio_sysfs_match_string_with_gaps().
The special ability of this function to skip gaps in an array
was never used by any upstream driver.
- Sort headers whilst touching this file.
* tools
- Fix memory leak in iio_utils.c
* various
- leftover i2c probe_new() conversions.
- scnprintf() -> sysfs_emit() cleanups.
- hand rolled devm enables -> devm_regulator[_bulk]_get_enable()
- typo fixes
- dt-binding cleanup (whitespace, excess quotes and similar)
* adi,ad7746
- Set variable without pointless conditional.
* fsl,mma9551
- Squash false positives about use of uninitialized variable where
garbage undergoes an endian conversion before being ignored.
* measspec,ms5611
- Switch to fully devm_ managed probe() and so drop explicit remove()
* qcom,spmi-adc
- Use dev_err_probe() to suppress deferred print.
* qcom,spmi-adc5
- Define a missing channel used for battery identification.
* qcom,spmi-iadc
- Document a compatible seen in wild.
* semtech,sx9360
- Fix units on semtech,resolution dt-binding.
* sensiron,scd30
- dev_err_probe() usage to simplify error paths a little.
* st,lsm6dsx
- Add missing mount matrix for the gyro IIO device.
* taos,tsl2563
- Respect firmware configured interrupt polarity if present.
- Use i2c_smbus_write_word_data() in a few cases not previously covered.
- Factor out duplicated interrupt configuration.
- Switch to GENMASK() / BIT() from hand coded equivalents.
- Tidy up unused definitions.
- Use dev_err_probe() as appropriate.
- Drop platform_data as no in kernel users and there are better ways to
do equivalent if any are added.
- Add local struct device variable to tidy up code.
- Avoid dance via i2c_client to get the drvdata.
- Tidy up headers ordering and Makefile ordering.
* ti,adc128s052
- Use new spi_get_device_match_data().
- Drop ACPI_PTR() protection.
- Sort headers whilst here.
- Use asm instead of incorrect include of asm-generic/unaligned.h
* vishay,vcn4000
- Interrupt support for vcnl4040 (lots of refactoring needed)
* xilinx,ams
- Use fwnode_device_is_compatible() instead of open coding it.
* tag 'iio-for-6.3a' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (71 commits)
iio: adc: ad7291: Fix indentation error by adding extra spaces
iio: accel: mma9551_core: Prevent uninitialized variable in mma9551_read_config_word()
iio: accel: mma9551_core: Prevent uninitialized variable in mma9551_read_status_word()
dt-bindings: iio/proximity: semtech,sx9360: Fix 'semtech,resolution' type
iio: imu: fix spdx format
iio: adc: imx93: Fix spelling mistake "geting" -> "getting"
dt-bindings: iio: cleanup examples - indentation
dt-bindings: iio: use lowercase hex in examples
dt-bindings: iio: correct node names in examples
dt-bindings: iio: minor whitespace cleanups
dt-bindings: iio: drop unneeded quotes
dt-bindings: iio: adc: Add NXP IMX93 ADC
iio: adc: add imx93 adc support
dt-bindings: iio: adc: add Texas Instruments ADS7924
iio: adc: ti-ads7924: add Texas Instruments ADS7924 driver
iio: imu: st_lsm6dsx: add 'mount_matrix' sysfs entry to gyro channel.
iio: imu: st_lsm6dsx: fix naming of 'struct iio_info' in st_lsm6dsx_shub.c.
iio: light: vcnl4000: Add interrupt support for vcnl4040
iio: light: vcnl4000: Make irq handling more generic
iio: light: vcnl4000: Prepare for more generic setup
...
133 files changed, 4018 insertions, 1047 deletions
diff --git a/Documentation/devicetree/bindings/iio/accel/adi,adis16201.yaml b/Documentation/devicetree/bindings/iio/accel/adi,adis16201.yaml index 7332442e5661..b6ba7ad1a8d5 100644 --- a/Documentation/devicetree/bindings/iio/accel/adi,adis16201.yaml +++ b/Documentation/devicetree/bindings/iio/accel/adi,adis16201.yaml @@ -41,7 +41,7 @@ unevaluatedProperties: false examples: - | #include <dt-bindings/interrupt-controller/irq.h> - spi0 { + spi { #address-cells = <1>; #size-cells = <0>; diff --git a/Documentation/devicetree/bindings/iio/accel/adi,adis16240.yaml b/Documentation/devicetree/bindings/iio/accel/adi,adis16240.yaml index f6f97164c2ca..5887021cc90f 100644 --- a/Documentation/devicetree/bindings/iio/accel/adi,adis16240.yaml +++ b/Documentation/devicetree/bindings/iio/accel/adi,adis16240.yaml @@ -39,7 +39,7 @@ examples: - | #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/interrupt-controller/irq.h> - spi0 { + spi { #address-cells = <1>; #size-cells = <0>; diff --git a/Documentation/devicetree/bindings/iio/accel/adi,adxl313.yaml b/Documentation/devicetree/bindings/iio/accel/adi,adxl313.yaml index 185b68ffb536..0c5b64cae965 100644 --- a/Documentation/devicetree/bindings/iio/accel/adi,adxl313.yaml +++ b/Documentation/devicetree/bindings/iio/accel/adi,adxl313.yaml @@ -59,7 +59,7 @@ examples: - | #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/interrupt-controller/irq.h> - i2c0 { + i2c { #address-cells = <1>; #size-cells = <0>; diff --git a/Documentation/devicetree/bindings/iio/accel/adi,adxl345.yaml b/Documentation/devicetree/bindings/iio/accel/adi,adxl345.yaml index 346abfb13a3a..07cacc3f6a97 100644 --- a/Documentation/devicetree/bindings/iio/accel/adi,adxl345.yaml +++ b/Documentation/devicetree/bindings/iio/accel/adi,adxl345.yaml @@ -49,7 +49,7 @@ examples: - | #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/interrupt-controller/irq.h> - i2c0 { + i2c { #address-cells = <1>; #size-cells = <0>; @@ -64,7 +64,7 @@ examples: - | #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/interrupt-controller/irq.h> - spi0 { + spi { #address-cells = <1>; #size-cells = <0>; diff --git a/Documentation/devicetree/bindings/iio/accel/adi,adxl355.yaml b/Documentation/devicetree/bindings/iio/accel/adi,adxl355.yaml index 6b03c4efbb08..c07261c71013 100644 --- a/Documentation/devicetree/bindings/iio/accel/adi,adxl355.yaml +++ b/Documentation/devicetree/bindings/iio/accel/adi,adxl355.yaml @@ -58,34 +58,34 @@ unevaluatedProperties: false examples: - | - #include <dt-bindings/gpio/gpio.h> - #include <dt-bindings/interrupt-controller/irq.h> - i2c { - #address-cells = <1>; - #size-cells = <0>; + #include <dt-bindings/gpio/gpio.h> + #include <dt-bindings/interrupt-controller/irq.h> + i2c { + #address-cells = <1>; + #size-cells = <0>; - /* Example for a I2C device node */ - accelerometer@1d { - compatible = "adi,adxl355"; - reg = <0x1d>; - interrupt-parent = <&gpio>; - interrupts = <25 IRQ_TYPE_EDGE_RISING>; - interrupt-names = "DRDY"; - }; + /* Example for a I2C device node */ + accelerometer@1d { + compatible = "adi,adxl355"; + reg = <0x1d>; + interrupt-parent = <&gpio>; + interrupts = <25 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "DRDY"; }; + }; - | - #include <dt-bindings/gpio/gpio.h> - #include <dt-bindings/interrupt-controller/irq.h> - spi { - #address-cells = <1>; - #size-cells = <0>; + #include <dt-bindings/gpio/gpio.h> + #include <dt-bindings/interrupt-controller/irq.h> + spi { + #address-cells = <1>; + #size-cells = <0>; - accelerometer@0 { - compatible = "adi,adxl355"; - reg = <0>; - spi-max-frequency = <1000000>; - interrupt-parent = <&gpio>; - interrupts = <25 IRQ_TYPE_EDGE_RISING>; - interrupt-names = "DRDY"; - }; + accelerometer@0 { + compatible = "adi,adxl355"; + reg = <0>; + spi-max-frequency = <1000000>; + interrupt-parent = <&gpio>; + interrupts = <25 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "DRDY"; }; + }; diff --git a/Documentation/devicetree/bindings/iio/accel/adi,adxl372.yaml b/Documentation/devicetree/bindings/iio/accel/adi,adxl372.yaml index 73a5c8f814cc..62465e36a590 100644 --- a/Documentation/devicetree/bindings/iio/accel/adi,adxl372.yaml +++ b/Documentation/devicetree/bindings/iio/accel/adi,adxl372.yaml @@ -37,32 +37,32 @@ unevaluatedProperties: false examples: - | - #include <dt-bindings/gpio/gpio.h> - #include <dt-bindings/interrupt-controller/irq.h> - i2c0 { - #address-cells = <1>; - #size-cells = <0>; + #include <dt-bindings/gpio/gpio.h> + #include <dt-bindings/interrupt-controller/irq.h> + i2c { + #address-cells = <1>; + #size-cells = <0>; - /* Example for a I2C device node */ - accelerometer@53 { - compatible = "adi,adxl372"; - reg = <0x53>; - interrupt-parent = <&gpio>; - interrupts = <25 IRQ_TYPE_EDGE_FALLING>; - }; + /* Example for a I2C device node */ + accelerometer@53 { + compatible = "adi,adxl372"; + reg = <0x53>; + interrupt-parent = <&gpio>; + interrupts = <25 IRQ_TYPE_EDGE_FALLING>; }; + }; - | - #include <dt-bindings/gpio/gpio.h> - #include <dt-bindings/interrupt-controller/irq.h> - spi0 { - #address-cells = <1>; - #size-cells = <0>; + #include <dt-bindings/gpio/gpio.h> + #include <dt-bindings/interrupt-controller/irq.h> + spi { + #address-cells = <1>; + #size-cells = <0>; - accelerometer@0 { - compatible = "adi,adxl372"; - reg = <0>; - spi-max-frequency = <1000000>; - interrupt-parent = <&gpio>; - interrupts = <25 IRQ_TYPE_EDGE_FALLING>; - }; + accelerometer@0 { + compatible = "adi,adxl372"; + reg = <0>; + spi-max-frequency = <1000000>; + interrupt-parent = <&gpio>; + interrupts = <25 IRQ_TYPE_EDGE_FALLING>; }; + }; diff --git a/Documentation/devicetree/bindings/iio/accel/bosch,bma220.yaml b/Documentation/devicetree/bindings/iio/accel/bosch,bma220.yaml index 5dd06f5905b4..ec643de031a3 100644 --- a/Documentation/devicetree/bindings/iio/accel/bosch,bma220.yaml +++ b/Documentation/devicetree/bindings/iio/accel/bosch,bma220.yaml @@ -36,7 +36,7 @@ unevaluatedProperties: false examples: - | #include <dt-bindings/interrupt-controller/irq.h> - spi0 { + spi { #address-cells = <1>; #size-cells = <0>; diff --git a/Documentation/devicetree/bindings/iio/accel/kionix,kxcjk1013.yaml b/Documentation/devicetree/bindings/iio/accel/kionix,kxcjk1013.yaml index 714e48e613de..6ddb03f61bd9 100644 --- a/Documentation/devicetree/bindings/iio/accel/kionix,kxcjk1013.yaml +++ b/Documentation/devicetree/bindings/iio/accel/kionix,kxcjk1013.yaml @@ -44,7 +44,7 @@ examples: accel@f { compatible = "kionix,kxtf9"; - reg = <0x0F>; + reg = <0xf>; mount-matrix = "0", "1", "0", "1", "0", "0", "0", "0", "1"; diff --git a/Documentation/devicetree/bindings/iio/accel/memsensing,msa311.yaml b/Documentation/devicetree/bindings/iio/accel/memsensing,msa311.yaml index 23528dcaa073..d530ec041fe7 100644 --- a/Documentation/devicetree/bindings/iio/accel/memsensing,msa311.yaml +++ b/Documentation/devicetree/bindings/iio/accel/memsensing,msa311.yaml @@ -1,9 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause - %YAML 1.2 --- -$id: "http://devicetree.org/schemas/iio/accel/memsensing,msa311.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/iio/accel/memsensing,msa311.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: MEMSensing digital 3-Axis accelerometer diff --git a/Documentation/devicetree/bindings/iio/accel/nxp,fxls8962af.yaml b/Documentation/devicetree/bindings/iio/accel/nxp,fxls8962af.yaml index 65ce8ea14b52..783c7ddfcd90 100644 --- a/Documentation/devicetree/bindings/iio/accel/nxp,fxls8962af.yaml +++ b/Documentation/devicetree/bindings/iio/accel/nxp,fxls8962af.yaml @@ -50,7 +50,7 @@ unevaluatedProperties: false examples: - | #include <dt-bindings/interrupt-controller/irq.h> - i2c0 { + i2c { #address-cells = <1>; #size-cells = <0>; @@ -65,7 +65,7 @@ examples: }; - | #include <dt-bindings/interrupt-controller/irq.h> - spi0 { + spi { #address-cells = <1>; #size-cells = <0>; diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml index b97559f23b3a..ce7ba634643c 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml @@ -44,11 +44,11 @@ examples: #size-cells = <0>; adc@2f { - compatible = "adi,ad7091r5"; - reg = <0x2f>; + compatible = "adi,ad7091r5"; + reg = <0x2f>; - interrupts = <25 IRQ_TYPE_EDGE_FALLING>; - interrupt-parent = <&gpio>; + interrupts = <25 IRQ_TYPE_EDGE_FALLING>; + interrupt-parent = <&gpio>; }; }; ... diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7124.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7124.yaml index 75a7184a4735..35ed04350e28 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7124.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7124.yaml @@ -61,7 +61,7 @@ required: patternProperties: "^channel@([0-9]|1[0-5])$": - $ref: "adc.yaml" + $ref: adc.yaml type: object description: | Represents the external channels which are connected to the ADC. diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7192.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7192.yaml index cc347dade4ef..d521d516088b 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7192.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7192.yaml @@ -99,26 +99,26 @@ unevaluatedProperties: false examples: - | - spi0 { - #address-cells = <1>; - #size-cells = <0>; - - adc@0 { - compatible = "adi,ad7192"; - reg = <0>; - spi-max-frequency = <1000000>; - spi-cpol; - spi-cpha; - clocks = <&ad7192_mclk>; - clock-names = "mclk"; - interrupts = <25 0x2>; - interrupt-parent = <&gpio>; - dvdd-supply = <&dvdd>; - avdd-supply = <&avdd>; - - adi,refin2-pins-enable; - adi,rejection-60-Hz-enable; - adi,buffer-enable; - adi,burnout-currents-enable; + spi { + #address-cells = <1>; + #size-cells = <0>; + + adc@0 { + compatible = "adi,ad7192"; + reg = <0>; + spi-max-frequency = <1000000>; + spi-cpol; + spi-cpha; + clocks = <&ad7192_mclk>; + clock-names = "mclk"; + interrupts = <25 0x2>; + interrupt-parent = <&gpio>; + dvdd-supply = <&dvdd>; + avdd-supply = <&avdd>; + + adi,refin2-pins-enable; + adi,rejection-60-Hz-enable; + adi,buffer-enable; + adi,burnout-currents-enable; }; }; diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7292.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7292.yaml index 1bfbeed6f299..7cc4ddc4e9b7 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7292.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7292.yaml @@ -43,7 +43,7 @@ required: patternProperties: "^channel@[0-7]$": - $ref: "adc.yaml" + $ref: adc.yaml type: object description: | Represents the external channels which are connected to the ADC. diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml index ac5a47c8f070..7fa46df1f4fb 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml @@ -112,30 +112,30 @@ examples: - | #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/interrupt-controller/irq.h> - spi0 { + spi { #address-cells = <1>; #size-cells = <0>; adc@0 { - compatible = "adi,ad7606-8"; - reg = <0>; - spi-max-frequency = <1000000>; - spi-cpol; - spi-cpha; - - avcc-supply = <&adc_vref>; - - interrupts = <25 IRQ_TYPE_EDGE_FALLING>; - interrupt-parent = <&gpio>; - - adi,conversion-start-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>; - reset-gpios = <&gpio 27 GPIO_ACTIVE_HIGH>; - adi,first-data-gpios = <&gpio 22 GPIO_ACTIVE_HIGH>; - adi,oversampling-ratio-gpios = <&gpio 18 GPIO_ACTIVE_HIGH>, - <&gpio 23 GPIO_ACTIVE_HIGH>, - <&gpio 26 GPIO_ACTIVE_HIGH>; - standby-gpios = <&gpio 24 GPIO_ACTIVE_LOW>; - adi,sw-mode; + compatible = "adi,ad7606-8"; + reg = <0>; + spi-max-frequency = <1000000>; + spi-cpol; + spi-cpha; + + avcc-supply = <&adc_vref>; + + interrupts = <25 IRQ_TYPE_EDGE_FALLING>; + interrupt-parent = <&gpio>; + + adi,conversion-start-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio 27 GPIO_ACTIVE_HIGH>; + adi,first-data-gpios = <&gpio 22 GPIO_ACTIVE_HIGH>; + adi,oversampling-ratio-gpios = <&gpio 18 GPIO_ACTIVE_HIGH>, + <&gpio 23 GPIO_ACTIVE_HIGH>, + <&gpio 26 GPIO_ACTIVE_HIGH>; + standby-gpios = <&gpio 24 GPIO_ACTIVE_LOW>; + adi,sw-mode; }; }; ... diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7780.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7780.yaml index a67ba67dab51..5fcc8dd012f1 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7780.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7780.yaml @@ -72,7 +72,7 @@ additionalProperties: false examples: - | #include <dt-bindings/gpio/gpio.h> - spi0 { + spi { #address-cells = <1>; #size-cells = <0>; diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad799x.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad799x.yaml index 29641ce7175b..433ed2c9295f 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad799x.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad799x.yaml @@ -57,17 +57,17 @@ additionalProperties: false examples: - | i2c { - #address-cells = <1>; - #size-cells = <0>; + #address-cells = <1>; + #size-cells = <0>; - adc1: adc@28 { - reg = <0x28>; - compatible = "adi,ad7991"; - interrupts = <13 2>; - interrupt-parent = <&gpio6>; + adc1: adc@28 { + reg = <0x28>; + compatible = "adi,ad7991"; + interrupts = <13 2>; + interrupt-parent = <&gpio6>; - vcc-supply = <&vcc_3v3>; - vref-supply = <&adc_vref>; + vcc-supply = <&vcc_3v3>; + vref-supply = <&adc_vref>; }; }; ... diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad9467.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad9467.yaml index 2d72ff6bcbc0..7aa748d6b7a0 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad9467.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad9467.yaml @@ -64,10 +64,10 @@ examples: #size-cells = <0>; adc@0 { - compatible = "adi,ad9467"; - reg = <0>; - clocks = <&adc_clk>; - clock-names = "adc-clk"; + compatible = "adi,ad9467"; + reg = <0>; + clocks = <&adc_clk>; + clock-names = "adc-clk"; }; }; ... diff --git a/Documentation/devicetree/bindings/iio/adc/adi,axi-adc.yaml b/Documentation/devicetree/bindings/iio/adc/adi,axi-adc.yaml index 8e25773d69be..9996dd93f84b 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,axi-adc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,axi-adc.yaml @@ -51,11 +51,11 @@ additionalProperties: false examples: - | axi-adc@44a00000 { - compatible = "adi,axi-adc-10.0.a"; - reg = <0x44a00000 0x10000>; - dmas = <&rx_dma 0>; - dma-names = "rx"; + compatible = "adi,axi-adc-10.0.a"; + reg = <0x44a00000 0x10000>; + dmas = <&rx_dma 0>; + dma-names = "rx"; - adi,adc-dev = <&spi_adc>; + adi,adc-dev = <&spi_adc>; }; ... diff --git a/Documentation/devicetree/bindings/iio/adc/atmel,sama5d2-adc.yaml b/Documentation/devicetree/bindings/iio/adc/atmel,sama5d2-adc.yaml index 31f840d59303..4817b840977a 100644 --- a/Documentation/devicetree/bindings/iio/adc/atmel,sama5d2-adc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/atmel,sama5d2-adc.yaml @@ -41,7 +41,7 @@ properties: description: Startup time expressed in ms, it depends on SoC. atmel,trigger-edge-type: - $ref: '/schemas/types.yaml#/definitions/uint32' + $ref: /schemas/types.yaml#/definitions/uint32 description: One of possible edge types for the ADTRG hardware trigger pin. When the specific edge type is detected, the conversion will diff --git a/Documentation/devicetree/bindings/iio/adc/avia-hx711.yaml b/Documentation/devicetree/bindings/iio/adc/avia-hx711.yaml index 77605f17901c..9c57eb13f892 100644 --- a/Documentation/devicetree/bindings/iio/adc/avia-hx711.yaml +++ b/Documentation/devicetree/bindings/iio/adc/avia-hx711.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 %YAML 1.2 --- -$id: "http://devicetree.org/schemas/iio/adc/avia-hx711.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/iio/adc/avia-hx711.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: AVIA HX711 ADC chip for weight cells diff --git a/Documentation/devicetree/bindings/iio/adc/cirrus,ep9301-adc.yaml b/Documentation/devicetree/bindings/iio/adc/cirrus,ep9301-adc.yaml new file mode 100644 index 000000000000..6d4fb3e1d2a2 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/cirrus,ep9301-adc.yaml @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/cirrus,ep9301-adc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Cirrus Logic EP930x internal ADC + +description: | + Cirrus Logic EP9301/EP9302 SoCs' internal ADC block. + + User's manual: + https://cdn.embeddedts.com/resource-attachments/ts-7000_ep9301-ug.pdf + +maintainers: + - Alexander Sverdlin <alexander.sverdlin@gmail.com> + +properties: + compatible: + const: cirrus,ep9301-adc + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + - clocks + +additionalProperties: false + +examples: + - | + adc: adc@80900000 { + compatible = "cirrus,ep9301-adc"; + reg = <0x80900000 0x28>; + clocks = <&syscon 24>; + interrupt-parent = <&vic1>; + interrupts = <30>; + }; +... diff --git a/Documentation/devicetree/bindings/iio/adc/ingenic,adc.yaml b/Documentation/devicetree/bindings/iio/adc/ingenic,adc.yaml index 517e8b1fcb73..9cd0fd539782 100644 --- a/Documentation/devicetree/bindings/iio/adc/ingenic,adc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/ingenic,adc.yaml @@ -2,8 +2,8 @@ # Copyright 2019-2020 Artur Rojek %YAML 1.2 --- -$id: "http://devicetree.org/schemas/iio/adc/ingenic,adc.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/iio/adc/ingenic,adc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Ingenic JZ47xx ADC controller IIO @@ -78,14 +78,14 @@ examples: #include <dt-bindings/iio/adc/ingenic,adc.h> adc@10070000 { - compatible = "ingenic,jz4740-adc"; - #io-channel-cells = <1>; + compatible = "ingenic,jz4740-adc"; + #io-channel-cells = <1>; - reg = <0x10070000 0x30>; + reg = <0x10070000 0x30>; - clocks = <&cgu JZ4740_CLK_ADC>; - clock-names = "adc"; + clocks = <&cgu JZ4740_CLK_ADC>; + clock-names = "adc"; - interrupt-parent = <&intc>; - interrupts = <18>; + interrupt-parent = <&intc>; + interrupts = <18>; }; diff --git a/Documentation/devicetree/bindings/iio/adc/maxim,max1027.yaml b/Documentation/devicetree/bindings/iio/adc/maxim,max1027.yaml index d0a7ed26d9ea..e4b362113509 100644 --- a/Documentation/devicetree/bindings/iio/adc/maxim,max1027.yaml +++ b/Documentation/devicetree/bindings/iio/adc/maxim,max1027.yaml @@ -54,8 +54,8 @@ examples: - | #include <dt-bindings/interrupt-controller/irq.h> spi { - #address-cells = <1>; - #size-cells = <0>; + #address-cells = <1>; + #size-cells = <0>; maxadc: adc@0 { compatible = "maxim,max1027"; reg = <0>; diff --git a/Documentation/devicetree/bindings/iio/adc/maxim,max1238.yaml b/Documentation/devicetree/bindings/iio/adc/maxim,max1238.yaml index 50bcd72ac9d6..60d7b34e3286 100644 --- a/Documentation/devicetree/bindings/iio/adc/maxim,max1238.yaml +++ b/Documentation/devicetree/bindings/iio/adc/maxim,max1238.yaml @@ -10,7 +10,7 @@ maintainers: - Jonathan Cameron <jic23@kernel.org> description: | - Family of simple ADCs with i2c inteface and internal references. + Family of simple ADCs with i2c interface and internal references. properties: compatible: diff --git a/Documentation/devicetree/bindings/iio/adc/maxim,max1241.yaml b/Documentation/devicetree/bindings/iio/adc/maxim,max1241.yaml index 58b12fe8070c..ef8d51e74c08 100644 --- a/Documentation/devicetree/bindings/iio/adc/maxim,max1241.yaml +++ b/Documentation/devicetree/bindings/iio/adc/maxim,max1241.yaml @@ -54,8 +54,8 @@ examples: - | #include <dt-bindings/gpio/gpio.h> spi { - #address-cells = <1>; - #size-cells = <0>; + #address-cells = <1>; + #size-cells = <0>; adc@0 { compatible = "maxim,max1241"; diff --git a/Documentation/devicetree/bindings/iio/adc/maxim,max1363.yaml b/Documentation/devicetree/bindings/iio/adc/maxim,max1363.yaml index e04f09f35601..96f3f535fe34 100644 --- a/Documentation/devicetree/bindings/iio/adc/maxim,max1363.yaml +++ b/Documentation/devicetree/bindings/iio/adc/maxim,max1363.yaml @@ -10,7 +10,7 @@ maintainers: - Jonathan Cameron <jic23@kernel.org> description: | - Family of ADCs with i2c inteface, internal references and threshold + Family of ADCs with i2c interface, internal references and threshold monitoring. properties: diff --git a/Documentation/devicetree/bindings/iio/adc/microchip,mcp3911.yaml b/Documentation/devicetree/bindings/iio/adc/microchip,mcp3911.yaml index 2c93fb41f172..f7b3fde4115a 100644 --- a/Documentation/devicetree/bindings/iio/adc/microchip,mcp3911.yaml +++ b/Documentation/devicetree/bindings/iio/adc/microchip,mcp3911.yaml @@ -2,8 +2,8 @@ # Copyright 2019 Marcus Folkesson <marcus.folkesson@gmail.com> %YAML 1.2 --- -$id: "http://devicetree.org/schemas/iio/adc/microchip,mcp3911.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/iio/adc/microchip,mcp3911.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Microchip MCP3911 Dual channel analog front end (ADC) diff --git a/Documentation/devicetree/bindings/iio/adc/nxp,imx93-adc.yaml b/Documentation/devicetree/bindings/iio/adc/nxp,imx93-adc.yaml new file mode 100644 index 000000000000..dacc526dc695 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/nxp,imx93-adc.yaml @@ -0,0 +1,81 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/nxp,imx93-adc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP iMX93 ADC + +maintainers: + - Haibo Chen <haibo.chen@nxp.com> + +description: + The ADC on iMX93 is a 8-channel 12-bit 1MS/s ADC with 4 channels + connected to pins. it support normal and inject mode, include + One-Shot and Scan (continuous) conversions. Programmable DMA + enables for each channel Also this ADC contain alternate analog + watchdog thresholds, select threshold through input ports. And + also has Self-test logic and Software-initiated calibration. + +properties: + compatible: + const: nxp,imx93-adc + + reg: + maxItems: 1 + + interrupts: + items: + - description: WDGnL, watchdog threshold interrupt requests. + - description: WDGnH, watchdog threshold interrupt requests. + - description: normal conversion, include EOC (End of Conversion), + ECH (End of Chain), JEOC (End of Injected Conversion) and + JECH (End of injected Chain). + - description: Self-testing Interrupts. + + clocks: + maxItems: 1 + + clock-names: + const: ipg + + vref-supply: + description: + The reference voltage which used to establish channel scaling. + + "#io-channel-cells": + const: 1 + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + - vref-supply + - "#io-channel-cells" + +additionalProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/irq.h> + #include <dt-bindings/clock/imx93-clock.h> + #include <dt-bindings/interrupt-controller/arm-gic.h> + soc { + #address-cells = <1>; + #size-cells = <1>; + adc@44530000 { + compatible = "nxp,imx93-adc"; + reg = <0x44530000 0x10000>; + interrupts = <GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk IMX93_CLK_ADC1_GATE>; + clock-names = "ipg"; + vref-supply = <®_vref_1v8>; + #io-channel-cells = <1>; + }; + }; +... diff --git a/Documentation/devicetree/bindings/iio/adc/qcom,pm8018-adc.yaml b/Documentation/devicetree/bindings/iio/adc/qcom,pm8018-adc.yaml index d186b713d6a7..58ea1ca4a5ee 100644 --- a/Documentation/devicetree/bindings/iio/adc/qcom,pm8018-adc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/qcom,pm8018-adc.yaml @@ -160,7 +160,7 @@ examples: }; ref_muxoff: adc-channel@f { reg = <0x00 0x0f>; - }; + }; }; }; ... diff --git a/Documentation/devicetree/bindings/iio/adc/qcom,spmi-iadc.yaml b/Documentation/devicetree/bindings/iio/adc/qcom,spmi-iadc.yaml index fa855baa368c..73def67fbe01 100644 --- a/Documentation/devicetree/bindings/iio/adc/qcom,spmi-iadc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/qcom,spmi-iadc.yaml @@ -20,6 +20,7 @@ properties: compatible: items: - enum: + - qcom,pm8226-iadc - qcom,pm8941-iadc - const: qcom,spmi-iadc @@ -49,7 +50,7 @@ additionalProperties: false examples: - | #include <dt-bindings/interrupt-controller/irq.h> - spmi_bus { + spmi { #address-cells = <1>; #size-cells = <0>; pmic_iadc: adc@3600 { diff --git a/Documentation/devicetree/bindings/iio/adc/qcom,spmi-rradc.yaml b/Documentation/devicetree/bindings/iio/adc/qcom,spmi-rradc.yaml index c8cbfd3444be..b3a626389870 100644 --- a/Documentation/devicetree/bindings/iio/adc/qcom,spmi-rradc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/qcom,spmi-rradc.yaml @@ -40,12 +40,12 @@ additionalProperties: false examples: - | pmic { - #address-cells = <1>; - #size-cells = <0>; - - pmic_rradc: adc@4500 { - compatible = "qcom,pmi8998-rradc"; - reg = <0x4500>; - #io-channel-cells = <1>; - }; + #address-cells = <1>; + #size-cells = <0>; + + pmic_rradc: adc@4500 { + compatible = "qcom,pmi8998-rradc"; + reg = <0x4500>; + #io-channel-cells = <1>; + }; }; diff --git a/Documentation/devicetree/bindings/iio/adc/renesas,rzg2l-adc.yaml b/Documentation/devicetree/bindings/iio/adc/renesas,rzg2l-adc.yaml index 8b743742a5f9..ba86c7b7d622 100644 --- a/Documentation/devicetree/bindings/iio/adc/renesas,rzg2l-adc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/renesas,rzg2l-adc.yaml @@ -69,7 +69,7 @@ required: patternProperties: "^channel@[0-7]$": - $ref: "adc.yaml" + $ref: adc.yaml type: object description: | Represents the external channels which are connected to the ADC. diff --git a/Documentation/devicetree/bindings/iio/adc/samsung,exynos-adc.yaml b/Documentation/devicetree/bindings/iio/adc/samsung,exynos-adc.yaml index 81c87295912c..582d0a03b814 100644 --- a/Documentation/devicetree/bindings/iio/adc/samsung,exynos-adc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/samsung,exynos-adc.yaml @@ -52,7 +52,7 @@ properties: vdd-supply: true samsung,syscon-phandle: - $ref: '/schemas/types.yaml#/definitions/phandle' + $ref: /schemas/types.yaml#/definitions/phandle description: Phandle to the PMU system controller node (to access the ADC_PHY register on Exynos3250/4x12/5250/5420/5800). @@ -142,7 +142,7 @@ examples: pullup-ohm = <47000>; pulldown-ohm = <0>; io-channels = <&adc 4>; - }; + }; }; - | @@ -150,7 +150,7 @@ examples: adc@126c0000 { compatible = "samsung,exynos3250-adc"; - reg = <0x126C0000 0x100>; + reg = <0x126c0000 0x100>; interrupts = <0 137 0>; #io-channel-cells = <1>; diff --git a/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.yaml b/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.yaml index 1c340c95df16..995cbf8cefc6 100644 --- a/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/iio/adc/st,stm32-adc.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/iio/adc/st,stm32-adc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: STMicroelectronics STM32 ADC @@ -80,7 +80,7 @@ properties: description: Phandle to system configuration controller. It can be used to control the analog circuitry on stm32mp1. - $ref: "/schemas/types.yaml#/definitions/phandle-array" + $ref: /schemas/types.yaml#/definitions/phandle-array interrupt-controller: true @@ -341,7 +341,7 @@ patternProperties: patternProperties: "^channel@([0-9]|1[0-9])$": type: object - $ref: "adc.yaml" + $ref: adc.yaml description: Represents the external channels which are connected to the ADC. properties: diff --git a/Documentation/devicetree/bindings/iio/adc/st,stmpe-adc.yaml b/Documentation/devicetree/bindings/iio/adc/st,stmpe-adc.yaml index 333744a2159c..474e35c49348 100644 --- a/Documentation/devicetree/bindings/iio/adc/st,stmpe-adc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/st,stmpe-adc.yaml @@ -35,10 +35,8 @@ additionalProperties: false examples: - | - stmpe { - stmpe_adc { - compatible = "st,stmpe-adc"; - st,norequest-mask = <0x0F>; /* dont use ADC CH3-0 */ - }; + adc { + compatible = "st,stmpe-adc"; + st,norequest-mask = <0x0f>; /* dont use ADC CH3-0 */ }; ... diff --git a/Documentation/devicetree/bindings/iio/adc/ti,adc081c.yaml b/Documentation/devicetree/bindings/iio/adc/ti,adc081c.yaml new file mode 100644 index 000000000000..caaad777580c --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/ti,adc081c.yaml @@ -0,0 +1,55 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/ti,adc081c.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TI Single-channel I2C ADCs + +maintainers: + - Jonathan Cameron <jic23@kernel.org> + - Lars-Peter Clausen <lars@metafoo.de> + +description: | + Single-channel ADC supporting 8, 10, or 12-bit samples and high/low alerts. + +properties: + compatible: + enum: + - ti,adc081c + - ti,adc101c + - ti,adc121c + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + vref-supply: + description: + Regulator for the combined power supply and voltage reference + + "#io-channel-cells": + const: 1 + +required: + - compatible + - reg + - vref-supply + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + adc@52 { + compatible = "ti,adc081c"; + reg = <0x52>; + vref-supply = <®_2p5v>; + }; + }; +... diff --git a/Documentation/devicetree/bindings/iio/adc/ti,ads1015.yaml b/Documentation/devicetree/bindings/iio/adc/ti,ads1015.yaml index 2c3c2cf2145c..2127d639a768 100644 --- a/Documentation/devicetree/bindings/iio/adc/ti,ads1015.yaml +++ b/Documentation/devicetree/bindings/iio/adc/ti,ads1015.yaml @@ -104,12 +104,12 @@ examples: #address-cells = <1>; #size-cells = <0>; channel@0 { - reg = <0>; + reg = <0>; }; channel@4 { - reg = <4>; - ti,gain = <3>; - ti,datarate = <5>; + reg = <4>; + ti,gain = <3>; + ti,datarate = <5>; }; }; }; diff --git a/Documentation/devicetree/bindings/iio/adc/ti,ads131e08.yaml b/Documentation/devicetree/bindings/iio/adc/ti,ads131e08.yaml index 55c2c73626f4..890f125d422c 100644 --- a/Documentation/devicetree/bindings/iio/adc/ti,ads131e08.yaml +++ b/Documentation/devicetree/bindings/iio/adc/ti,ads131e08.yaml @@ -77,7 +77,7 @@ required: patternProperties: "^channel@([0-7])$": - $ref: "adc.yaml" + $ref: adc.yaml type: object description: | Represents the external channels which are connected to the ADC. diff --git a/Documentation/devicetree/bindings/iio/adc/ti,ads7924.yaml b/Documentation/devicetree/bindings/iio/adc/ti,ads7924.yaml new file mode 100644 index 000000000000..0d8d06afed8b --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/ti,ads7924.yaml @@ -0,0 +1,110 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/ti,ads7924.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TI ADS7924 4 channels 12 bits I2C analog to digital converter + +maintainers: + - Hugo Villeneuve <hvilleneuve@dimonoff.com> + +description: | + Texas Instruments ADS7924 4 channels 12 bits I2C analog to digital converter + + Specifications: + https://www.ti.com/lit/gpn/ads7924 + +properties: + compatible: + const: ti,ads7924 + + reg: + maxItems: 1 + + vref-supply: + description: + The regulator supply for the ADC reference voltage (AVDD) + + reset-gpios: + maxItems: 1 + + interrupts: + maxItems: 1 + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + "#io-channel-cells": + const: 1 + +patternProperties: + "^channel@[0-3]+$": + $ref: adc.yaml + + description: | + Represents the external channels which are connected to the ADC. + + properties: + reg: + description: | + The channel number. It can have up to 4 channels numbered from 0 to 3. + items: + - minimum: 0 + maximum: 3 + + label: true + + required: + - reg + + additionalProperties: false + +additionalProperties: false + +required: + - compatible + - reg + - vref-supply + - "#address-cells" + - "#size-cells" + +examples: + - | + #include <dt-bindings/interrupt-controller/irq.h> + #include <dt-bindings/gpio/gpio.h> + i2c { + #address-cells = <1>; + #size-cells = <0>; + + adc@48 { + compatible = "ti,ads7924"; + reg = <0x48>; + vref-supply = <&ads7924_reg>; + reset-gpios = <&gpio 5 GPIO_ACTIVE_LOW>; + interrupts = <25 IRQ_TYPE_EDGE_FALLING>; + interrupt-parent = <&gpio>; + #address-cells = <1>; + #size-cells = <0>; + channel@0 { + reg = <0>; + label = "CH0"; + }; + channel@1 { + reg = <1>; + label = "CH1"; + }; + channel@2 { + reg = <2>; + label = "CH2"; + }; + channel@3 { + reg = <3>; + label = "CH3"; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/iio/adc/ti,lmp92064.yaml b/Documentation/devicetree/bindings/iio/adc/ti,lmp92064.yaml new file mode 100644 index 000000000000..5fb65bf7749d --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/ti,lmp92064.yaml @@ -0,0 +1,70 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/ti,lmp92064.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments LMP92064 Precision Current and Voltage Sensor. + +maintainers: + - Leonard Göhrs <l.goehrs@pengutronix.de> + +description: | + The LMP92064 is a two channel ADC intended for combined voltage and current + measurements. + + The device contains two ADCs to allow simultaneous sampling of voltage and + current and thus of instantaneous power consumption. + +properties: + compatible: + enum: + - ti,lmp92064 + + reg: + maxItems: 1 + + vdd-supply: + description: Regulator that provides power to the main part of the chip + + vdig-supply: + description: | + Regulator that provides power to the digital I/O part of the chip + + shunt-resistor-micro-ohms: + description: | + Value of the shunt resistor (in µΩ) connected between INCP and INCN, + across which current is measured. Used to provide correct scaling of the + raw ADC measurement. + + reset-gpios: + maxItems: 1 + +required: + - compatible + - reg + - shunt-resistor-micro-ohms + +allOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml# + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + spi { + #address-cells = <1>; + #size-cells = <0>; + + adc@0 { + compatible = "ti,lmp92064"; + reg = <0>; + vdd-supply = <&vdd>; + vdig-supply = <&vdd>; + spi-max-frequency = <20000000>; + shunt-resistor-micro-ohms = <15000>; + reset-gpios = <&gpio1 16 GPIO_ACTIVE_HIGH>; + }; + }; +... diff --git a/Documentation/devicetree/bindings/iio/adc/ti,tsc2046.yaml b/Documentation/devicetree/bindings/iio/adc/ti,tsc2046.yaml index bdf3bba2d750..866a05c9db36 100644 --- a/Documentation/devicetree/bindings/iio/adc/ti,tsc2046.yaml +++ b/Documentation/devicetree/bindings/iio/adc/ti,tsc2046.yaml @@ -41,7 +41,7 @@ required: patternProperties: "^channel@[0-7]$": - $ref: "adc.yaml" + $ref: adc.yaml type: object properties: @@ -83,36 +83,36 @@ examples: #size-cells = <0>; channel@0 { - reg = <0>; + reg = <0>; }; channel@1 { - reg = <1>; - settling-time-us = <700>; - oversampling-ratio = <5>; + reg = <1>; + settling-time-us = <700>; + oversampling-ratio = <5>; }; channel@2 { - reg = <2>; + reg = <2>; }; channel@3 { - reg = <3>; - settling-time-us = <700>; - oversampling-ratio = <5>; + reg = <3>; + settling-time-us = <700>; + oversampling-ratio = <5>; }; channel@4 { - reg = <4>; - settling-time-us = <700>; - oversampling-ratio = <5>; + reg = <4>; + settling-time-us = <700>; + oversampling-ratio = <5>; }; channel@5 { - reg = <5>; - settling-time-us = <700>; - oversampling-ratio = <5>; + reg = <5>; + settling-time-us = <700>; + oversampling-ratio = <5>; }; channel@6 { - reg = <6>; + reg = <6>; }; channel@7 { - reg = <7>; + reg = <7>; }; }; }; diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml index fee0f023a8c8..96340a05754c 100644 --- a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml @@ -192,26 +192,26 @@ additionalProperties: false examples: - | spi { - #address-cells = <1>; - #size-cells = <0>; - ad3552r@0 { - compatible = "adi,ad3552r"; - reg = <0>; - spi-max-frequency = <20000000>; - #address-cells = <1>; - #size-cells = <0>; - channel@0 { - reg = <0>; - adi,output-range-microvolt = <0 10000000>; - }; - channel@1 { - 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,rfb-ohms = <1>; - }; + #address-cells = <1>; + #size-cells = <0>; + ad3552r@0 { + compatible = "adi,ad3552r"; + reg = <0>; + spi-max-frequency = <20000000>; + #address-cells = <1>; + #size-cells = <0>; + channel@0 { + reg = <0>; + adi,output-range-microvolt = <0 10000000>; + }; + channel@1 { + 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,rfb-ohms = <1>; + }; }; }; }; diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad5380.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad5380.yaml index ff50c72c62b5..9eb9928500e2 100644 --- a/Documentation/devicetree/bindings/iio/dac/adi,ad5380.yaml +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad5380.yaml @@ -12,6 +12,7 @@ maintainers: description: | DAC devices supporting both SPI and I2C interfaces. + properties: compatible: enum: diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad5686.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad5686.yaml index 13f214234b8e..b4400c52bec3 100644 --- a/Documentation/devicetree/bindings/iio/dac/adi,ad5686.yaml +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad5686.yaml @@ -33,6 +33,7 @@ properties: - description: I2C devices enum: - adi,ad5311r + - adi,ad5337r - adi,ad5338r - adi,ad5671r - adi,ad5675r diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad5766.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad5766.yaml index 3c8784a54d2c..212c936bab8d 100644 --- a/Documentation/devicetree/bindings/iio/dac/adi,ad5766.yaml +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad5766.yaml @@ -51,15 +51,15 @@ additionalProperties: false examples: - | spi { - #address-cells = <1>; - #size-cells = <0>; + #address-cells = <1>; + #size-cells = <0>; - ad5766@0 { - compatible = "adi,ad5766"; - output-range-microvolts = <(-5000000) 5000000>; - reg = <0>; - spi-cpol; - spi-max-frequency = <1000000>; - reset-gpios = <&gpio 22 0>; - }; - }; + ad5766@0 { + compatible = "adi,ad5766"; + output-range-microvolts = <(-5000000) 5000000>; + reg = <0>; + spi-cpol; + spi-max-frequency = <1000000>; + reset-gpios = <&gpio 22 0>; + }; + }; diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad5770r.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad5770r.yaml index 8e7da0de918f..82b0eed6a7b7 100644 --- a/Documentation/devicetree/bindings/iio/dac/adi,ad5770r.yaml +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad5770r.yaml @@ -147,49 +147,49 @@ unevaluatedProperties: false examples: - | - spi { - #address-cells = <1>; - #size-cells = <0>; - - ad5770r@0 { - compatible = "adi,ad5770r"; - reg = <0>; - spi-max-frequency = <1000000>; - vref-supply = <&vref>; - adi,external-resistor; - reset-gpios = <&gpio 22 0>; - #address-cells = <1>; - #size-cells = <0>; - - channel@0 { - reg = <0>; - adi,range-microamp = <0 300000>; - }; - - channel@1 { - reg = <1>; - adi,range-microamp = <0 140000>; - }; - - channel@2 { - reg = <2>; - adi,range-microamp = <0 55000>; - }; - - channel@3 { - reg = <3>; - adi,range-microamp = <0 45000>; - }; - - channel@4 { - reg = <4>; - adi,range-microamp = <0 45000>; - }; - - channel@5 { - reg = <5>; - adi,range-microamp = <0 45000>; - }; - }; + spi { + #address-cells = <1>; + #size-cells = <0>; + + ad5770r@0 { + compatible = "adi,ad5770r"; + reg = <0>; + spi-max-frequency = <1000000>; + vref-supply = <&vref>; + adi,external-resistor; + reset-gpios = <&gpio 22 0>; + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + adi,range-microamp = <0 300000>; + }; + + channel@1 { + reg = <1>; + adi,range-microamp = <0 140000>; + }; + + channel@2 { + reg = <2>; + adi,range-microamp = <0 55000>; + }; + + channel@3 { + reg = <3>; + adi,range-microamp = <0 45000>; + }; + + channel@4 { + reg = <4>; + adi,range-microamp = <0 45000>; + }; + + channel@5 { + reg = <5>; + adi,range-microamp = <0 45000>; + }; }; + }; ... diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ltc2688.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ltc2688.yaml index 15cc6bf59b13..f22ef710ecde 100644 --- a/Documentation/devicetree/bindings/iio/dac/adi,ltc2688.yaml +++ b/Documentation/devicetree/bindings/iio/dac/adi,ltc2688.yaml @@ -116,32 +116,32 @@ examples: - | spi { - #address-cells = <1>; - #size-cells = <0>; - ltc2688: ltc2688@0 { - compatible = "adi,ltc2688"; - reg = <0>; - - vcc-supply = <&vcc>; - iovcc-supply = <&vcc>; - vref-supply = <&vref>; - - #address-cells = <1>; - #size-cells = <0>; - channel@0 { - reg = <0>; - adi,toggle-mode; - adi,overrange; - }; - - channel@1 { - reg = <1>; - adi,output-range-microvolt = <0 10000000>; - - clocks = <&clock_tgp3>; - adi,toggle-dither-input = <2>; - }; - }; + #address-cells = <1>; + #size-cells = <0>; + ltc2688: ltc2688@0 { + compatible = "adi,ltc2688"; + reg = <0>; + + vcc-supply = <&vcc>; + iovcc-supply = <&vcc>; + vref-supply = <&vref>; + + #address-cells = <1>; + #size-cells = <0>; + channel@0 { + reg = <0>; + adi,toggle-mode; + adi,overrange; + }; + + channel@1 { + reg = <1>; + adi,output-range-microvolt = <0 10000000>; + + clocks = <&clock_tgp3>; + adi,toggle-dither-input = <2>; + }; + }; }; ... diff --git a/Documentation/devicetree/bindings/iio/dac/lltc,ltc1660.yaml b/Documentation/devicetree/bindings/iio/dac/lltc,ltc1660.yaml index 133b0f867992..c9f51d00fa8f 100644 --- a/Documentation/devicetree/bindings/iio/dac/lltc,ltc1660.yaml +++ b/Documentation/devicetree/bindings/iio/dac/lltc,ltc1660.yaml @@ -2,8 +2,8 @@ # Copyright 2019 Marcus Folkesson <marcus.folkesson@gmail.com> %YAML 1.2 --- -$id: "http://devicetree.org/schemas/iio/dac/lltc,ltc1660.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/iio/dac/lltc,ltc1660.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Linear Technology Micropower octal 8-Bit and 10-Bit DACs diff --git a/Documentation/devicetree/bindings/iio/dac/lltc,ltc2632.yaml b/Documentation/devicetree/bindings/iio/dac/lltc,ltc2632.yaml index b1eb77335d05..733edc7d6d17 100644 --- a/Documentation/devicetree/bindings/iio/dac/lltc,ltc2632.yaml +++ b/Documentation/devicetree/bindings/iio/dac/lltc,ltc2632.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause %YAML 1.2 --- -$id: "http://devicetree.org/schemas/iio/dac/lltc,ltc2632.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/iio/dac/lltc,ltc2632.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Linear Technology LTC263x 12-/10-/8-Bit Rail-to-Rail DAC @@ -64,14 +64,14 @@ examples: }; spi { - #address-cells = <1>; - #size-cells = <0>; + #address-cells = <1>; + #size-cells = <0>; - dac@0 { - compatible = "lltc,ltc2632-l12"; - reg = <0>; /* CS0 */ - spi-max-frequency = <1000000>; - vref-supply = <&vref>; - }; + dac@0 { + compatible = "lltc,ltc2632-l12"; + reg = <0>; /* CS0 */ + spi-max-frequency = <1000000>; + vref-supply = <&vref>; + }; }; ... diff --git a/Documentation/devicetree/bindings/iio/dac/maxim,max5522.yaml b/Documentation/devicetree/bindings/iio/dac/maxim,max5522.yaml new file mode 100644 index 000000000000..24830f56c501 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/dac/maxim,max5522.yaml @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/dac/maxim,max5522.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Maxim Integrated MAX5522 Dual 10-bit Voltage-Output SPI DACs + +maintainers: + - Angelo Dureghello <angelo.dureghello@timesys.com> + - Jonathan Cameron <jic23@kernel.org> + +description: | + Datasheet available at: + https://www.analog.com/en/products/max5522.html + +properties: + compatible: + const: maxim,max5522 + + reg: + maxItems: 1 + + vdd-supply: true + vrefin-supply: true + +required: + - compatible + - reg + - vrefin-supply + +allOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml# + +unevaluatedProperties: false + +examples: + - | + spi { + #address-cells = <1>; + #size-cells = <0>; + + dac@0 { + compatible = "maxim,max5522"; + reg = <0>; + vrefin-supply = <&vref>; + }; + }; +... diff --git a/Documentation/devicetree/bindings/iio/dac/st,stm32-dac.yaml b/Documentation/devicetree/bindings/iio/dac/st,stm32-dac.yaml index 0f1bf1110122..04045b932bd2 100644 --- a/Documentation/devicetree/bindings/iio/dac/st,stm32-dac.yaml +++ b/Documentation/devicetree/bindings/iio/dac/st,stm32-dac.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/iio/dac/st,stm32-dac.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/iio/dac/st,stm32-dac.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: STMicroelectronics STM32 DAC diff --git a/Documentation/devicetree/bindings/iio/dac/ti,dac5571.yaml b/Documentation/devicetree/bindings/iio/dac/ti,dac5571.yaml index 88298bc43b81..79da0323c327 100644 --- a/Documentation/devicetree/bindings/iio/dac/ti,dac5571.yaml +++ b/Documentation/devicetree/bindings/iio/dac/ti,dac5571.yaml @@ -46,7 +46,7 @@ examples: dac@4c { compatible = "ti,dac5571"; - reg = <0x4C>; + reg = <0x4c>; vref-supply = <&vdd_supply>; }; }; diff --git a/Documentation/devicetree/bindings/iio/frequency/adf4371.yaml b/Documentation/devicetree/bindings/iio/frequency/adf4371.yaml index 0144f74a4768..1cb2adaf66f9 100644 --- a/Documentation/devicetree/bindings/iio/frequency/adf4371.yaml +++ b/Documentation/devicetree/bindings/iio/frequency/adf4371.yaml @@ -53,16 +53,16 @@ unevaluatedProperties: false examples: - | - spi0 { + spi { #address-cells = <1>; #size-cells = <0>; frequency@0 { - compatible = "adi,adf4371"; - reg = <0>; - spi-max-frequency = <1000000>; - clocks = <&adf4371_clkin>; - clock-names = "clkin"; + compatible = "adi,adf4371"; + reg = <0>; + spi-max-frequency = <1000000>; + clocks = <&adf4371_clkin>; + clock-names = "clkin"; }; }; ... diff --git a/Documentation/devicetree/bindings/iio/gyroscope/adi,adxrs290.yaml b/Documentation/devicetree/bindings/iio/gyroscope/adi,adxrs290.yaml index 0ae2464b9bc4..3d94dd4612c4 100644 --- a/Documentation/devicetree/bindings/iio/gyroscope/adi,adxrs290.yaml +++ b/Documentation/devicetree/bindings/iio/gyroscope/adi,adxrs290.yaml @@ -50,13 +50,13 @@ examples: #address-cells = <1>; #size-cells = <0>; gyro@0 { - compatible = "adi,adxrs290"; - reg = <0>; - spi-max-frequency = <5000000>; - spi-cpol; - spi-cpha; - interrupt-parent = <&gpio>; - interrupts = <25 IRQ_TYPE_EDGE_RISING>; + compatible = "adi,adxrs290"; + reg = <0>; + spi-max-frequency = <5000000>; + spi-cpol; + spi-cpha; + interrupt-parent = <&gpio>; + interrupts = <25 IRQ_TYPE_EDGE_RISING>; }; }; ... diff --git a/Documentation/devicetree/bindings/iio/gyroscope/nxp,fxas21002c.yaml b/Documentation/devicetree/bindings/iio/gyroscope/nxp,fxas21002c.yaml index 2c900e9dddc6..297d519d68f2 100644 --- a/Documentation/devicetree/bindings/iio/gyroscope/nxp,fxas21002c.yaml +++ b/Documentation/devicetree/bindings/iio/gyroscope/nxp,fxas21002c.yaml @@ -65,34 +65,34 @@ examples: - | #include <dt-bindings/interrupt-controller/irq.h> - i2c0 { + i2c { #address-cells = <1>; #size-cells = <0>; gyroscope@20 { - compatible = "nxp,fxas21002c"; - reg = <0x20>; + compatible = "nxp,fxas21002c"; + reg = <0x20>; - vdd-supply = <®_peri_3p15v>; - vddio-supply = <®_peri_3p15v>; + vdd-supply = <®_peri_3p15v>; + vddio-supply = <®_peri_3p15v>; - interrupt-parent = <&gpio1>; - interrupts = <7 IRQ_TYPE_EDGE_RISING>; - interrupt-names = "INT1"; + interrupt-parent = <&gpio1>; + interrupts = <7 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "INT1"; }; }; - spi0 { + spi { #address-cells = <1>; #size-cells = <0>; gyroscope@0 { - compatible = "nxp,fxas21002c"; - reg = <0x0>; + compatible = "nxp,fxas21002c"; + reg = <0x0>; - spi-max-frequency = <2000000>; + spi-max-frequency = <2000000>; - interrupt-parent = <&gpio2>; - interrupts = <7 IRQ_TYPE_EDGE_RISING>; - interrupt-names = "INT2"; + interrupt-parent = <&gpio2>; + interrupts = <7 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "INT2"; }; }; diff --git a/Documentation/devicetree/bindings/iio/health/ti,afe4403.yaml b/Documentation/devicetree/bindings/iio/health/ti,afe4403.yaml index 6c5ad426a016..b9b5beac33b2 100644 --- a/Documentation/devicetree/bindings/iio/health/ti,afe4403.yaml +++ b/Documentation/devicetree/bindings/iio/health/ti,afe4403.yaml @@ -42,7 +42,7 @@ examples: #address-cells = <1>; #size-cells = <0>; - heart_mon@0 { + heart-mon@0 { compatible = "ti,afe4403"; reg = <0>; spi-max-frequency = <10000000>; diff --git a/Documentation/devicetree/bindings/iio/health/ti,afe4404.yaml b/Documentation/devicetree/bindings/iio/health/ti,afe4404.yaml index c0e815d9999e..2958c4ca75b4 100644 --- a/Documentation/devicetree/bindings/iio/health/ti,afe4404.yaml +++ b/Documentation/devicetree/bindings/iio/health/ti,afe4404.yaml @@ -39,7 +39,7 @@ examples: #address-cells = <1>; #size-cells = <0>; - heart_mon@58 { + heart-mon@58 { compatible = "ti,afe4404"; reg = <0x58>; tx-supply = <&vbat>; diff --git a/Documentation/devicetree/bindings/iio/humidity/dht11.yaml b/Documentation/devicetree/bindings/iio/humidity/dht11.yaml index 2247481d0203..0103f4238942 100644 --- a/Documentation/devicetree/bindings/iio/humidity/dht11.yaml +++ b/Documentation/devicetree/bindings/iio/humidity/dht11.yaml @@ -34,7 +34,7 @@ additionalProperties: false examples: - | - humidity_sensor { + humidity-sensor { compatible = "dht11"; gpios = <&gpio0 6 0>; }; diff --git a/Documentation/devicetree/bindings/iio/humidity/ti,hdc2010.yaml b/Documentation/devicetree/bindings/iio/humidity/ti,hdc2010.yaml index 88384b69f917..a2bc1fa92da0 100644 --- a/Documentation/devicetree/bindings/iio/humidity/ti,hdc2010.yaml +++ b/Documentation/devicetree/bindings/iio/humidity/ti,hdc2010.yaml @@ -35,12 +35,12 @@ additionalProperties: false examples: - | - i2c0 { - #address-cells = <1>; - #size-cells = <0>; - - humidity@40 { - compatible = "ti,hdc2010"; - reg = <0x40>; - }; + i2c { + #address-cells = <1>; + #size-cells = <0>; + + humidity@40 { + compatible = "ti,hdc2010"; + reg = <0x40>; + }; }; diff --git a/Documentation/devicetree/bindings/iio/imu/adi,adis16460.yaml b/Documentation/devicetree/bindings/iio/imu/adi,adis16460.yaml index d166dbca18c3..4e43c80e5119 100644 --- a/Documentation/devicetree/bindings/iio/imu/adi,adis16460.yaml +++ b/Documentation/devicetree/bindings/iio/imu/adi,adis16460.yaml @@ -42,7 +42,7 @@ examples: - | #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/interrupt-controller/irq.h> - spi0 { + spi { #address-cells = <1>; #size-cells = <0>; diff --git a/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml b/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml index 5dbfae80bb28..c73533c54588 100644 --- a/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml +++ b/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml @@ -114,17 +114,17 @@ examples: - | #include <dt-bindings/interrupt-controller/irq.h> spi { - #address-cells = <1>; - #size-cells = <0>; - - adis16475: adis16475-3@0 { - compatible = "adi,adis16475-3"; - reg = <0>; - spi-cpha; - spi-cpol; - spi-max-frequency = <2000000>; - interrupts = <4 IRQ_TYPE_EDGE_RISING>; - interrupt-parent = <&gpio>; - }; + #address-cells = <1>; + #size-cells = <0>; + + adis16475: adis16475-3@0 { + compatible = "adi,adis16475-3"; + reg = <0>; + spi-cpha; + spi-cpol; + spi-max-frequency = <2000000>; + interrupts = <4 IRQ_TYPE_EDGE_RISING>; + interrupt-parent = <&gpio>; + }; }; ... diff --git a/Documentation/devicetree/bindings/iio/imu/bosch,bmi160.yaml b/Documentation/devicetree/bindings/iio/imu/bosch,bmi160.yaml index a0760382548d..47cfba939ca6 100644 --- a/Documentation/devicetree/bindings/iio/imu/bosch,bmi160.yaml +++ b/Documentation/devicetree/bindings/iio/imu/bosch,bmi160.yaml @@ -64,16 +64,16 @@ examples: #size-cells = <0>; bmi160@68 { - compatible = "bosch,bmi160"; - reg = <0x68>; - vdd-supply = <&pm8916_l17>; - vddio-supply = <&pm8916_l6>; - interrupt-parent = <&gpio4>; - interrupts = <12 IRQ_TYPE_EDGE_RISING>; - interrupt-names = "INT1"; - mount-matrix = "0", "1", "0", - "-1", "0", "0", - "0", "0", "1"; + compatible = "bosch,bmi160"; + reg = <0x68>; + vdd-supply = <&pm8916_l17>; + vddio-supply = <&pm8916_l6>; + interrupt-parent = <&gpio4>; + interrupts = <12 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "INT1"; + mount-matrix = "0", "1", "0", + "-1", "0", "0", + "0", "0", "1"; }; }; - | @@ -84,11 +84,11 @@ examples: #size-cells = <0>; bmi160@0 { - compatible = "bosch,bmi160"; - reg = <0>; - spi-max-frequency = <10000000>; - interrupt-parent = <&gpio2>; - interrupts = <12 IRQ_TYPE_EDGE_RISING>; - interrupt-names = "INT2"; + compatible = "bosch,bmi160"; + reg = <0>; + spi-max-frequency = <10000000>; + interrupt-parent = <&gpio2>; + interrupts = <12 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "INT2"; }; }; diff --git a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml index 13c9abdd3131..7cd05bcbee31 100644 --- a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml +++ b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml @@ -65,35 +65,35 @@ examples: - | #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/interrupt-controller/irq.h> - i2c0 { + i2c { #address-cells = <1>; #size-cells = <0>; icm42605@68 { - compatible = "invensense,icm42605"; - reg = <0x68>; - interrupt-parent = <&gpio2>; - interrupts = <7 IRQ_TYPE_EDGE_FALLING>; - vdd-supply = <&vdd>; - vddio-supply = <&vddio>; + compatible = "invensense,icm42605"; + reg = <0x68>; + interrupt-parent = <&gpio2>; + interrupts = <7 IRQ_TYPE_EDGE_FALLING>; + vdd-supply = <&vdd>; + vddio-supply = <&vddio>; }; }; - | #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/interrupt-controller/irq.h> - spi0 { + spi { #address-cells = <1>; #size-cells = <0>; icm42602@0 { - compatible = "invensense,icm42602"; - reg = <0>; - spi-max-frequency = <24000000>; - spi-cpha; - spi-cpol; - interrupt-parent = <&gpio1>; - interrupts = <2 IRQ_TYPE_EDGE_FALLING>; - vdd-supply = <&vdd>; - vddio-supply = <&vddio>; + compatible = "invensense,icm42602"; + reg = <0>; + spi-max-frequency = <24000000>; + spi-cpha; + spi-cpol; + interrupt-parent = <&gpio1>; + interrupts = <2 IRQ_TYPE_EDGE_FALLING>; + vdd-supply = <&vdd>; + vddio-supply = <&vddio>; }; }; diff --git a/Documentation/devicetree/bindings/iio/imu/nxp,fxos8700.yaml b/Documentation/devicetree/bindings/iio/imu/nxp,fxos8700.yaml index 24416b59b782..688100b240bc 100644 --- a/Documentation/devicetree/bindings/iio/imu/nxp,fxos8700.yaml +++ b/Documentation/devicetree/bindings/iio/imu/nxp,fxos8700.yaml @@ -49,33 +49,33 @@ examples: - | #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/interrupt-controller/irq.h> - i2c0 { + i2c { #address-cells = <1>; #size-cells = <0>; fxos8700@1e { - compatible = "nxp,fxos8700"; - reg = <0x1e>; + compatible = "nxp,fxos8700"; + reg = <0x1e>; - interrupt-parent = <&gpio2>; - interrupts = <7 IRQ_TYPE_EDGE_RISING>; - interrupt-names = "INT1"; + interrupt-parent = <&gpio2>; + interrupts = <7 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "INT1"; }; }; - | #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/interrupt-controller/irq.h> - spi0 { + spi { #address-cells = <1>; #size-cells = <0>; fxos8700@0 { - compatible = "nxp,fxos8700"; - reg = <0>; + compatible = "nxp,fxos8700"; + reg = <0>; - spi-max-frequency = <1000000>; - interrupt-parent = <&gpio1>; - interrupts = <7 IRQ_TYPE_EDGE_RISING>; - interrupt-names = "INT2"; + spi-max-frequency = <1000000>; + interrupt-parent = <&gpio1>; + interrupts = <7 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "INT2"; }; }; diff --git a/Documentation/devicetree/bindings/iio/imu/st,lsm6dsx.yaml b/Documentation/devicetree/bindings/iio/imu/st,lsm6dsx.yaml index 68b481c63318..decf022335d8 100644 --- a/Documentation/devicetree/bindings/iio/imu/st,lsm6dsx.yaml +++ b/Documentation/devicetree/bindings/iio/imu/st,lsm6dsx.yaml @@ -63,7 +63,7 @@ properties: description: if defined provides VDD IO power to the sensor. st,drdy-int-pin: - $ref: '/schemas/types.yaml#/definitions/uint32' + $ref: /schemas/types.yaml#/definitions/uint32 description: | The pin on the package that will be used to signal data ready enum: diff --git a/Documentation/devicetree/bindings/iio/magnetometer/ti,tmag5273.yaml b/Documentation/devicetree/bindings/iio/magnetometer/ti,tmag5273.yaml new file mode 100644 index 000000000000..121d540b7b6e --- /dev/null +++ b/Documentation/devicetree/bindings/iio/magnetometer/ti,tmag5273.yaml @@ -0,0 +1,75 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/magnetometer/ti,tmag5273.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TI TMAG5273 Low-Power Linear 3D Hall-Effect Sensor + +maintainers: + - Gerald Loacker <gerald.loacker@wolfvision.net> + +description: + The TI TMAG5273 is a low-power linear 3D Hall-effect sensor. This device + integrates three independent Hall-effect sensors in the X, Y, and Z axes. + The device has an integrated temperature sensor available. The TMAG5273 + can be configured through the I2C interface to enable any combination of + magnetic axes and temperature measurements. An integrated angle calculation + engine (CORDIC) provides full 360° angular position information for both + on-axis and off-axis angle measurement topologies. The angle calculation is + performed using two user-selected magnetic axes. + +properties: + compatible: + const: ti,tmag5273 + + reg: + maxItems: 1 + + "#io-channel-cells": + const: 1 + + ti,angle-measurement: + $ref: /schemas/types.yaml#/definitions/string + description: + Enables angle measurement in the selected plane. + If not specified, "x-y" will be anables as default. + enum: + - off + - x-y + - y-z + - x-z + + vcc-supply: + description: + A regulator providing 1.7 V to 3.6 V supply voltage on the VCC pin, + typically 3.3 V. + + interrupts: + description: + The low active interrupt can be configured to be fixed width or latched. + Interrupt events can be configured to be generated from magnetic + thresholds or when a conversion is completed. + maxItems: 1 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + magnetometer@35 { + compatible = "ti,tmag5273"; + reg = <0x35>; + #io-channel-cells = <1>; + ti,angle-measurement = "x-z"; + vcc-supply = <&vcc3v3>; + }; + }; +... diff --git a/Documentation/devicetree/bindings/iio/magnetometer/yamaha,yas530.yaml b/Documentation/devicetree/bindings/iio/magnetometer/yamaha,yas530.yaml index 9438fffaf0ba..877226e9219b 100644 --- a/Documentation/devicetree/bindings/iio/magnetometer/yamaha,yas530.yaml +++ b/Documentation/devicetree/bindings/iio/magnetometer/yamaha,yas530.yaml @@ -91,12 +91,12 @@ examples: #size-cells = <0>; magnetometer@2e { - compatible = "yamaha,yas530"; - reg = <0x2e>; - vdd-supply = <&ldo1_reg>; - iovdd-supply = <&ldo2_reg>; - reset-gpios = <&gpio6 12 GPIO_ACTIVE_LOW>; - interrupts = <13 IRQ_TYPE_EDGE_RISING>; + compatible = "yamaha,yas530"; + reg = <0x2e>; + vdd-supply = <&ldo1_reg>; + iovdd-supply = <&ldo2_reg>; + reset-gpios = <&gpio6 12 GPIO_ACTIVE_LOW>; + interrupts = <13 IRQ_TYPE_EDGE_RISING>; }; }; @@ -105,8 +105,8 @@ examples: #size-cells = <0>; magnetometer@2e { - compatible = "yamaha,yas539"; - reg = <0x2e>; - vdd-supply = <&ldo1_reg>; + compatible = "yamaha,yas539"; + reg = <0x2e>; + vdd-supply = <&ldo1_reg>; }; }; diff --git a/Documentation/devicetree/bindings/iio/potentiometer/adi,ad5272.yaml b/Documentation/devicetree/bindings/iio/potentiometer/adi,ad5272.yaml index 0ebb6725a1af..b8d7083c97f8 100644 --- a/Documentation/devicetree/bindings/iio/potentiometer/adi,ad5272.yaml +++ b/Documentation/devicetree/bindings/iio/potentiometer/adi,ad5272.yaml @@ -44,7 +44,7 @@ examples: potentiometer@2f { compatible = "adi,ad5272-020"; - reg = <0x2F>; + reg = <0x2f>; reset-gpios = <&gpio3 6 GPIO_ACTIVE_LOW>; }; }; diff --git a/Documentation/devicetree/bindings/iio/pressure/asc,dlhl60d.yaml b/Documentation/devicetree/bindings/iio/pressure/asc,dlhl60d.yaml index 1f9fe15b4b3c..9fb8d773efa3 100644 --- a/Documentation/devicetree/bindings/iio/pressure/asc,dlhl60d.yaml +++ b/Documentation/devicetree/bindings/iio/pressure/asc,dlhl60d.yaml @@ -39,7 +39,7 @@ examples: - | #include <dt-bindings/interrupt-controller/irq.h> - i2c0 { + i2c { #address-cells = <1>; #size-cells = <0>; diff --git a/Documentation/devicetree/bindings/iio/pressure/bmp085.yaml b/Documentation/devicetree/bindings/iio/pressure/bmp085.yaml index 72cd2c2d3f17..63885af6a74b 100644 --- a/Documentation/devicetree/bindings/iio/pressure/bmp085.yaml +++ b/Documentation/devicetree/bindings/iio/pressure/bmp085.yaml @@ -60,16 +60,16 @@ examples: - | #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/interrupt-controller/irq.h> - i2c0 { - #address-cells = <1>; - #size-cells = <0>; - pressure@77 { - compatible = "bosch,bmp085"; - reg = <0x77>; - interrupt-parent = <&gpio0>; - interrupts = <25 IRQ_TYPE_EDGE_RISING>; - reset-gpios = <&gpio0 26 GPIO_ACTIVE_LOW>; - vddd-supply = <&foo>; - vdda-supply = <&bar>; - }; + i2c { + #address-cells = <1>; + #size-cells = <0>; + pressure@77 { + compatible = "bosch,bmp085"; + reg = <0x77>; + interrupt-parent = <&gpio0>; + interrupts = <25 IRQ_TYPE_EDGE_RISING>; + reset-gpios = <&gpio0 26 GPIO_ACTIVE_LOW>; + vddd-supply = <&foo>; + vdda-supply = <&bar>; + }; }; diff --git a/Documentation/devicetree/bindings/iio/proximity/ams,as3935.yaml b/Documentation/devicetree/bindings/iio/proximity/ams,as3935.yaml index 710d3b9a86d9..c999994e19e3 100644 --- a/Documentation/devicetree/bindings/iio/proximity/ams,as3935.yaml +++ b/Documentation/devicetree/bindings/iio/proximity/ams,as3935.yaml @@ -60,7 +60,7 @@ examples: #address-cells = <1>; #size-cells = <0>; - lightning@0 { + lightning@0 { compatible = "ams,as3935"; reg = <0>; spi-max-frequency = <400000>; diff --git a/Documentation/devicetree/bindings/iio/proximity/google,cros-ec-mkbp-proximity.yaml b/Documentation/devicetree/bindings/iio/proximity/google,cros-ec-mkbp-proximity.yaml index 00e3b59641d2..d4e09d2dcd21 100644 --- a/Documentation/devicetree/bindings/iio/proximity/google,cros-ec-mkbp-proximity.yaml +++ b/Documentation/devicetree/bindings/iio/proximity/google,cros-ec-mkbp-proximity.yaml @@ -1,7 +1,6 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2 --- - $id: http://devicetree.org/schemas/iio/proximity/google,cros-ec-mkbp-proximity.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# diff --git a/Documentation/devicetree/bindings/iio/proximity/semtech,sx9360.yaml b/Documentation/devicetree/bindings/iio/proximity/semtech,sx9360.yaml index f088c5d2be99..ad0bb44f41b6 100644 --- a/Documentation/devicetree/bindings/iio/proximity/semtech,sx9360.yaml +++ b/Documentation/devicetree/bindings/iio/proximity/semtech,sx9360.yaml @@ -36,7 +36,7 @@ properties: const: 1 semtech,resolution: - $ref: /schemas/types.yaml#/definitions/uint32-array + $ref: /schemas/types.yaml#/definitions/uint32 enum: [8, 16, 32, 64, 128, 256, 512, 1024] description: Capacitance measurement resolution. For both phases, "reference" and diff --git a/Documentation/devicetree/bindings/iio/st,st-sensors.yaml b/Documentation/devicetree/bindings/iio/st,st-sensors.yaml index 250439b13152..c6201976378f 100644 --- a/Documentation/devicetree/bindings/iio/st,st-sensors.yaml +++ b/Documentation/devicetree/bindings/iio/st,st-sensors.yaml @@ -39,6 +39,7 @@ properties: - st,lis3lv02dl-accel - st,lng2dm-accel - st,lsm303agr-accel + - st,lsm303c-accel - st,lsm303dl-accel - st,lsm303dlh-accel - st,lsm303dlhc-accel @@ -66,6 +67,7 @@ properties: - st,lis2mdl - st,lis3mdl-magn - st,lsm303agr-magn + - st,lsm303c-magn - st,lsm303dlh-magn - st,lsm303dlhc-magn - st,lsm303dlm-magn diff --git a/Documentation/devicetree/bindings/iio/temperature/adi,ltc2983.yaml b/Documentation/devicetree/bindings/iio/temperature/adi,ltc2983.yaml index b69813f281da..f44fc32ce87e 100644 --- a/Documentation/devicetree/bindings/iio/temperature/adi,ltc2983.yaml +++ b/Documentation/devicetree/bindings/iio/temperature/adi,ltc2983.yaml @@ -472,75 +472,74 @@ examples: #size-cells = <0>; temperature-sensor@0 { - compatible = "adi,ltc2983"; - reg = <0>; - - #address-cells = <1>; - #size-cells = <0>; - - interrupts = <20 IRQ_TYPE_EDGE_RISING>; - interrupt-parent = <&gpio>; - - thermocouple@18 { - reg = <18>; - adi,sensor-type = <8>; //Type B - adi,sensor-oc-current-microamp = <10>; - adi,cold-junction-handle = <&diode5>; - }; - - diode5: diode@5 { - reg = <5>; - adi,sensor-type = <28>; - }; - - rsense2: rsense@2 { - reg = <2>; - adi,sensor-type = <29>; - adi,rsense-val-milli-ohms = <1200000>; //1.2Kohms - }; - - rtd@14 { - reg = <14>; - adi,sensor-type = <15>; //PT1000 - /*2-wire, internal gnd, no current rotation*/ - adi,number-of-wires = <2>; - adi,rsense-share; - adi,excitation-current-microamp = <500>; - adi,rsense-handle = <&rsense2>; - }; - - adc@10 { - reg = <10>; - adi,sensor-type = <30>; - adi,single-ended; - }; - - thermistor@12 { - reg = <12>; - adi,sensor-type = <26>; //Steinhart - adi,rsense-handle = <&rsense2>; - adi,custom-steinhart = <0x00F371EC 0x12345678 - 0x2C0F8733 0x10018C66 0xA0FEACCD - 0x90021D99>; //6 entries - }; - - thermocouple@20 { - reg = <20>; - adi,sensor-type = <9>; //custom thermocouple - adi,single-ended; - adi,custom-thermocouple = - /bits/ 64 <(-50220000) 0>, - /bits/ 64 <(-30200000) 99100000>, - /bits/ 64 <(-5300000) 135400000>, - /bits/ 64 <0 273150000>, - /bits/ 64 <40200000 361200000>, - /bits/ 64 <55300000 522100000>, - /bits/ 64 <88300000 720300000>, - /bits/ 64 <132200000 811200000>, - /bits/ 64 <188700000 922500000>, - /bits/ 64 <460400000 1000000000>; //10 pairs - }; - + compatible = "adi,ltc2983"; + reg = <0>; + + #address-cells = <1>; + #size-cells = <0>; + + interrupts = <20 IRQ_TYPE_EDGE_RISING>; + interrupt-parent = <&gpio>; + + thermocouple@18 { + reg = <18>; + adi,sensor-type = <8>; //Type B + adi,sensor-oc-current-microamp = <10>; + adi,cold-junction-handle = <&diode5>; + }; + + diode5: diode@5 { + reg = <5>; + adi,sensor-type = <28>; + }; + + rsense2: rsense@2 { + reg = <2>; + adi,sensor-type = <29>; + adi,rsense-val-milli-ohms = <1200000>; //1.2Kohms + }; + + rtd@14 { + reg = <14>; + adi,sensor-type = <15>; //PT1000 + /*2-wire, internal gnd, no current rotation*/ + adi,number-of-wires = <2>; + adi,rsense-share; + adi,excitation-current-microamp = <500>; + adi,rsense-handle = <&rsense2>; + }; + + adc@10 { + reg = <10>; + adi,sensor-type = <30>; + adi,single-ended; + }; + + thermistor@12 { + reg = <12>; + adi,sensor-type = <26>; //Steinhart + adi,rsense-handle = <&rsense2>; + adi,custom-steinhart = <0x00f371ec 0x12345678 + 0x2c0f8733 0x10018c66 0xa0feaccd + 0x90021d99>; //6 entries + }; + + thermocouple@20 { + reg = <20>; + adi,sensor-type = <9>; //custom thermocouple + adi,single-ended; + adi,custom-thermocouple = + /bits/ 64 <(-50220000) 0>, + /bits/ 64 <(-30200000) 99100000>, + /bits/ 64 <(-5300000) 135400000>, + /bits/ 64 <0 273150000>, + /bits/ 64 <40200000 361200000>, + /bits/ 64 <55300000 522100000>, + /bits/ 64 <88300000 720300000>, + /bits/ 64 <132200000 811200000>, + /bits/ 64 <188700000 922500000>, + /bits/ 64 <460400000 1000000000>; //10 pairs + }; }; }; ... diff --git a/Documentation/devicetree/bindings/iio/temperature/maxim,max31865.yaml b/Documentation/devicetree/bindings/iio/temperature/maxim,max31865.yaml index a2823ed6867b..7cc365e0ebc8 100644 --- a/Documentation/devicetree/bindings/iio/temperature/maxim,max31865.yaml +++ b/Documentation/devicetree/bindings/iio/temperature/maxim,max31865.yaml @@ -43,12 +43,12 @@ examples: #address-cells = <1>; #size-cells = <0>; - temp_sensor@0 { - compatible = "maxim,max31865"; - reg = <0>; - spi-max-frequency = <400000>; - spi-cpha; - maxim,3-wire; + temperature-sensor@0 { + compatible = "maxim,max31865"; + reg = <0>; + spi-max-frequency = <400000>; + spi-cpha; + maxim,3-wire; }; }; ... diff --git a/Documentation/devicetree/bindings/iio/temperature/ti,tmp117.yaml b/Documentation/devicetree/bindings/iio/temperature/ti,tmp117.yaml index 347bc16a4671..c4f1c69f9330 100644 --- a/Documentation/devicetree/bindings/iio/temperature/ti,tmp117.yaml +++ b/Documentation/devicetree/bindings/iio/temperature/ti,tmp117.yaml @@ -1,10 +1,10 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/iio/temperature/ti,tmp117.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/iio/temperature/ti,tmp117.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# -title: "TI TMP117 - Digital temperature sensor with integrated NV memory" +title: TI TMP117 - Digital temperature sensor with integrated NV memory description: | TI TMP117 - Digital temperature sensor with integrated NV memory that supports diff --git a/MAINTAINERS b/MAINTAINERS index bd30e1490465..c81bbb771678 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2090,8 +2090,10 @@ M: Hartley Sweeten <hsweeten@visionengravers.com> M: Alexander Sverdlin <alexander.sverdlin@gmail.com> L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained +F: Documentation/devicetree/bindings/iio/adc/cirrus,ep9301-adc.yaml F: arch/arm/mach-ep93xx/ F: arch/arm/mach-ep93xx/include/mach/ +F: drivers/iio/adc/ep93xx_adc.c ARM/CLKDEV SUPPORT M: Russell King <linux@armlinux.org.uk> @@ -15038,14 +15040,16 @@ S: Maintained F: Documentation/devicetree/bindings/iio/adc/nxp,imx8qxp-adc.yaml F: drivers/iio/adc/imx8qxp-adc.c -NXP i.MX 7D/6SX/6UL AND VF610 ADC DRIVER +NXP i.MX 7D/6SX/6UL/93 AND VF610 ADC DRIVER M: Haibo Chen <haibo.chen@nxp.com> L: linux-iio@vger.kernel.org L: linux-imx@nxp.com S: Maintained F: Documentation/devicetree/bindings/iio/adc/fsl,imx7d-adc.yaml F: Documentation/devicetree/bindings/iio/adc/fsl,vf610-adc.yaml +F: Documentation/devicetree/bindings/iio/adc/nxp,imx93-adc.yaml F: drivers/iio/adc/imx7d_adc.c +F: drivers/iio/adc/imx93_adc.c F: drivers/iio/adc/vf610_adc.c NXP PF8100/PF8121A/PF8200 PMIC REGULATOR DEVICE DRIVER @@ -20814,6 +20818,13 @@ M: Robert Richter <rric@kernel.org> S: Odd Fixes F: drivers/gpio/gpio-thunderx.c +TI ADS7924 ADC DRIVER +M: Hugo Villeneuve <hvilleneuve@dimonoff.com> +L: linux-iio@vger.kernel.org +S: Supported +F: Documentation/devicetree/bindings/iio/adc/ti,ads7924.yaml +F: drivers/iio/adc/ti-ads7924.c + TI AM437X VPFE DRIVER M: "Lad, Prabhakar" <prabhakar.csengg@gmail.com> L: linux-media@vger.kernel.org @@ -20934,6 +20945,14 @@ S: Maintained F: sound/soc/codecs/isabelle* F: sound/soc/codecs/lm49453* +TI LMP92064 ADC DRIVER +M: Leonard Göhrs <l.goehrs@pengutronix.de> +R: kernel@pengutronix.de +L: linux-iio@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/iio/adc/ti,lmp92064.yaml +F: drivers/iio/adc/ti-lmp92064.c + TI PCM3060 ASoC CODEC DRIVER M: Kirill Marinushkin <kmarinushkin@birdec.com> L: alsa-devel@alsa-project.org (moderated for non-subscribers) @@ -20947,6 +20966,13 @@ L: alsa-devel@alsa-project.org (moderated for non-subscribers) S: Odd Fixes F: sound/soc/codecs/tas571x* +TI TMAG5273 MAGNETOMETER DRIVER +M: Gerald Loacker <gerald.loacker@wolfvision.net> +L: linux-iio@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/iio/magnetometer/ti,tmag5273.yaml +F: drivers/iio/magnetometer/tmag5273.c + TI TRF7970A NFC DRIVER M: Mark Greer <mgreer@animalcreek.com> L: linux-wireless@vger.kernel.org diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index 03ac410c162e..b6b45d359f28 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -380,7 +380,7 @@ config IIO_ST_ACCEL_3AXIS select IIO_TRIGGERED_BUFFER if (IIO_BUFFER) help Say yes here to build support for STMicroelectronics accelerometers: - LSM303DLH, LSM303DLHC, LIS3DH, LSM330D, LSM330DL, LSM330DLC, + LSM303C, LSM303DLH, LSM303DLHC, LIS3DH, LSM330D, LSM330DL, LSM330DLC, LIS331DLH, LSM303DL, LSM303DLM, LSM330, LIS2DH12, H3LIS331DL, LNG2DM, LIS3DE, LIS2DE12, LIS2HH12 diff --git a/drivers/iio/accel/bma400.h b/drivers/iio/accel/bma400.h index 36edbaff4f7f..932358b45f17 100644 --- a/drivers/iio/accel/bma400.h +++ b/drivers/iio/accel/bma400.h @@ -141,10 +141,6 @@ #define BMA400_SCALE_MIN 9577 #define BMA400_SCALE_MAX 76617 -#define BMA400_NUM_REGULATORS 2 -#define BMA400_VDD_REGULATOR 0 -#define BMA400_VDDIO_REGULATOR 1 - extern const struct regmap_config bma400_regmap_config; int bma400_probe(struct device *dev, struct regmap *regmap, int irq, diff --git a/drivers/iio/accel/bma400_core.c b/drivers/iio/accel/bma400_core.c index b612d0146d4d..623f37cbaf50 100644 --- a/drivers/iio/accel/bma400_core.c +++ b/drivers/iio/accel/bma400_core.c @@ -98,7 +98,6 @@ enum bma400_activity { struct bma400_data { struct device *dev; struct regmap *regmap; - struct regulator_bulk_data regulators[BMA400_NUM_REGULATORS]; struct mutex mutex; /* data register lock */ struct iio_mount_matrix orientation; enum bma400_power_mode power_mode; @@ -832,13 +831,6 @@ static void bma400_init_tables(void) } } -static void bma400_regulators_disable(void *data_ptr) -{ - struct bma400_data *data = data_ptr; - - regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators); -} - static void bma400_power_disable(void *data_ptr) { struct bma400_data *data = data_ptr; @@ -868,30 +860,17 @@ static enum iio_modifier bma400_act_to_mod(enum bma400_activity activity) static int bma400_init(struct bma400_data *data) { + static const char * const regulator_names[] = { "vdd", "vddio" }; unsigned int val; int ret; - data->regulators[BMA400_VDD_REGULATOR].supply = "vdd"; - data->regulators[BMA400_VDDIO_REGULATOR].supply = "vddio"; - ret = devm_regulator_bulk_get(data->dev, - ARRAY_SIZE(data->regulators), - data->regulators); + ret = devm_regulator_bulk_get_enable(data->dev, + ARRAY_SIZE(regulator_names), + regulator_names); if (ret) return dev_err_probe(data->dev, ret, "Failed to get regulators: %d\n", ret); - ret = regulator_bulk_enable(ARRAY_SIZE(data->regulators), - data->regulators); - if (ret) { - dev_err(data->dev, "Failed to enable regulators: %d\n", - ret); - return ret; - } - - ret = devm_add_action_or_reset(data->dev, bma400_regulators_disable, data); - if (ret) - return ret; - /* Try to read chip_id register. It must return 0x90. */ ret = regmap_read(data->regmap, BMA400_CHIP_ID_REG, &val); if (ret) { diff --git a/drivers/iio/accel/mma9551_core.c b/drivers/iio/accel/mma9551_core.c index 64ca7d7a9673..b898f865fb87 100644 --- a/drivers/iio/accel/mma9551_core.c +++ b/drivers/iio/accel/mma9551_core.c @@ -296,9 +296,12 @@ int mma9551_read_config_word(struct i2c_client *client, u8 app_id, ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_CONFIG, reg, NULL, 0, (u8 *)&v, 2); + if (ret < 0) + return ret; + *val = be16_to_cpu(v); - return ret; + return 0; } EXPORT_SYMBOL_NS(mma9551_read_config_word, IIO_MMA9551); @@ -354,9 +357,12 @@ int mma9551_read_status_word(struct i2c_client *client, u8 app_id, ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS, reg, NULL, 0, (u8 *)&v, 2); + if (ret < 0) + return ret; + *val = be16_to_cpu(v); - return ret; + return 0; } EXPORT_SYMBOL_NS(mma9551_read_status_word, IIO_MMA9551); diff --git a/drivers/iio/accel/st_accel.h b/drivers/iio/accel/st_accel.h index 5b0f54e33d9e..56ed0c776d4a 100644 --- a/drivers/iio/accel/st_accel.h +++ b/drivers/iio/accel/st_accel.h @@ -37,6 +37,7 @@ #define LIS2DE12_ACCEL_DEV_NAME "lis2de12" #define LIS2HH12_ACCEL_DEV_NAME "lis2hh12" #define LIS302DL_ACCEL_DEV_NAME "lis302dl" +#define LSM303C_ACCEL_DEV_NAME "lsm303c_accel" #define SC7A20_ACCEL_DEV_NAME "sc7a20" diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index c8c8eb15c34e..6b8562f684d5 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -929,6 +929,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LIS2HH12_ACCEL_DEV_NAME, + [1] = LSM303C_ACCEL_DEV_NAME, }, .ch = (struct iio_chan_spec *)st_accel_16bit_channels, .odr = { diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c index 45ee0ddc133c..3f02fd5d5946 100644 --- a/drivers/iio/accel/st_accel_i2c.c +++ b/drivers/iio/accel/st_accel_i2c.c @@ -112,6 +112,10 @@ static const struct of_device_id st_accel_of_match[] = { .data = LIS302DL_ACCEL_DEV_NAME, }, { + .compatible = "st,lsm303c-accel", + .data = LSM303C_ACCEL_DEV_NAME, + }, + { .compatible = "silan,sc7a20", .data = SC7A20_ACCEL_DEV_NAME, }, @@ -151,6 +155,7 @@ static const struct i2c_device_id st_accel_id_table[] = { { LIS2DE12_ACCEL_DEV_NAME }, { LIS2HH12_ACCEL_DEV_NAME }, { LIS302DL_ACCEL_DEV_NAME }, + { LSM303C_ACCEL_DEV_NAME }, { SC7A20_ACCEL_DEV_NAME }, {}, }; diff --git a/drivers/iio/accel/st_accel_spi.c b/drivers/iio/accel/st_accel_spi.c index 6c0917750288..5740dc1820bd 100644 --- a/drivers/iio/accel/st_accel_spi.c +++ b/drivers/iio/accel/st_accel_spi.c @@ -96,6 +96,10 @@ static const struct of_device_id st_accel_of_match[] = { .compatible = "st,lis302dl", .data = LIS302DL_ACCEL_DEV_NAME, }, + { + .compatible = "st,lsm303c-accel", + .data = LSM303C_ACCEL_DEV_NAME, + }, {} }; MODULE_DEVICE_TABLE(of, st_accel_of_match); @@ -152,6 +156,7 @@ static const struct spi_device_id st_accel_id_table[] = { { LIS3DHH_ACCEL_DEV_NAME }, { LIS3DE_ACCEL_DEV_NAME }, { LIS302DL_ACCEL_DEV_NAME }, + { LSM303C_ACCEL_DEV_NAME }, {}, }; MODULE_DEVICE_TABLE(spi, st_accel_id_table); diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 63f80d747cbd..4a95c843a91b 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -441,7 +441,8 @@ config ENVELOPE_DETECTOR config EP93XX_ADC tristate "Cirrus Logic EP93XX ADC driver" - depends on ARCH_EP93XX + depends on ARCH_EP93XX || COMPILE_TEST + depends on HAS_IOMEM help Driver for the ADC module on the EP93XX series of SoC from Cirrus Logic. It's recommended to switch on CONFIG_HIGH_RES_TIMERS option, in this @@ -565,6 +566,16 @@ config IMX8QXP_ADC This driver can also be built as a module. If so, the module will be called imx8qxp-adc. +config IMX93_ADC + tristate "IMX93 ADC driver" + depends on ARCH_MXC || COMPILE_TEST + depends on HAS_IOMEM + help + Say yes here to build support for IMX93 ADC. + + This driver can also be built as a module. If so, the module will be + called imx93_adc. + config LP8788_ADC tristate "LP8788 ADC driver" depends on MFD_LP8788 @@ -1207,6 +1218,17 @@ config TI_ADS1015 This driver can also be built as a module. If so, the module will be called ti-ads1015. +config TI_ADS7924 + tristate "Texas Instruments ADS7924 ADC" + depends on I2C + select REGMAP_I2C + help + If you say yes here you get support for Texas Instruments ADS7924 + 4 channels, 12-bit I2C ADC chip. + + This driver can also be built as a module. If so, the module will be + called ti-ads7924. + config TI_ADS7950 tristate "Texas Instruments ADS7950 ADC driver" depends on SPI && GPIOLIB @@ -1274,6 +1296,16 @@ config TI_AM335X_ADC To compile this driver as a module, choose M here: the module will be called ti_am335x_adc. +config TI_LMP92064 + tristate "Texas Instruments LMP92064 ADC driver" + depends on SPI + help + Say yes here to build support for the LMP92064 Precision Current and Voltage + sensor. + + This driver can also be built as a module. If so, the module will be called + ti-lmp92064. + config TI_TLC4541 tristate "Texas Instruments TLC4541 ADC driver" depends on SPI diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 4ef41a7dfac6..36c18177322a 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -49,6 +49,7 @@ obj-$(CONFIG_HI8435) += hi8435.o obj-$(CONFIG_HX711) += hx711.o obj-$(CONFIG_IMX7D_ADC) += imx7d_adc.o obj-$(CONFIG_IMX8QXP_ADC) += imx8qxp-adc.o +obj-$(CONFIG_IMX93_ADC) += imx93_adc.o obj-$(CONFIG_INA2XX_ADC) += ina2xx-adc.o obj-$(CONFIG_INGENIC_ADC) += ingenic-adc.o obj-$(CONFIG_INTEL_MRFLD_ADC) += intel_mrfld_adc.o @@ -107,12 +108,14 @@ obj-$(CONFIG_TI_ADC108S102) += ti-adc108s102.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_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 obj-$(CONFIG_TI_TSC2046) += ti-tsc2046.o obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o diff --git a/drivers/iio/adc/ad7291.c b/drivers/iio/adc/ad7291.c index 3dd0105f63d7..f9ee189925de 100644 --- a/drivers/iio/adc/ad7291.c +++ b/drivers/iio/adc/ad7291.c @@ -179,7 +179,7 @@ static unsigned int ad7291_threshold_reg(const struct iio_chan_spec *chan, offset = AD7291_VOLTAGE_OFFSET; break; default: - return 0; + return 0; } switch (info) { diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c index ed4f8501bda8..50d02e5fc6fc 100644 --- a/drivers/iio/adc/at91-sama5d2_adc.c +++ b/drivers/iio/adc/at91-sama5d2_adc.c @@ -2181,7 +2181,7 @@ static ssize_t at91_adc_get_fifo_state(struct device *dev, struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct at91_adc_state *st = iio_priv(indio_dev); - return scnprintf(buf, PAGE_SIZE, "%d\n", !!st->dma_st.dma_chan); + return sysfs_emit(buf, "%d\n", !!st->dma_st.dma_chan); } static ssize_t at91_adc_get_watermark(struct device *dev, @@ -2190,7 +2190,7 @@ static ssize_t at91_adc_get_watermark(struct device *dev, struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct at91_adc_state *st = iio_priv(indio_dev); - return scnprintf(buf, PAGE_SIZE, "%d\n", st->dma_st.watermark); + return sysfs_emit(buf, "%d\n", st->dma_st.watermark); } static IIO_DEVICE_ATTR(hwfifo_enabled, 0444, diff --git a/drivers/iio/adc/ep93xx_adc.c b/drivers/iio/adc/ep93xx_adc.c index fd5a9404c8dc..a35e6cead67d 100644 --- a/drivers/iio/adc/ep93xx_adc.c +++ b/drivers/iio/adc/ep93xx_adc.c @@ -21,6 +21,7 @@ #include <linux/module.h> #include <linux/mutex.h> #include <linux/platform_device.h> +#include <linux/of.h> /* * This code could benefit from real HR Timers, but jiffy granularity would @@ -227,9 +228,16 @@ static int ep93xx_adc_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id ep93xx_adc_of_ids[] = { + { .compatible = "cirrus,ep9301-adc" }, + {} +}; +MODULE_DEVICE_TABLE(of, ep93xx_adc_of_ids); + static struct platform_driver ep93xx_adc_driver = { .driver = { .name = "ep93xx-adc", + .of_match_table = ep93xx_adc_of_ids, }, .probe = ep93xx_adc_probe, .remove = ep93xx_adc_remove, diff --git a/drivers/iio/adc/imx93_adc.c b/drivers/iio/adc/imx93_adc.c new file mode 100644 index 000000000000..a775d2e40567 --- /dev/null +++ b/drivers/iio/adc/imx93_adc.c @@ -0,0 +1,484 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * NXP i.MX93 ADC driver + * + * Copyright 2023 NXP + */ + +#include <linux/bitfield.h> +#include <linux/clk.h> +#include <linux/completion.h> +#include <linux/err.h> +#include <linux/iio/iio.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/regulator/consumer.h> + +#define IMX93_ADC_DRIVER_NAME "imx93-adc" + +/* Register map definition */ +#define IMX93_ADC_MCR 0x00 +#define IMX93_ADC_MSR 0x04 +#define IMX93_ADC_ISR 0x10 +#define IMX93_ADC_IMR 0x20 +#define IMX93_ADC_CIMR0 0x24 +#define IMX93_ADC_CTR0 0x94 +#define IMX93_ADC_NCMR0 0xA4 +#define IMX93_ADC_PCDR0 0x100 +#define IMX93_ADC_PCDR1 0x104 +#define IMX93_ADC_PCDR2 0x108 +#define IMX93_ADC_PCDR3 0x10c +#define IMX93_ADC_PCDR4 0x110 +#define IMX93_ADC_PCDR5 0x114 +#define IMX93_ADC_PCDR6 0x118 +#define IMX93_ADC_PCDR7 0x11c +#define IMX93_ADC_CALSTAT 0x39C + +/* ADC bit shift */ +#define IMX93_ADC_MCR_MODE_MASK BIT(29) +#define IMX93_ADC_MCR_NSTART_MASK BIT(24) +#define IMX93_ADC_MCR_CALSTART_MASK BIT(14) +#define IMX93_ADC_MCR_ADCLKSE_MASK BIT(8) +#define IMX93_ADC_MCR_PWDN_MASK BIT(0) +#define IMX93_ADC_MSR_CALFAIL_MASK BIT(30) +#define IMX93_ADC_MSR_CALBUSY_MASK BIT(29) +#define IMX93_ADC_MSR_ADCSTATUS_MASK GENMASK(2, 0) +#define IMX93_ADC_ISR_ECH_MASK BIT(0) +#define IMX93_ADC_ISR_EOC_MASK BIT(1) +#define IMX93_ADC_ISR_EOC_ECH_MASK (IMX93_ADC_ISR_EOC_MASK | \ + IMX93_ADC_ISR_ECH_MASK) +#define IMX93_ADC_IMR_JEOC_MASK BIT(3) +#define IMX93_ADC_IMR_JECH_MASK BIT(2) +#define IMX93_ADC_IMR_EOC_MASK BIT(1) +#define IMX93_ADC_IMR_ECH_MASK BIT(0) +#define IMX93_ADC_PCDR_CDATA_MASK GENMASK(11, 0) + +/* ADC status */ +#define IMX93_ADC_MSR_ADCSTATUS_IDLE 0 +#define IMX93_ADC_MSR_ADCSTATUS_POWER_DOWN 1 +#define IMX93_ADC_MSR_ADCSTATUS_WAIT_STATE 2 +#define IMX93_ADC_MSR_ADCSTATUS_BUSY_IN_CALIBRATION 3 +#define IMX93_ADC_MSR_ADCSTATUS_SAMPLE 4 +#define IMX93_ADC_MSR_ADCSTATUS_CONVERSION 6 + +#define IMX93_ADC_TIMEOUT msecs_to_jiffies(100) + +struct imx93_adc { + struct device *dev; + void __iomem *regs; + struct clk *ipg_clk; + int irq; + struct regulator *vref; + /* lock to protect against multiple access to the device */ + struct mutex lock; + struct completion completion; +}; + +#define IMX93_ADC_CHAN(_idx) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = (_idx), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ +} + +static const struct iio_chan_spec imx93_adc_iio_channels[] = { + IMX93_ADC_CHAN(0), + IMX93_ADC_CHAN(1), + IMX93_ADC_CHAN(2), + IMX93_ADC_CHAN(3), +}; + +static void imx93_adc_power_down(struct imx93_adc *adc) +{ + u32 mcr, msr; + int ret; + + mcr = readl(adc->regs + IMX93_ADC_MCR); + mcr |= FIELD_PREP(IMX93_ADC_MCR_PWDN_MASK, 1); + writel(mcr, adc->regs + IMX93_ADC_MCR); + + ret = readl_poll_timeout(adc->regs + IMX93_ADC_MSR, msr, + ((msr & IMX93_ADC_MSR_ADCSTATUS_MASK) == + IMX93_ADC_MSR_ADCSTATUS_POWER_DOWN), + 1, 50); + if (ret == -ETIMEDOUT) + dev_warn(adc->dev, + "ADC do not in power down mode, current MSR is %x\n", + msr); +} + +static void imx93_adc_power_up(struct imx93_adc *adc) +{ + u32 mcr; + + /* bring ADC out of power down state, in idle state */ + mcr = readl(adc->regs + IMX93_ADC_MCR); + mcr &= ~FIELD_PREP(IMX93_ADC_MCR_PWDN_MASK, 1); + writel(mcr, adc->regs + IMX93_ADC_MCR); +} + +static void imx93_adc_config_ad_clk(struct imx93_adc *adc) +{ + u32 mcr; + + /* put adc in power down mode */ + imx93_adc_power_down(adc); + + /* config the AD_CLK equal to bus clock */ + mcr = readl(adc->regs + IMX93_ADC_MCR); + mcr |= FIELD_PREP(IMX93_ADC_MCR_ADCLKSE_MASK, 1); + writel(mcr, adc->regs + IMX93_ADC_MCR); + + imx93_adc_power_up(adc); +} + +static int imx93_adc_calibration(struct imx93_adc *adc) +{ + u32 mcr, msr; + int ret; + + /* make sure ADC in power down mode */ + imx93_adc_power_down(adc); + + /* config SAR controller operating clock */ + mcr = readl(adc->regs + IMX93_ADC_MCR); + mcr &= ~FIELD_PREP(IMX93_ADC_MCR_ADCLKSE_MASK, 1); + writel(mcr, adc->regs + IMX93_ADC_MCR); + + imx93_adc_power_up(adc); + + /* + * TODO: we use the default TSAMP/NRSMPL/AVGEN in MCR, + * can add the setting of these bit if need in future. + */ + + /* run calibration */ + mcr = readl(adc->regs + IMX93_ADC_MCR); + mcr |= FIELD_PREP(IMX93_ADC_MCR_CALSTART_MASK, 1); + writel(mcr, adc->regs + IMX93_ADC_MCR); + + /* wait calibration to be finished */ + ret = readl_poll_timeout(adc->regs + IMX93_ADC_MSR, msr, + !(msr & IMX93_ADC_MSR_CALBUSY_MASK), 1000, 2000000); + if (ret == -ETIMEDOUT) { + dev_warn(adc->dev, "ADC do not finish calibration in 2 min!\n"); + imx93_adc_power_down(adc); + return ret; + } + + /* check whether calbration is success or not */ + msr = readl(adc->regs + IMX93_ADC_MSR); + if (msr & IMX93_ADC_MSR_CALFAIL_MASK) { + dev_warn(adc->dev, "ADC calibration failed!\n"); + imx93_adc_power_down(adc); + return -EAGAIN; + } + + return 0; +} + +static int imx93_adc_read_channel_conversion(struct imx93_adc *adc, + int channel_number, + int *result) +{ + u32 channel; + u32 imr, mcr, pcda; + long ret; + + reinit_completion(&adc->completion); + + /* config channel mask register */ + channel = 1 << channel_number; + writel(channel, adc->regs + IMX93_ADC_NCMR0); + + /* TODO: can config desired sample time in CTRn if need */ + + /* config interrupt mask */ + imr = FIELD_PREP(IMX93_ADC_IMR_EOC_MASK, 1); + writel(imr, adc->regs + IMX93_ADC_IMR); + writel(channel, adc->regs + IMX93_ADC_CIMR0); + + /* config one-shot mode */ + mcr = readl(adc->regs + IMX93_ADC_MCR); + mcr &= ~FIELD_PREP(IMX93_ADC_MCR_MODE_MASK, 1); + writel(mcr, adc->regs + IMX93_ADC_MCR); + + /* start normal conversion */ + mcr = readl(adc->regs + IMX93_ADC_MCR); + mcr |= FIELD_PREP(IMX93_ADC_MCR_NSTART_MASK, 1); + writel(mcr, adc->regs + IMX93_ADC_MCR); + + ret = wait_for_completion_interruptible_timeout(&adc->completion, + IMX93_ADC_TIMEOUT); + if (ret == 0) + return -ETIMEDOUT; + + if (ret < 0) + return ret; + + pcda = readl(adc->regs + IMX93_ADC_PCDR0 + channel_number * 4); + + *result = FIELD_GET(IMX93_ADC_PCDR_CDATA_MASK, pcda); + + return ret; +} + +static int imx93_adc_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct imx93_adc *adc = iio_priv(indio_dev); + struct device *dev = adc->dev; + long ret; + u32 vref_uv; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + pm_runtime_get_sync(dev); + mutex_lock(&adc->lock); + ret = imx93_adc_read_channel_conversion(adc, chan->channel, val); + mutex_unlock(&adc->lock); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_sync_autosuspend(dev); + if (ret < 0) + return ret; + + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SCALE: + ret = vref_uv = regulator_get_voltage(adc->vref); + if (ret < 0) + return ret; + *val = vref_uv / 1000; + *val2 = 12; + return IIO_VAL_FRACTIONAL_LOG2; + + case IIO_CHAN_INFO_SAMP_FREQ: + *val = clk_get_rate(adc->ipg_clk); + return IIO_VAL_INT; + + default: + return -EINVAL; + } +} + +static irqreturn_t imx93_adc_isr(int irq, void *dev_id) +{ + struct imx93_adc *adc = dev_id; + u32 isr, eoc, unexpected; + + isr = readl(adc->regs + IMX93_ADC_ISR); + + if (FIELD_GET(IMX93_ADC_ISR_EOC_ECH_MASK, isr)) { + eoc = isr & IMX93_ADC_ISR_EOC_ECH_MASK; + writel(eoc, adc->regs + IMX93_ADC_ISR); + complete(&adc->completion); + } + + unexpected = isr & ~IMX93_ADC_ISR_EOC_ECH_MASK; + if (unexpected) { + writel(unexpected, adc->regs + IMX93_ADC_ISR); + dev_err(adc->dev, "Unexpected interrupt 0x%08x.\n", unexpected); + return IRQ_NONE; + } + + return IRQ_HANDLED; +} + +static const struct iio_info imx93_adc_iio_info = { + .read_raw = &imx93_adc_read_raw, +}; + +static int imx93_adc_probe(struct platform_device *pdev) +{ + struct imx93_adc *adc; + struct iio_dev *indio_dev; + struct device *dev = &pdev->dev; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*adc)); + if (!indio_dev) + return dev_err_probe(dev, -ENOMEM, + "Failed allocating iio device\n"); + + adc = iio_priv(indio_dev); + adc->dev = dev; + + mutex_init(&adc->lock); + adc->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(adc->regs)) + return dev_err_probe(dev, PTR_ERR(adc->regs), + "Failed getting ioremap resource\n"); + + /* The third irq is for ADC conversion usage */ + adc->irq = platform_get_irq(pdev, 2); + if (adc->irq < 0) + return adc->irq; + + adc->ipg_clk = devm_clk_get(dev, "ipg"); + if (IS_ERR(adc->ipg_clk)) + return dev_err_probe(dev, PTR_ERR(adc->ipg_clk), + "Failed getting clock.\n"); + + adc->vref = devm_regulator_get(dev, "vref"); + if (IS_ERR(adc->vref)) + return dev_err_probe(dev, PTR_ERR(adc->vref), + "Failed getting reference voltage.\n"); + + ret = regulator_enable(adc->vref); + if (ret) + return dev_err_probe(dev, ret, + "Failed to enable reference voltage.\n"); + + platform_set_drvdata(pdev, indio_dev); + + init_completion(&adc->completion); + + indio_dev->name = "imx93-adc"; + indio_dev->info = &imx93_adc_iio_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = imx93_adc_iio_channels; + indio_dev->num_channels = ARRAY_SIZE(imx93_adc_iio_channels); + + ret = clk_prepare_enable(adc->ipg_clk); + if (ret) { + dev_err_probe(dev, ret, + "Failed to enable ipg clock.\n"); + goto error_regulator_disable; + } + + ret = request_irq(adc->irq, imx93_adc_isr, 0, IMX93_ADC_DRIVER_NAME, adc); + if (ret < 0) { + dev_err_probe(dev, ret, + "Failed requesting irq, irq = %d\n", adc->irq); + goto error_ipg_clk_disable; + } + + ret = imx93_adc_calibration(adc); + if (ret < 0) + goto error_free_adc_irq; + + imx93_adc_config_ad_clk(adc); + + ret = iio_device_register(indio_dev); + if (ret) { + dev_err_probe(dev, ret, + "Failed to register this iio device.\n"); + goto error_adc_power_down; + } + + pm_runtime_set_active(dev); + pm_runtime_set_autosuspend_delay(dev, 50); + pm_runtime_use_autosuspend(dev); + pm_runtime_enable(dev); + + return 0; + +error_adc_power_down: + imx93_adc_power_down(adc); +error_free_adc_irq: + free_irq(adc->irq, adc); +error_ipg_clk_disable: + clk_disable_unprepare(adc->ipg_clk); +error_regulator_disable: + regulator_disable(adc->vref); + + return ret; +} + +static int imx93_adc_remove(struct platform_device *pdev) +{ + struct iio_dev *indio_dev = platform_get_drvdata(pdev); + struct imx93_adc *adc = iio_priv(indio_dev); + struct device *dev = adc->dev; + + /* adc power down need clock on */ + pm_runtime_get_sync(dev); + + pm_runtime_disable(dev); + pm_runtime_dont_use_autosuspend(dev); + pm_runtime_put_noidle(dev); + + iio_device_unregister(indio_dev); + imx93_adc_power_down(adc); + free_irq(adc->irq, adc); + clk_disable_unprepare(adc->ipg_clk); + regulator_disable(adc->vref); + + return 0; +} + +static int imx93_adc_runtime_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct imx93_adc *adc = iio_priv(indio_dev); + + imx93_adc_power_down(adc); + clk_disable_unprepare(adc->ipg_clk); + regulator_disable(adc->vref); + + return 0; +} + +static int imx93_adc_runtime_resume(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct imx93_adc *adc = iio_priv(indio_dev); + int ret; + + ret = regulator_enable(adc->vref); + if (ret) { + dev_err(dev, + "Can't enable adc reference top voltage, err = %d\n", + ret); + return ret; + } + + ret = clk_prepare_enable(adc->ipg_clk); + if (ret) { + dev_err(dev, "Could not prepare or enable clock.\n"); + goto err_disable_reg; + } + + imx93_adc_power_up(adc); + + return 0; + +err_disable_reg: + regulator_disable(adc->vref); + + return ret; +} + +static DEFINE_RUNTIME_DEV_PM_OPS(imx93_adc_pm_ops, + imx93_adc_runtime_suspend, + imx93_adc_runtime_resume, NULL); + +static const struct of_device_id imx93_adc_match[] = { + { .compatible = "nxp,imx93-adc", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, imx93_adc_match); + +static struct platform_driver imx93_adc_driver = { + .probe = imx93_adc_probe, + .remove = imx93_adc_remove, + .driver = { + .name = IMX93_ADC_DRIVER_NAME, + .of_match_table = imx93_adc_match, + .pm = pm_ptr(&imx93_adc_pm_ops), + }, +}; + +module_platform_driver(imx93_adc_driver); + +MODULE_DESCRIPTION("NXP i.MX93 ADC driver"); +MODULE_AUTHOR("Haibo Chen <haibo.chen@nxp.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/adc/max11410.c b/drivers/iio/adc/max11410.c index fdc9f03135b5..b74b689ee7de 100644 --- a/drivers/iio/adc/max11410.c +++ b/drivers/iio/adc/max11410.c @@ -4,7 +4,6 @@ * * Copyright 2022 Analog Devices Inc. */ -#include <asm-generic/unaligned.h> #include <linux/bitfield.h> #include <linux/delay.h> #include <linux/device.h> @@ -16,6 +15,8 @@ #include <linux/regulator/consumer.h> #include <linux/spi/spi.h> +#include <asm/unaligned.h> + #include <linux/iio/buffer.h> #include <linux/iio/sysfs.h> #include <linux/iio/trigger.h> diff --git a/drivers/iio/adc/qcom-spmi-adc5.c b/drivers/iio/adc/qcom-spmi-adc5.c index 821fee60a765..e90c299c913a 100644 --- a/drivers/iio/adc/qcom-spmi-adc5.c +++ b/drivers/iio/adc/qcom-spmi-adc5.c @@ -543,6 +543,8 @@ static const struct adc5_channels adc5_chans_pmic[ADC5_MAX_CHANNEL] = { SCALE_HW_CALIB_DEFAULT) [ADC5_XO_THERM_100K_PU] = ADC5_CHAN_TEMP("xo_therm", 0, SCALE_HW_CALIB_XOTHERM) + [ADC5_BAT_ID_100K_PU] = ADC5_CHAN_TEMP("bat_id", 0, + SCALE_HW_CALIB_DEFAULT) [ADC5_AMUX_THM1_100K_PU] = ADC5_CHAN_TEMP("amux_thm1_100k_pu", 0, SCALE_HW_CALIB_THERM_100K_PULLUP) [ADC5_AMUX_THM2_100K_PU] = ADC5_CHAN_TEMP("amux_thm2_100k_pu", 0, @@ -894,10 +896,8 @@ static int adc5_probe(struct platform_device *pdev) mutex_init(&adc->lock); ret = adc5_get_fw_data(adc); - if (ret) { - dev_err(dev, "adc get dt data failed\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "adc get dt data failed\n"); irq_eoc = platform_get_irq(pdev, 0); if (irq_eoc < 0) { diff --git a/drivers/iio/adc/stm32-dfsdm-core.c b/drivers/iio/adc/stm32-dfsdm-core.c index a3d4de6ba4c2..0362df285a57 100644 --- a/drivers/iio/adc/stm32-dfsdm-core.c +++ b/drivers/iio/adc/stm32-dfsdm-core.c @@ -6,6 +6,7 @@ * Author(s): Arnaud Pouliquen <arnaud.pouliquen@st.com> for STMicroelectronics. */ +#include <linux/bitfield.h> #include <linux/clk.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> @@ -19,7 +20,15 @@ #include "stm32-dfsdm.h" +/** + * struct stm32_dfsdm_dev_data - DFSDM compatible configuration data + * @ipid: DFSDM identification number. Used only if hardware provides identification registers + * @num_filters: DFSDM number of filters. Unused if identification registers are available + * @num_channels: DFSDM number of channels. Unused if identification registers are available + * @regmap_cfg: SAI register map configuration pointer + */ struct stm32_dfsdm_dev_data { + u32 ipid; unsigned int num_filters; unsigned int num_channels; const struct regmap_config *regmap_cfg; @@ -27,8 +36,6 @@ struct stm32_dfsdm_dev_data { #define STM32H7_DFSDM_NUM_FILTERS 4 #define STM32H7_DFSDM_NUM_CHANNELS 8 -#define STM32MP1_DFSDM_NUM_FILTERS 6 -#define STM32MP1_DFSDM_NUM_CHANNELS 8 static bool stm32_dfsdm_volatile_reg(struct device *dev, unsigned int reg) { @@ -75,8 +82,7 @@ static const struct regmap_config stm32mp1_dfsdm_regmap_cfg = { }; static const struct stm32_dfsdm_dev_data stm32mp1_dfsdm_data = { - .num_filters = STM32MP1_DFSDM_NUM_FILTERS, - .num_channels = STM32MP1_DFSDM_NUM_CHANNELS, + .ipid = STM32MP15_IPIDR_NUMBER, .regmap_cfg = &stm32mp1_dfsdm_regmap_cfg, }; @@ -295,6 +301,65 @@ static const struct of_device_id stm32_dfsdm_of_match[] = { }; MODULE_DEVICE_TABLE(of, stm32_dfsdm_of_match); +static int stm32_dfsdm_probe_identification(struct platform_device *pdev, + struct dfsdm_priv *priv, + const struct stm32_dfsdm_dev_data *dev_data) +{ + struct device_node *np = pdev->dev.of_node; + struct device_node *child; + struct stm32_dfsdm *dfsdm = &priv->dfsdm; + const char *compat; + int ret, count = 0; + u32 id, val; + + if (!dev_data->ipid) { + dfsdm->num_fls = dev_data->num_filters; + dfsdm->num_chs = dev_data->num_channels; + return 0; + } + + ret = regmap_read(dfsdm->regmap, DFSDM_IPIDR, &id); + if (ret) + return ret; + + if (id != dev_data->ipid) { + dev_err(&pdev->dev, "Unexpected IP version: 0x%x", id); + return -EINVAL; + } + + for_each_child_of_node(np, child) { + ret = of_property_read_string(child, "compatible", &compat); + if (ret) + continue; + /* Count only child nodes with dfsdm compatible */ + if (strstr(compat, "dfsdm")) + count++; + } + + ret = regmap_read(dfsdm->regmap, DFSDM_HWCFGR, &val); + if (ret) + return ret; + + dfsdm->num_fls = FIELD_GET(DFSDM_HWCFGR_NBF_MASK, val); + dfsdm->num_chs = FIELD_GET(DFSDM_HWCFGR_NBT_MASK, val); + + if (count > dfsdm->num_fls) { + dev_err(&pdev->dev, "Unexpected child number: %d", count); + return -EINVAL; + } + + ret = regmap_read(dfsdm->regmap, DFSDM_VERR, &val); + if (ret) + return ret; + + dev_dbg(&pdev->dev, "DFSDM version: %lu.%lu. %d channels/%d filters\n", + FIELD_GET(DFSDM_VERR_MAJREV_MASK, val), + FIELD_GET(DFSDM_VERR_MINREV_MASK, val), + dfsdm->num_chs, dfsdm->num_fls); + + return 0; +} + static int stm32_dfsdm_probe(struct platform_device *pdev) { struct dfsdm_priv *priv; @@ -311,18 +376,6 @@ static int stm32_dfsdm_probe(struct platform_device *pdev) dev_data = of_device_get_match_data(&pdev->dev); dfsdm = &priv->dfsdm; - dfsdm->fl_list = devm_kcalloc(&pdev->dev, dev_data->num_filters, - sizeof(*dfsdm->fl_list), GFP_KERNEL); - if (!dfsdm->fl_list) - return -ENOMEM; - - dfsdm->num_fls = dev_data->num_filters; - dfsdm->ch_list = devm_kcalloc(&pdev->dev, dev_data->num_channels, - sizeof(*dfsdm->ch_list), - GFP_KERNEL); - if (!dfsdm->ch_list) - return -ENOMEM; - dfsdm->num_chs = dev_data->num_channels; ret = stm32_dfsdm_parse_of(pdev, priv); if (ret < 0) @@ -338,6 +391,20 @@ static int stm32_dfsdm_probe(struct platform_device *pdev) return ret; } + ret = stm32_dfsdm_probe_identification(pdev, priv, dev_data); + if (ret < 0) + return ret; + + dfsdm->fl_list = devm_kcalloc(&pdev->dev, dfsdm->num_fls, + sizeof(*dfsdm->fl_list), GFP_KERNEL); + if (!dfsdm->fl_list) + return -ENOMEM; + + dfsdm->ch_list = devm_kcalloc(&pdev->dev, dfsdm->num_chs, + sizeof(*dfsdm->ch_list), GFP_KERNEL); + if (!dfsdm->ch_list) + return -ENOMEM; + platform_set_drvdata(pdev, dfsdm); ret = stm32_dfsdm_clk_prepare_enable(dfsdm); diff --git a/drivers/iio/adc/stm32-dfsdm.h b/drivers/iio/adc/stm32-dfsdm.h index 4afc1f528b78..570a1552aec4 100644 --- a/drivers/iio/adc/stm32-dfsdm.h +++ b/drivers/iio/adc/stm32-dfsdm.h @@ -13,25 +13,29 @@ /* * STM32 DFSDM - global register map - * ________________________________________________________ - * | Offset | Registers block | - * -------------------------------------------------------- - * | 0x000 | CHANNEL 0 + COMMON CHANNEL FIELDS | - * -------------------------------------------------------- - * | 0x020 | CHANNEL 1 | - * -------------------------------------------------------- - * | ... | ..... | - * -------------------------------------------------------- - * | 0x0E0 | CHANNEL 7 | - * -------------------------------------------------------- - * | 0x100 | FILTER 0 + COMMON FILTER FIELDs | - * -------------------------------------------------------- - * | 0x200 | FILTER 1 | - * -------------------------------------------------------- - * | 0x300 | FILTER 2 | - * -------------------------------------------------------- - * | 0x400 | FILTER 3 | - * -------------------------------------------------------- + * __________________________________________________________ + * | Offset | Registers block | + * ---------------------------------------------------------- + * | 0x000 | CHANNEL 0 + COMMON CHANNEL FIELDS | + * ---------------------------------------------------------- + * | 0x020 | CHANNEL 1 | + * ---------------------------------------------------------- + * | ... | ..... | + * ---------------------------------------------------------- + * | 0x20 x n | CHANNEL n | + * ---------------------------------------------------------- + * | 0x100 | FILTER 0 + COMMON FILTER FIELDs | + * ---------------------------------------------------------- + * | 0x200 | FILTER 1 | + * ---------------------------------------------------------- + * | | ..... | + * ---------------------------------------------------------- + * | 0x100 x m | FILTER m | + * ---------------------------------------------------------- + * | | ..... | + * ---------------------------------------------------------- + * | 0x7F0-7FC | Identification registers | + * ---------------------------------------------------------- */ /* @@ -231,6 +235,24 @@ #define DFSDM_AWCFR_AWHTF_MASK GENMASK(15, 8) #define DFSDM_AWCFR_AWHTF(v) FIELD_PREP(DFSDM_AWCFR_AWHTF_MASK, v) +/* + * Identification register definitions + */ +#define DFSDM_HWCFGR 0x7F0 +#define DFSDM_VERR 0x7F4 +#define DFSDM_IPIDR 0x7F8 +#define DFSDM_SIDR 0x7FC + +/* HWCFGR: Hardware configuration register */ +#define DFSDM_HWCFGR_NBT_MASK GENMASK(7, 0) +#define DFSDM_HWCFGR_NBF_MASK GENMASK(15, 8) + +/* VERR: Version register */ +#define DFSDM_VERR_MINREV_MASK GENMASK(3, 0) +#define DFSDM_VERR_MAJREV_MASK GENMASK(7, 4) + +#define STM32MP15_IPIDR_NUMBER 0x00110031 + /* DFSDM filter order */ enum stm32_dfsdm_sinc_order { DFSDM_FASTSINC_ORDER, /* FastSinc filter type */ diff --git a/drivers/iio/adc/ti-adc128s052.c b/drivers/iio/adc/ti-adc128s052.c index b3d5b9b7255b..a456ea78462f 100644 --- a/drivers/iio/adc/ti-adc128s052.c +++ b/drivers/iio/adc/ti-adc128s052.c @@ -9,14 +9,13 @@ * https://www.ti.com/lit/ds/symlink/adc124s021.pdf */ -#include <linux/acpi.h> #include <linux/err.h> -#include <linux/spi/spi.h> -#include <linux/module.h> -#include <linux/mod_devicetable.h> #include <linux/iio/iio.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> #include <linux/property.h> #include <linux/regulator/consumer.h> +#include <linux/spi/spi.h> struct adc128_configuration { const struct iio_chan_spec *channels; @@ -139,16 +138,11 @@ static void adc128_disable_regulator(void *reg) static int adc128_probe(struct spi_device *spi) { + const struct adc128_configuration *config; struct iio_dev *indio_dev; - unsigned int config; struct adc128 *adc; int ret; - if (dev_fwnode(&spi->dev)) - config = (unsigned long) device_get_match_data(&spi->dev); - else - config = spi_get_device_id(spi)->driver_data; - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc)); if (!indio_dev) return -ENOMEM; @@ -160,8 +154,10 @@ static int adc128_probe(struct spi_device *spi) indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &adc128_info; - indio_dev->channels = adc128_config[config].channels; - indio_dev->num_channels = adc128_config[config].num_channels; + config = spi_get_device_match_data(spi); + + indio_dev->channels = config->channels; + indio_dev->num_channels = config->num_channels; adc->reg = devm_regulator_get(&spi->dev, "vref"); if (IS_ERR(adc->reg)) @@ -181,42 +177,40 @@ static int adc128_probe(struct spi_device *spi) } static const struct of_device_id adc128_of_match[] = { - { .compatible = "ti,adc128s052", .data = (void*)0L, }, - { .compatible = "ti,adc122s021", .data = (void*)1L, }, - { .compatible = "ti,adc122s051", .data = (void*)1L, }, - { .compatible = "ti,adc122s101", .data = (void*)1L, }, - { .compatible = "ti,adc124s021", .data = (void*)2L, }, - { .compatible = "ti,adc124s051", .data = (void*)2L, }, - { .compatible = "ti,adc124s101", .data = (void*)2L, }, + { .compatible = "ti,adc128s052", .data = &adc128_config[0] }, + { .compatible = "ti,adc122s021", .data = &adc128_config[1] }, + { .compatible = "ti,adc122s051", .data = &adc128_config[1] }, + { .compatible = "ti,adc122s101", .data = &adc128_config[1] }, + { .compatible = "ti,adc124s021", .data = &adc128_config[2] }, + { .compatible = "ti,adc124s051", .data = &adc128_config[2] }, + { .compatible = "ti,adc124s101", .data = &adc128_config[2] }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, adc128_of_match); static const struct spi_device_id adc128_id[] = { - { "adc128s052", 0 }, /* index into adc128_config */ - { "adc122s021", 1 }, - { "adc122s051", 1 }, - { "adc122s101", 1 }, - { "adc124s021", 2 }, - { "adc124s051", 2 }, - { "adc124s101", 2 }, + { "adc128s052", (kernel_ulong_t)&adc128_config[0] }, + { "adc122s021", (kernel_ulong_t)&adc128_config[1] }, + { "adc122s051", (kernel_ulong_t)&adc128_config[1] }, + { "adc122s101", (kernel_ulong_t)&adc128_config[1] }, + { "adc124s021", (kernel_ulong_t)&adc128_config[2] }, + { "adc124s051", (kernel_ulong_t)&adc128_config[2] }, + { "adc124s101", (kernel_ulong_t)&adc128_config[2] }, { } }; MODULE_DEVICE_TABLE(spi, adc128_id); -#ifdef CONFIG_ACPI static const struct acpi_device_id adc128_acpi_match[] = { - { "AANT1280", 2 }, /* ADC124S021 compatible ACPI ID */ + { "AANT1280", (kernel_ulong_t)&adc128_config[2] }, { } }; MODULE_DEVICE_TABLE(acpi, adc128_acpi_match); -#endif static struct spi_driver adc128_driver = { .driver = { .name = "adc128s052", .of_match_table = adc128_of_match, - .acpi_match_table = ACPI_PTR(adc128_acpi_match), + .acpi_match_table = adc128_acpi_match, }, .probe = adc128_probe, .id_table = adc128_id, diff --git a/drivers/iio/adc/ti-ads7924.c b/drivers/iio/adc/ti-ads7924.c new file mode 100644 index 000000000000..b02abb026966 --- /dev/null +++ b/drivers/iio/adc/ti-ads7924.c @@ -0,0 +1,474 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IIO driver for Texas Instruments ADS7924 ADC, 12-bit, 4-Channels, I2C + * + * Author: Hugo Villeneuve <hvilleneuve@dimonoff.com> + * Copyright 2022 DimOnOff + * + * based on iio/adc/ti-ads1015.c + * Copyright (c) 2016, Intel Corporation. + * + * Datasheet: https://www.ti.com/lit/gpn/ads7924 + */ + +#include <linux/bitfield.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/init.h> +#include <linux/irq.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> + +#include <linux/iio/iio.h> +#include <linux/iio/types.h> + +#define ADS7924_CHANNELS 4 +#define ADS7924_BITS 12 +#define ADS7924_DATA_SHIFT 4 + +/* Registers. */ +#define ADS7924_MODECNTRL_REG 0x00 +#define ADS7924_INTCNTRL_REG 0x01 +#define ADS7924_DATA0_U_REG 0x02 +#define ADS7924_DATA0_L_REG 0x03 +#define ADS7924_DATA1_U_REG 0x04 +#define ADS7924_DATA1_L_REG 0x05 +#define ADS7924_DATA2_U_REG 0x06 +#define ADS7924_DATA2_L_REG 0x07 +#define ADS7924_DATA3_U_REG 0x08 +#define ADS7924_DATA3_L_REG 0x09 +#define ADS7924_ULR0_REG 0x0A +#define ADS7924_LLR0_REG 0x0B +#define ADS7924_ULR1_REG 0x0C +#define ADS7924_LLR1_REG 0x0D +#define ADS7924_ULR2_REG 0x0E +#define ADS7924_LLR2_REG 0x0F +#define ADS7924_ULR3_REG 0x10 +#define ADS7924_LLR3_REG 0x11 +#define ADS7924_INTCONFIG_REG 0x12 +#define ADS7924_SLPCONFIG_REG 0x13 +#define ADS7924_ACQCONFIG_REG 0x14 +#define ADS7924_PWRCONFIG_REG 0x15 +#define ADS7924_RESET_REG 0x16 + +/* + * Register address INC bit: when set to '1', the register address is + * automatically incremented after every register read which allows convenient + * reading of multiple registers. Set INC to '0' when reading a single register. + */ +#define ADS7924_AUTO_INCREMENT_BIT BIT(7) + +#define ADS7924_MODECNTRL_MODE_MASK GENMASK(7, 2) + +#define ADS7924_MODECNTRL_SEL_MASK GENMASK(1, 0) + +#define ADS7924_CFG_INTPOL_BIT 1 +#define ADS7924_CFG_INTTRIG_BIT 0 + +#define ADS7924_CFG_INTPOL_MASK BIT(ADS7924_CFG_INTPOL_BIT) +#define ADS7924_CFG_INTTRIG_MASK BIT(ADS7924_CFG_INTTRIG_BIT) + +/* Interrupt pin polarity */ +#define ADS7924_CFG_INTPOL_LOW 0 +#define ADS7924_CFG_INTPOL_HIGH 1 + +/* Interrupt pin signaling */ +#define ADS7924_CFG_INTTRIG_LEVEL 0 +#define ADS7924_CFG_INTTRIG_EDGE 1 + +/* Mode control values */ +#define ADS7924_MODECNTRL_IDLE 0x00 +#define ADS7924_MODECNTRL_AWAKE 0x20 +#define ADS7924_MODECNTRL_MANUAL_SINGLE 0x30 +#define ADS7924_MODECNTRL_MANUAL_SCAN 0x32 +#define ADS7924_MODECNTRL_AUTO_SINGLE 0x31 +#define ADS7924_MODECNTRL_AUTO_SCAN 0x33 +#define ADS7924_MODECNTRL_AUTO_SINGLE_SLEEP 0x39 +#define ADS7924_MODECNTRL_AUTO_SCAN_SLEEP 0x3B +#define ADS7924_MODECNTRL_AUTO_BURST_SLEEP 0x3F + +#define ADS7924_ACQTIME_MASK GENMASK(4, 0) + +#define ADS7924_PWRUPTIME_MASK GENMASK(4, 0) + +/* + * The power-up time is allowed to elapse whenever the device has been shutdown + * in idle mode. Power-up time can allow external circuits, such as an + * operational amplifier, between the MUXOUT and ADCIN pins to turn on. + * The nominal time programmed by the PUTIME[4:0] register bits is given by: + * t PU = PWRUPTIME[4:0] × 2 μs + * If a power-up time is not required, set the bits to '0' to effectively bypass. + */ +#define ADS7924_PWRUPTIME_US 0 /* Bypass (0us). */ + +/* + * Acquisition Time according to ACQTIME[4:0] register bits. + * The Acquisition Time is given by: + * t ACQ = (ACQTIME[4:0] × 2 μs) + 6 μs + * Using default value of 0 for ACQTIME[4:0] results in a minimum acquisition + * time of 6us. + */ +#define ADS7924_ACQTIME_US 6 + +/* The conversion time is always 4μs and cannot be programmed by the user. */ +#define ADS7924_CONVTIME_US 4 + +#define ADS7924_TOTAL_CONVTIME_US (ADS7924_PWRUPTIME_US + ADS7924_ACQTIME_US + \ + ADS7924_CONVTIME_US) + +#define ADS7924_V_CHAN(_chan, _addr) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = _chan, \ + .address = _addr, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .datasheet_name = "AIN"#_chan, \ +} + +struct ads7924_data { + struct device *dev; + struct regmap *regmap; + struct regulator *vref_reg; + + /* GPIO descriptor for device hard-reset pin. */ + struct gpio_desc *reset_gpio; + + /* + * Protects ADC ops, e.g: concurrent sysfs/buffered + * data reads, configuration updates + */ + struct mutex lock; + + /* + * Set to true when the ADC is switched to the continuous-conversion + * mode and exits from a power-down state. This flag is used to avoid + * getting the stale result from the conversion register. + */ + bool conv_invalid; +}; + +static bool ads7924_is_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ADS7924_MODECNTRL_REG: + case ADS7924_INTCNTRL_REG: + case ADS7924_ULR0_REG: + case ADS7924_LLR0_REG: + case ADS7924_ULR1_REG: + case ADS7924_LLR1_REG: + case ADS7924_ULR2_REG: + case ADS7924_LLR2_REG: + case ADS7924_ULR3_REG: + case ADS7924_LLR3_REG: + case ADS7924_INTCONFIG_REG: + case ADS7924_SLPCONFIG_REG: + case ADS7924_ACQCONFIG_REG: + case ADS7924_PWRCONFIG_REG: + case ADS7924_RESET_REG: + return true; + default: + return false; + } +} + +static const struct regmap_config ads7924_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = ADS7924_RESET_REG, + .writeable_reg = ads7924_is_writeable_reg, +}; + +static const struct iio_chan_spec ads7924_channels[] = { + ADS7924_V_CHAN(0, ADS7924_DATA0_U_REG), + ADS7924_V_CHAN(1, ADS7924_DATA1_U_REG), + ADS7924_V_CHAN(2, ADS7924_DATA2_U_REG), + ADS7924_V_CHAN(3, ADS7924_DATA3_U_REG), +}; + +static int ads7924_get_adc_result(struct ads7924_data *data, + struct iio_chan_spec const *chan, int *val) +{ + int ret; + __be16 be_val; + + if (chan->channel < 0 || chan->channel >= ADS7924_CHANNELS) + return -EINVAL; + + if (data->conv_invalid) { + int conv_time; + + conv_time = ADS7924_TOTAL_CONVTIME_US; + /* Allow 10% for internal clock inaccuracy. */ + conv_time += conv_time / 10; + usleep_range(conv_time, conv_time + 1); + data->conv_invalid = false; + } + + ret = regmap_raw_read(data->regmap, ADS7924_AUTO_INCREMENT_BIT | + chan->address, &be_val, sizeof(be_val)); + if (ret) + return ret; + + *val = be16_to_cpu(be_val) >> ADS7924_DATA_SHIFT; + + return 0; +} + +static int ads7924_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + int ret, vref_uv; + struct ads7924_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + mutex_lock(&data->lock); + ret = ads7924_get_adc_result(data, chan, val); + mutex_unlock(&data->lock); + if (ret < 0) + return ret; + + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + vref_uv = regulator_get_voltage(data->vref_reg); + if (vref_uv < 0) + return vref_uv; + + *val = vref_uv / 1000; /* Convert reg voltage to mV */ + *val2 = ADS7924_BITS; + return IIO_VAL_FRACTIONAL_LOG2; + default: + return -EINVAL; + } +} + +static const struct iio_info ads7924_info = { + .read_raw = ads7924_read_raw, +}; + +static int ads7924_get_channels_config(struct i2c_client *client, + struct iio_dev *indio_dev) +{ + struct ads7924_data *priv = iio_priv(indio_dev); + struct device *dev = priv->dev; + struct fwnode_handle *node; + int num_channels = 0; + + device_for_each_child_node(dev, node) { + u32 pval; + unsigned int channel; + + if (fwnode_property_read_u32(node, "reg", &pval)) { + dev_err(dev, "invalid reg on %pfw\n", node); + continue; + } + + channel = pval; + if (channel >= ADS7924_CHANNELS) { + dev_err(dev, "invalid channel index %d on %pfw\n", + channel, node); + continue; + } + + num_channels++; + } + + if (!num_channels) + return -EINVAL; + + return 0; +} + +static int ads7924_set_conv_mode(struct ads7924_data *data, int mode) +{ + int ret; + unsigned int mode_field; + struct device *dev = data->dev; + + /* + * When switching between modes, be sure to first select the Awake mode + * and then switch to the desired mode. This procedure ensures the + * internal control logic is properly synchronized. + */ + if (mode != ADS7924_MODECNTRL_IDLE) { + mode_field = FIELD_PREP(ADS7924_MODECNTRL_MODE_MASK, + ADS7924_MODECNTRL_AWAKE); + + ret = regmap_update_bits(data->regmap, ADS7924_MODECNTRL_REG, + ADS7924_MODECNTRL_MODE_MASK, + mode_field); + if (ret) { + dev_err(dev, "failed to set awake mode (%pe)\n", + ERR_PTR(ret)); + return ret; + } + } + + mode_field = FIELD_PREP(ADS7924_MODECNTRL_MODE_MASK, mode); + + ret = regmap_update_bits(data->regmap, ADS7924_MODECNTRL_REG, + ADS7924_MODECNTRL_MODE_MASK, mode_field); + if (ret) + dev_err(dev, "failed to set mode %d (%pe)\n", mode, + ERR_PTR(ret)); + + return ret; +} + +static int ads7924_reset(struct iio_dev *indio_dev) +{ + struct ads7924_data *data = iio_priv(indio_dev); + + if (data->reset_gpio) { + gpiod_set_value(data->reset_gpio, 1); /* Assert. */ + /* Educated guess: assert time not specified in datasheet... */ + mdelay(100); + gpiod_set_value(data->reset_gpio, 0); /* Deassert. */ + return 0; + } + + /* + * A write of 10101010 to this register will generate a + * software reset of the ADS7924. + */ + return regmap_write(data->regmap, ADS7924_RESET_REG, 0b10101010); +}; + +static void ads7924_reg_disable(void *data) +{ + regulator_disable(data); +} + +static void ads7924_set_idle_mode(void *data) +{ + ads7924_set_conv_mode(data, ADS7924_MODECNTRL_IDLE); +} + +static int ads7924_probe(struct i2c_client *client) +{ + struct iio_dev *indio_dev; + struct ads7924_data *data; + struct device *dev = &client->dev; + int ret; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) + return dev_err_probe(dev, -ENOMEM, + "failed to allocate iio device\n"); + + data = iio_priv(indio_dev); + + data->dev = dev; + + /* Initialize the reset GPIO as output with an initial value of 0. */ + data->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(data->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(data->reset_gpio), + "failed to get request reset GPIO\n"); + + mutex_init(&data->lock); + + indio_dev->name = "ads7924"; + indio_dev->modes = INDIO_DIRECT_MODE; + + indio_dev->channels = ads7924_channels; + indio_dev->num_channels = ARRAY_SIZE(ads7924_channels); + indio_dev->info = &ads7924_info; + + ret = ads7924_get_channels_config(client, indio_dev); + if (ret < 0) + return dev_err_probe(dev, ret, + "failed to get channels configuration\n"); + + data->regmap = devm_regmap_init_i2c(client, &ads7924_regmap_config); + if (IS_ERR(data->regmap)) + return dev_err_probe(dev, PTR_ERR(data->regmap), + "failed to init regmap\n"); + + data->vref_reg = devm_regulator_get(dev, "vref"); + if (IS_ERR(data->vref_reg)) + return dev_err_probe(dev, PTR_ERR(data->vref_reg), + "failed to get vref regulator\n"); + + ret = regulator_enable(data->vref_reg); + if (ret) + return dev_err_probe(dev, ret, + "failed to enable regulator\n"); + + ret = devm_add_action_or_reset(dev, ads7924_reg_disable, data->vref_reg); + if (ret) + return dev_err_probe(dev, ret, + "failed to add regulator disable action\n"); + + ret = ads7924_reset(indio_dev); + if (ret < 0) + return dev_err_probe(dev, ret, + "failed to reset device\n"); + + ret = ads7924_set_conv_mode(data, ADS7924_MODECNTRL_AUTO_SCAN); + if (ret) + return dev_err_probe(dev, ret, + "failed to set conversion mode\n"); + + ret = devm_add_action_or_reset(dev, ads7924_set_idle_mode, data); + if (ret) + return dev_err_probe(dev, ret, + "failed to add idle mode action\n"); + + /* Use minimum signal acquire time. */ + ret = regmap_update_bits(data->regmap, ADS7924_ACQCONFIG_REG, + ADS7924_ACQTIME_MASK, + FIELD_PREP(ADS7924_ACQTIME_MASK, 0)); + if (ret < 0) + return dev_err_probe(dev, ret, + "failed to configure signal acquire time\n"); + + /* Disable power-up time. */ + ret = regmap_update_bits(data->regmap, ADS7924_PWRCONFIG_REG, + ADS7924_PWRUPTIME_MASK, + FIELD_PREP(ADS7924_PWRUPTIME_MASK, 0)); + if (ret < 0) + return dev_err_probe(dev, ret, + "failed to configure power-up time\n"); + + data->conv_invalid = true; + + ret = devm_iio_device_register(dev, indio_dev); + if (ret < 0) + return dev_err_probe(dev, ret, + "failed to register IIO device\n"); + + return 0; +} + +static const struct i2c_device_id ads7924_id[] = { + { "ads7924", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, ads7924_id); + +static const struct of_device_id ads7924_of_match[] = { + { .compatible = "ti,ads7924", }, + {} +}; +MODULE_DEVICE_TABLE(of, ads7924_of_match); + +static struct i2c_driver ads7924_driver = { + .driver = { + .name = "ads7924", + .of_match_table = ads7924_of_match, + }, + .probe_new = ads7924_probe, + .id_table = ads7924_id, +}; + +module_i2c_driver(ads7924_driver); + +MODULE_AUTHOR("Hugo Villeneuve <hvilleneuve@dimonoff.com>"); +MODULE_DESCRIPTION("Texas Instruments ADS7924 ADC I2C driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/adc/ti-lmp92064.c b/drivers/iio/adc/ti-lmp92064.c new file mode 100644 index 000000000000..c30ed824924f --- /dev/null +++ b/drivers/iio/adc/ti-lmp92064.c @@ -0,0 +1,332 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Texas Instruments LMP92064 SPI ADC driver + * + * Copyright (c) 2022 Leonard Göhrs <kernel@pengutronix.de>, Pengutronix + * + * Based on linux/drivers/iio/adc/ti-tsc2046.c + * Copyright (c) 2021 Oleksij Rempel <kernel@pengutronix.de>, Pengutronix + */ + +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/spi/spi.h> + +#include <linux/iio/iio.h> +#include <linux/iio/driver.h> + +#define TI_LMP92064_REG_CONFIG_A 0x0000 +#define TI_LMP92064_REG_CONFIG_B 0x0001 +#define TI_LMP92064_REG_CHIP_REV 0x0006 + +#define TI_LMP92064_REG_MFR_ID1 0x000C +#define TI_LMP92064_REG_MFR_ID2 0x000D + +#define TI_LMP92064_REG_REG_UPDATE 0x000F +#define TI_LMP92064_REG_CONFIG_REG 0x0100 +#define TI_LMP92064_REG_STATUS 0x0103 + +#define TI_LMP92064_REG_DATA_VOUT_LSB 0x0200 +#define TI_LMP92064_REG_DATA_VOUT_MSB 0x0201 +#define TI_LMP92064_REG_DATA_COUT_LSB 0x0202 +#define TI_LMP92064_REG_DATA_COUT_MSB 0x0203 + +#define TI_LMP92064_VAL_CONFIG_A 0x99 +#define TI_LMP92064_VAL_CONFIG_B 0x00 +#define TI_LMP92064_VAL_STATUS_OK 0x01 + +/* + * Channel number definitions for the two channels of the device + * - IN Current (INC) + * - IN Voltage (INV) + */ +#define TI_LMP92064_CHAN_INC 0 +#define TI_LMP92064_CHAN_INV 1 + +static const struct regmap_range lmp92064_readable_reg_ranges[] = { + regmap_reg_range(TI_LMP92064_REG_CONFIG_A, TI_LMP92064_REG_CHIP_REV), + regmap_reg_range(TI_LMP92064_REG_MFR_ID1, TI_LMP92064_REG_MFR_ID2), + regmap_reg_range(TI_LMP92064_REG_REG_UPDATE, TI_LMP92064_REG_REG_UPDATE), + regmap_reg_range(TI_LMP92064_REG_CONFIG_REG, TI_LMP92064_REG_CONFIG_REG), + regmap_reg_range(TI_LMP92064_REG_STATUS, TI_LMP92064_REG_STATUS), + regmap_reg_range(TI_LMP92064_REG_DATA_VOUT_LSB, TI_LMP92064_REG_DATA_COUT_MSB), +}; + +static const struct regmap_access_table lmp92064_readable_regs = { + .yes_ranges = lmp92064_readable_reg_ranges, + .n_yes_ranges = ARRAY_SIZE(lmp92064_readable_reg_ranges), +}; + +static const struct regmap_range lmp92064_writable_reg_ranges[] = { + regmap_reg_range(TI_LMP92064_REG_CONFIG_A, TI_LMP92064_REG_CONFIG_B), + regmap_reg_range(TI_LMP92064_REG_REG_UPDATE, TI_LMP92064_REG_REG_UPDATE), + regmap_reg_range(TI_LMP92064_REG_CONFIG_REG, TI_LMP92064_REG_CONFIG_REG), +}; + +static const struct regmap_access_table lmp92064_writable_regs = { + .yes_ranges = lmp92064_writable_reg_ranges, + .n_yes_ranges = ARRAY_SIZE(lmp92064_writable_reg_ranges), +}; + +static const struct regmap_config lmp92064_spi_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .max_register = TI_LMP92064_REG_DATA_COUT_MSB, + .rd_table = &lmp92064_readable_regs, + .wr_table = &lmp92064_writable_regs, +}; + +struct lmp92064_adc_priv { + int shunt_resistor_uohm; + struct spi_device *spi; + struct regmap *regmap; +}; + +static const struct iio_chan_spec lmp92064_adc_channels[] = { + { + .type = IIO_CURRENT, + .address = TI_LMP92064_CHAN_INC, + .info_mask_separate = + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + .datasheet_name = "INC", + }, + { + .type = IIO_VOLTAGE, + .address = TI_LMP92064_CHAN_INV, + .info_mask_separate = + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + .datasheet_name = "INV", + }, +}; + +static int lmp92064_read_meas(struct lmp92064_adc_priv *priv, u16 *res) +{ + __be16 raw[2]; + int ret; + + /* + * The ADC only latches in new samples if all DATA registers are read + * in descending sequential order. + * The ADC auto-decrements the register index with each clocked byte. + * Read both channels in single SPI transfer by selecting the highest + * register using the command below and clocking out all four data + * bytes. + */ + + ret = regmap_bulk_read(priv->regmap, TI_LMP92064_REG_DATA_COUT_MSB, + &raw, sizeof(raw)); + + if (ret) { + dev_err(&priv->spi->dev, "regmap_bulk_read failed: %pe\n", + ERR_PTR(ret)); + return ret; + } + + res[0] = be16_to_cpu(raw[0]); + res[1] = be16_to_cpu(raw[1]); + + return 0; +} + +static int lmp92064_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + struct lmp92064_adc_priv *priv = iio_priv(indio_dev); + u16 raw[2]; + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = lmp92064_read_meas(priv, raw); + if (ret < 0) + return ret; + + *val = (chan->address == TI_LMP92064_CHAN_INC) ? raw[0] : raw[1]; + + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + if (chan->address == TI_LMP92064_CHAN_INC) { + /* + * processed (mA) = raw * current_lsb (mA) + * current_lsb (mA) = shunt_voltage_lsb (nV) / shunt_resistor (uOhm) + * shunt_voltage_lsb (nV) = 81920000 / 4096 = 20000 + */ + *val = 20000; + *val2 = priv->shunt_resistor_uohm; + } else { + /* + * processed (mV) = raw * voltage_lsb (mV) + * voltage_lsb (mV) = 2048 / 4096 + */ + *val = 2048; + *val2 = 4096; + } + return IIO_VAL_FRACTIONAL; + default: + return -EINVAL; + } +} + +static int lmp92064_reset(struct lmp92064_adc_priv *priv, + struct gpio_desc *gpio_reset) +{ + unsigned int status; + int ret, i; + + if (gpio_reset) { + /* + * Perform a hard reset if gpio_reset is available. + * The datasheet specifies a very low 3.5ns reset pulse duration and does not + * specify how long to wait after a reset to access the device. + * Use more conservative pulse lengths to allow analog RC filtering of the + * reset line at the board level (as recommended in the datasheet). + */ + gpiod_set_value_cansleep(gpio_reset, 1); + usleep_range(1, 10); + gpiod_set_value_cansleep(gpio_reset, 0); + usleep_range(500, 750); + } else { + /* + * Perform a soft-reset if not. + * Also write default values to the config registers that are not + * affected by soft reset. + */ + ret = regmap_write(priv->regmap, TI_LMP92064_REG_CONFIG_A, + TI_LMP92064_VAL_CONFIG_A); + if (ret < 0) + return ret; + + ret = regmap_write(priv->regmap, TI_LMP92064_REG_CONFIG_B, + TI_LMP92064_VAL_CONFIG_B); + if (ret < 0) + return ret; + } + + /* + * Wait for the device to signal readiness to prevent reading bogus data + * and make sure device is actually connected. + * The datasheet does not specify how long this takes but usually it is + * not more than 3-4 iterations of this loop. + */ + for (i = 0; i < 10; i++) { + ret = regmap_read(priv->regmap, TI_LMP92064_REG_STATUS, &status); + if (ret < 0) + return ret; + + if (status == TI_LMP92064_VAL_STATUS_OK) + return 0; + + usleep_range(1000, 2000); + } + + /* + * No (correct) response received. + * Device is mostly likely not connected to the bus. + */ + return -ENXIO; +} + +static const struct iio_info lmp92064_adc_info = { + .read_raw = lmp92064_read_raw, +}; + +static int lmp92064_adc_probe(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + struct lmp92064_adc_priv *priv; + struct gpio_desc *gpio_reset; + struct iio_dev *indio_dev; + u32 shunt_resistor_uohm; + struct regmap *regmap; + int ret; + + ret = spi_setup(spi); + if (ret < 0) + return dev_err_probe(dev, ret, "Error in SPI setup\n"); + + regmap = devm_regmap_init_spi(spi, &lmp92064_spi_regmap_config); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), + "Failed to set up SPI regmap\n"); + + indio_dev = devm_iio_device_alloc(dev, sizeof(*priv)); + if (!indio_dev) + return -ENOMEM; + + priv = iio_priv(indio_dev); + + priv->spi = spi; + priv->regmap = regmap; + + ret = device_property_read_u32(dev, "shunt-resistor-micro-ohms", + &shunt_resistor_uohm); + if (ret < 0) + return dev_err_probe(dev, ret, + "Failed to get shunt-resistor value\n"); + + /* + * The shunt resistance is passed to userspace as the denominator of an iio + * fraction. Make sure it is in range for that. + */ + if (shunt_resistor_uohm == 0 || shunt_resistor_uohm > INT_MAX) { + dev_err(dev, "Shunt resistance is out of range\n"); + return -EINVAL; + } + + priv->shunt_resistor_uohm = shunt_resistor_uohm; + + ret = devm_regulator_get_enable(dev, "vdd"); + if (ret) + return ret; + + ret = devm_regulator_get_enable(dev, "vdig"); + if (ret) + return ret; + + gpio_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(gpio_reset)) + return dev_err_probe(dev, PTR_ERR(gpio_reset), + "Failed to get GPIO reset pin\n"); + + ret = lmp92064_reset(priv, gpio_reset); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to reset device\n"); + + indio_dev->name = "lmp92064"; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = lmp92064_adc_channels; + indio_dev->num_channels = ARRAY_SIZE(lmp92064_adc_channels); + indio_dev->info = &lmp92064_adc_info; + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct spi_device_id lmp92064_id_table[] = { + { "lmp92064" }, + {} +}; +MODULE_DEVICE_TABLE(spi, lmp92064_id_table); + +static const struct of_device_id lmp92064_of_table[] = { + { .compatible = "ti,lmp92064" }, + {} +}; +MODULE_DEVICE_TABLE(of, lmp92064_of_table); + +static struct spi_driver lmp92064_adc_driver = { + .driver = { + .name = "lmp92064", + .of_match_table = lmp92064_of_table, + }, + .probe = lmp92064_adc_probe, + .id_table = lmp92064_id_table, +}; +module_spi_driver(lmp92064_adc_driver); + +MODULE_AUTHOR("Leonard Göhrs <kernel@pengutronix.de>"); +MODULE_DESCRIPTION("TI LMP92064 ADC"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/adc/xilinx-ams.c b/drivers/iio/adc/xilinx-ams.c index 5b4bdf3a26bb..fde358d388ab 100644 --- a/drivers/iio/adc/xilinx-ams.c +++ b/drivers/iio/adc/xilinx-ams.c @@ -1220,8 +1220,7 @@ static int ams_init_module(struct iio_dev *indio_dev, int num_channels = 0; int ret; - if (fwnode_property_match_string(fwnode, "compatible", - "xlnx,zynqmp-ams-ps") == 0) { + if (fwnode_device_is_compatible(fwnode, "xlnx,zynqmp-ams-ps")) { ams->ps_base = fwnode_iomap(fwnode, 0); if (!ams->ps_base) return -ENXIO; @@ -1232,8 +1231,7 @@ static int ams_init_module(struct iio_dev *indio_dev, /* add PS channels to iio device channels */ memcpy(channels, ams_ps_channels, sizeof(ams_ps_channels)); num_channels = ARRAY_SIZE(ams_ps_channels); - } else if (fwnode_property_match_string(fwnode, "compatible", - "xlnx,zynqmp-ams-pl") == 0) { + } else if (fwnode_device_is_compatible(fwnode, "xlnx,zynqmp-ams-pl")) { ams->pl_base = fwnode_iomap(fwnode, 0); if (!ams->pl_base) return -ENXIO; @@ -1247,8 +1245,7 @@ static int ams_init_module(struct iio_dev *indio_dev, num_channels += AMS_PL_MAX_FIXED_CHANNEL; num_channels = ams_get_ext_chan(fwnode, channels, num_channels); - } else if (fwnode_property_match_string(fwnode, "compatible", - "xlnx,zynqmp-ams") == 0) { + } else if (fwnode_device_is_compatible(fwnode, "xlnx,zynqmp-ams")) { /* add AMS channels to iio device channels */ memcpy(channels, ams_ctrl_channels, sizeof(ams_ctrl_channels)); num_channels += ARRAY_SIZE(ams_ctrl_channels); diff --git a/drivers/iio/cdc/ad7746.c b/drivers/iio/cdc/ad7746.c index 6f68651ce1d5..a1db5469f2d1 100644 --- a/drivers/iio/cdc/ad7746.c +++ b/drivers/iio/cdc/ad7746.c @@ -285,8 +285,7 @@ static int ad7746_select_channel(struct iio_dev *indio_dev, if (ret < 0) return ret; - if (chip->capdac_set != chan->channel) - chip->capdac_set = chan->channel; + chip->capdac_set = chan->channel; break; case IIO_VOLTAGE: case IIO_TEMP: diff --git a/drivers/iio/chemical/scd30_core.c b/drivers/iio/chemical/scd30_core.c index 682fca39d14d..7be5a45cf71a 100644 --- a/drivers/iio/chemical/scd30_core.c +++ b/drivers/iio/chemical/scd30_core.c @@ -354,7 +354,7 @@ static ssize_t sampling_frequency_available_show(struct device *dev, struct devi ssize_t len = 0; do { - len += scnprintf(buf + len, PAGE_SIZE - len, "0.%09u ", 1000000000 / i); + len += sysfs_emit_at(buf, len, "0.%09u ", 1000000000 / i); /* * Not all values fit PAGE_SIZE buffer hence print every 6th * (each frequency differs by 6s in time domain from the @@ -380,7 +380,7 @@ static ssize_t calibration_auto_enable_show(struct device *dev, struct device_at ret = scd30_command_read(state, CMD_ASC, &val); mutex_unlock(&state->lock); - return ret ?: sprintf(buf, "%d\n", val); + return ret ?: sysfs_emit(buf, "%d\n", val); } static ssize_t calibration_auto_enable_store(struct device *dev, struct device_attribute *attr, @@ -414,7 +414,7 @@ static ssize_t calibration_forced_value_show(struct device *dev, struct device_a ret = scd30_command_read(state, CMD_FRC, &val); mutex_unlock(&state->lock); - return ret ?: sprintf(buf, "%d\n", val); + return ret ?: sysfs_emit(buf, "%d\n", val); } static ssize_t calibration_forced_value_store(struct device *dev, struct device_attribute *attr, @@ -642,10 +642,8 @@ static int scd30_setup_trigger(struct iio_dev *indio_dev) trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name, iio_device_id(indio_dev)); - if (!trig) { - dev_err(dev, "failed to allocate trigger\n"); - return -ENOMEM; - } + if (!trig) + return dev_err_probe(dev, -ENOMEM, "failed to allocate trigger\n"); trig->ops = &scd30_trigger_ops; iio_trigger_set_drvdata(trig, indio_dev); @@ -667,9 +665,9 @@ static int scd30_setup_trigger(struct iio_dev *indio_dev) IRQF_NO_AUTOEN, indio_dev->name, indio_dev); if (ret) - dev_err(dev, "failed to request irq\n"); + return dev_err_probe(dev, ret, "failed to request irq\n"); - return ret; + return 0; } int scd30_probe(struct device *dev, int irq, const char *name, void *priv, @@ -717,17 +715,13 @@ int scd30_probe(struct device *dev, int irq, const char *name, void *priv, return ret; ret = scd30_reset(state); - if (ret) { - dev_err(dev, "failed to reset device: %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "failed to reset device\n"); if (state->irq > 0) { ret = scd30_setup_trigger(indio_dev); - if (ret) { - dev_err(dev, "failed to setup trigger: %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "failed to setup trigger\n"); } ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, scd30_trigger_handler, NULL); @@ -735,23 +729,17 @@ int scd30_probe(struct device *dev, int irq, const char *name, void *priv, return ret; ret = scd30_command_read(state, CMD_FW_VERSION, &val); - if (ret) { - dev_err(dev, "failed to read firmware version: %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "failed to read firmware version\n"); dev_info(dev, "firmware version: %d.%d\n", val >> 8, (char)val); ret = scd30_command_write(state, CMD_MEAS_INTERVAL, state->meas_interval); - if (ret) { - dev_err(dev, "failed to set measurement interval: %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "failed to set measurement interval\n"); ret = scd30_command_write(state, CMD_START_MEAS, state->pressure_comp); - if (ret) { - dev_err(dev, "failed to start measurement: %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "failed to start measurement\n"); ret = devm_add_action_or_reset(dev, scd30_stop_meas, state); if (ret) diff --git a/drivers/iio/common/scmi_sensors/scmi_iio.c b/drivers/iio/common/scmi_sensors/scmi_iio.c index d92f7f651f7b..0c2caf3570db 100644 --- a/drivers/iio/common/scmi_sensors/scmi_iio.c +++ b/drivers/iio/common/scmi_sensors/scmi_iio.c @@ -400,12 +400,12 @@ static ssize_t scmi_iio_get_raw_available(struct iio_dev *iio_dev, rem = do_div(resolution, int_pow(10, abs(exponent)) ); - len = scnprintf(buf, PAGE_SIZE, + len = sysfs_emit(buf, "[%lld %llu.%llu %lld]\n", min_range, resolution, rem, max_range); } else { resolution = resolution * int_pow(10, exponent); - len = scnprintf(buf, PAGE_SIZE, "[%lld %llu %lld]\n", + len = sysfs_emit(buf, "[%lld %llu %lld]\n", min_range, resolution, max_range); } } diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index 80521bd28d0f..d3f90cf86143 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -162,10 +162,10 @@ config AD5696_I2C depends on I2C select AD5686 help - Say yes here to build support for Analog Devices AD5311R, AD5338R, - AD5671R, AD5673R, AD5675R, AD5677R, AD5691R, AD5692R, AD5693, AD5693R, - AD5694, AD5694R, AD5695R, AD5696, and AD5696R Digital to Analog - converters. + Say yes here to build support for Analog Devices AD5311R, AD5337, + AD5338R, AD5671R, AD5673R, AD5675R, AD5677R, AD5691R, AD5692R, AD5693, + AD5693R, AD5694, AD5694R, AD5695R, AD5696, and AD5696R Digital to + Analog converters. To compile this driver as a module, choose M here: the module will be called ad5696. @@ -357,6 +357,19 @@ config MAX517 This driver can also be built as a module. If so, the module will be called max517. +config MAX5522 + tristate "Maxim MAX5522 DAC driver" + depends on SPI_MASTER + select REGMAP_SPI + help + Say Y here if you want to build a driver for the Maxim MAX5522. + + MAX5522 is a dual, ultra-low-power, 10-Bit, voltage-output + digital to analog converter (DAC) offering rail-to-rail buffered + voltage outputs. + + If compiled as a module, it will be called max5522. + config MAX5821 tristate "Maxim MAX5821 DAC driver" depends on I2C diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile index ec3e42713f00..6c74fea21736 100644 --- a/drivers/iio/dac/Makefile +++ b/drivers/iio/dac/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_LTC2632) += ltc2632.o obj-$(CONFIG_LTC2688) += ltc2688.o obj-$(CONFIG_M62332) += m62332.o obj-$(CONFIG_MAX517) += max517.o +obj-$(CONFIG_MAX5522) += max5522.o obj-$(CONFIG_MAX5821) += max5821.o obj-$(CONFIG_MCP4725) += mcp4725.o obj-$(CONFIG_MCP4922) += mcp4922.o diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c index 15361d8bbf94..57cc0f0eedc6 100644 --- a/drivers/iio/dac/ad5686.c +++ b/drivers/iio/dac/ad5686.c @@ -258,6 +258,7 @@ static const struct iio_chan_spec name[] = { \ DECLARE_AD5693_CHANNELS(ad5310r_channels, 10, 2); DECLARE_AD5693_CHANNELS(ad5311r_channels, 10, 6); +DECLARE_AD5338_CHANNELS(ad5337r_channels, 8, 8); DECLARE_AD5338_CHANNELS(ad5338r_channels, 10, 6); DECLARE_AD5676_CHANNELS(ad5672_channels, 12, 4); DECLARE_AD5679_CHANNELS(ad5674r_channels, 12, 4); @@ -283,6 +284,12 @@ static const struct ad5686_chip_info ad5686_chip_info_tbl[] = { .num_channels = 1, .regmap_type = AD5693_REGMAP, }, + [ID_AD5337R] = { + .channels = ad5337r_channels, + .int_vref_mv = 2500, + .num_channels = 2, + .regmap_type = AD5686_REGMAP, + }, [ID_AD5338R] = { .channels = ad5338r_channels, .int_vref_mv = 2500, diff --git a/drivers/iio/dac/ad5686.h b/drivers/iio/dac/ad5686.h index b7ade3a6b9b6..760f852911df 100644 --- a/drivers/iio/dac/ad5686.h +++ b/drivers/iio/dac/ad5686.h @@ -54,6 +54,7 @@ enum ad5686_supported_device_ids { ID_AD5310R, ID_AD5311R, + ID_AD5337R, ID_AD5338R, ID_AD5671R, ID_AD5672R, diff --git a/drivers/iio/dac/ad5696-i2c.c b/drivers/iio/dac/ad5696-i2c.c index 160e80cf9135..8a95f0278018 100644 --- a/drivers/iio/dac/ad5696-i2c.c +++ b/drivers/iio/dac/ad5696-i2c.c @@ -72,6 +72,7 @@ static void ad5686_i2c_remove(struct i2c_client *i2c) static const struct i2c_device_id ad5686_i2c_id[] = { {"ad5311r", ID_AD5311R}, + {"ad5337r", ID_AD5337R}, {"ad5338r", ID_AD5338R}, {"ad5671r", ID_AD5671R}, {"ad5673r", ID_AD5673R}, @@ -92,6 +93,7 @@ MODULE_DEVICE_TABLE(i2c, ad5686_i2c_id); static const struct of_device_id ad5686_of_match[] = { { .compatible = "adi,ad5311r" }, + { .compatible = "adi,ad5337r" }, { .compatible = "adi,ad5338r" }, { .compatible = "adi,ad5671r" }, { .compatible = "adi,ad5675r" }, diff --git a/drivers/iio/dac/max5522.c b/drivers/iio/dac/max5522.c new file mode 100644 index 000000000000..00ba4e98fb9c --- /dev/null +++ b/drivers/iio/dac/max5522.c @@ -0,0 +1,207 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Maxim MAX5522 + * Dual, Ultra-Low-Power 10-Bit, Voltage-Output DACs + * + * Copyright 2022 Timesys Corp. + */ + +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> +#include <linux/spi/spi.h> + +#include <linux/iio/iio.h> + +#define MAX5522_MAX_ADDR 15 +#define MAX5522_CTRL_NONE 0 +#define MAX5522_CTRL_LOAD_IN_A 9 +#define MAX5522_CTRL_LOAD_IN_B 10 + +#define MAX5522_REG_DATA(x) ((x) + MAX5522_CTRL_LOAD_IN_A) + +struct max5522_chip_info { + const char *name; + const struct iio_chan_spec *channels; + unsigned int num_channels; +}; + +struct max5522_state { + struct regmap *regmap; + const struct max5522_chip_info *chip_info; + unsigned short dac_cache[2]; + struct regulator *vrefin_reg; +}; + +#define MAX5522_CHANNEL(chan) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .output = 1, \ + .channel = chan, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE), \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 10, \ + .storagebits = 16, \ + .shift = 2, \ + } \ +} + +const struct iio_chan_spec max5522_channels[] = { + MAX5522_CHANNEL(0), + MAX5522_CHANNEL(1), +}; + +enum max5522_type { + ID_MAX5522, +}; + +static const struct max5522_chip_info max5522_chip_info_tbl[] = { + [ID_MAX5522] = { + .name = "max5522", + .channels = max5522_channels, + .num_channels = 2, + }, +}; + +static inline int max5522_info_to_reg(struct iio_chan_spec const *chan) +{ + return MAX5522_REG_DATA(chan->channel); +} + +static int max5522_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long info) +{ + struct max5522_state *state = iio_priv(indio_dev); + int ret; + + switch (info) { + case IIO_CHAN_INFO_RAW: + *val = state->dac_cache[chan->channel]; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + ret = regulator_get_voltage(state->vrefin_reg); + if (ret < 0) + return -EINVAL; + *val = ret / 1000; + *val2 = 10; + return IIO_VAL_FRACTIONAL_LOG2; + default: + return -EINVAL; + } + + return -EINVAL; +} + +static int max5522_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long info) +{ + struct max5522_state *state = iio_priv(indio_dev); + int rval; + + if (val > 1023 || val < 0) + return -EINVAL; + + rval = regmap_write(state->regmap, max5522_info_to_reg(chan), + val << chan->scan_type.shift); + if (rval < 0) + return rval; + + state->dac_cache[chan->channel] = val; + + return 0; +} + +static const struct iio_info max5522_info = { + .read_raw = max5522_read_raw, + .write_raw = max5522_write_raw, +}; + +static const struct regmap_config max5522_regmap_config = { + .reg_bits = 4, + .val_bits = 12, + .max_register = MAX5522_MAX_ADDR, +}; + +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; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*state)); + if (indio_dev == NULL) { + dev_err(&spi->dev, "failed to allocate iio device\n"); + return -ENOMEM; + } + + 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->vrefin_reg = devm_regulator_get(&spi->dev, "vrefin"); + if (IS_ERR(state->vrefin_reg)) + return dev_err_probe(&spi->dev, PTR_ERR(state->vrefin_reg), + "Vrefin regulator not specified\n"); + + ret = regulator_enable(state->vrefin_reg); + if (ret) { + return dev_err_probe(&spi->dev, ret, + "Failed to enable vref regulators\n"); + } + + state->regmap = devm_regmap_init_spi(spi, &max5522_regmap_config); + + if (IS_ERR(state->regmap)) + return PTR_ERR(state->regmap); + + indio_dev->info = &max5522_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = max5522_channels; + indio_dev->num_channels = ARRAY_SIZE(max5522_channels); + indio_dev->name = max5522_chip_info_tbl[ID_MAX5522].name; + + return devm_iio_device_register(&spi->dev, indio_dev); +} + +static const struct spi_device_id max5522_ids[] = { + { "max5522", (kernel_ulong_t)&max5522_chip_info_tbl[ID_MAX5522] }, + {} +}; +MODULE_DEVICE_TABLE(spi, max5522_ids); + +static const struct of_device_id max5522_of_match[] = { + { + .compatible = "maxim,max5522", + .data = &max5522_chip_info_tbl[ID_MAX5522], + }, + {} +}; +MODULE_DEVICE_TABLE(of, max5522_of_match); + +static struct spi_driver max5522_spi_driver = { + .driver = { + .name = "max5522", + .of_match_table = max5522_of_match, + }, + .probe = max5522_spi_probe, + .id_table = max5522_ids, +}; +module_spi_driver(max5522_spi_driver); + +MODULE_AUTHOR("Angelo Dureghello <angelo.dureghello@timesys.com"); +MODULE_DESCRIPTION("MAX5522 DAC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/imu/bno055/bno055_ser_trace.c b/drivers/iio/imu/bno055/bno055_ser_trace.c index 48397b66daef..ab564186d19c 100644 --- a/drivers/iio/imu/bno055/bno055_ser_trace.c +++ b/drivers/iio/imu/bno055/bno055_ser_trace.c @@ -1,4 +1,4 @@ -//SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0 /* * bno055_ser Trace Support diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c index e692dfeeda44..53ba020fa5d0 100644 --- a/drivers/iio/imu/kmx61.c +++ b/drivers/iio/imu/kmx61.c @@ -649,7 +649,7 @@ static int kmx61_chip_update_thresholds(struct kmx61_data *data) KMX61_REG_WUF_TIMER, data->wake_duration); if (ret < 0) { - dev_err(&data->client->dev, "Errow writing reg_wuf_timer\n"); + dev_err(&data->client->dev, "Error writing reg_wuf_timer\n"); return ret; } diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index 5b6f195748fc..499fcf8875b4 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -93,7 +93,7 @@ enum st_lsm6dsx_hw_id { .endianness = IIO_LE, \ }, \ .event_spec = &st_lsm6dsx_event, \ - .ext_info = st_lsm6dsx_accel_ext_info, \ + .ext_info = st_lsm6dsx_ext_info, \ .num_event_specs = 1, \ } @@ -113,6 +113,7 @@ enum st_lsm6dsx_hw_id { .storagebits = 16, \ .endianness = IIO_LE, \ }, \ + .ext_info = st_lsm6dsx_ext_info, \ } struct st_lsm6dsx_reg { @@ -528,7 +529,7 @@ st_lsm6dsx_device_set_enable(struct st_lsm6dsx_sensor *sensor, bool enable) } static const -struct iio_chan_spec_ext_info __maybe_unused st_lsm6dsx_accel_ext_info[] = { +struct iio_chan_spec_ext_info __maybe_unused st_lsm6dsx_ext_info[] = { IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, st_lsm6dsx_get_mount_matrix), { } }; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c index f2b64b4956a3..c1b444520d2a 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c @@ -704,18 +704,18 @@ static ssize_t st_lsm6dsx_shub_scale_avail(struct device *dev, static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(st_lsm6dsx_shub_sampling_freq_avail); static IIO_DEVICE_ATTR(in_scale_available, 0444, st_lsm6dsx_shub_scale_avail, NULL, 0); -static struct attribute *st_lsm6dsx_ext_attributes[] = { +static struct attribute *st_lsm6dsx_shub_attributes[] = { &iio_dev_attr_sampling_frequency_available.dev_attr.attr, &iio_dev_attr_in_scale_available.dev_attr.attr, NULL, }; -static const struct attribute_group st_lsm6dsx_ext_attribute_group = { - .attrs = st_lsm6dsx_ext_attributes, +static const struct attribute_group st_lsm6dsx_shub_attribute_group = { + .attrs = st_lsm6dsx_shub_attributes, }; -static const struct iio_info st_lsm6dsx_ext_info = { - .attrs = &st_lsm6dsx_ext_attribute_group, +static const struct iio_info st_lsm6dsx_shub_info = { + .attrs = &st_lsm6dsx_shub_attribute_group, .read_raw = st_lsm6dsx_shub_read_raw, .write_raw = st_lsm6dsx_shub_write_raw, .hwfifo_set_watermark = st_lsm6dsx_set_watermark, @@ -737,7 +737,7 @@ st_lsm6dsx_shub_alloc_iiodev(struct st_lsm6dsx_hw *hw, return NULL; iio_dev->modes = INDIO_DIRECT_MODE; - iio_dev->info = &st_lsm6dsx_ext_info; + iio_dev->info = &st_lsm6dsx_shub_info; sensor = iio_priv(iio_dev); sensor->id = id; diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 52e690f031cb..c117f50d0cf3 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -8,30 +8,32 @@ #define pr_fmt(fmt) "iio-core: " fmt -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/idr.h> -#include <linux/kdev_t.h> -#include <linux/err.h> +#include <linux/anon_inodes.h> +#include <linux/cdev.h> +#include <linux/debugfs.h> #include <linux/device.h> +#include <linux/err.h> #include <linux/fs.h> +#include <linux/idr.h> +#include <linux/kdev_t.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mutex.h> #include <linux/poll.h> #include <linux/property.h> #include <linux/sched.h> -#include <linux/wait.h> -#include <linux/cdev.h> #include <linux/slab.h> -#include <linux/anon_inodes.h> -#include <linux/debugfs.h> -#include <linux/mutex.h> -#include <linux/iio/iio.h> +#include <linux/wait.h> + +#include <linux/iio/buffer.h> +#include <linux/iio/buffer_impl.h> +#include <linux/iio/events.h> #include <linux/iio/iio-opaque.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> + #include "iio_core.h" #include "iio_core_trigger.h" -#include <linux/iio/sysfs.h> -#include <linux/iio/events.h> -#include <linux/iio/buffer.h> -#include <linux/iio/buffer_impl.h> /* IDA to assign each registered device a unique id */ static DEFINE_IDA(iio_ida); @@ -205,36 +207,6 @@ bool iio_buffer_enabled(struct iio_dev *indio_dev) } EXPORT_SYMBOL_GPL(iio_buffer_enabled); -/** - * iio_sysfs_match_string_with_gaps - matches given string in an array with gaps - * @array: array of strings - * @n: number of strings in the array - * @str: string to match with - * - * Returns index of @str in the @array or -EINVAL, similar to match_string(). - * Uses sysfs_streq instead of strcmp for matching. - * - * This routine will look for a string in an array of strings. - * The search will continue until the element is found or the n-th element - * is reached, regardless of any NULL elements in the array. - */ -static int iio_sysfs_match_string_with_gaps(const char * const *array, size_t n, - const char *str) -{ - const char *item; - int index; - - for (index = 0; index < n; index++) { - item = array[index]; - if (!item) - continue; - if (sysfs_streq(item, str)) - return index; - } - - return -EINVAL; -} - #if defined(CONFIG_DEBUG_FS) /* * There's also a CONFIG_DEBUG_FS guard in include/linux/iio/iio.h for @@ -569,7 +541,7 @@ ssize_t iio_enum_write(struct iio_dev *indio_dev, if (!e->set) return -EINVAL; - ret = iio_sysfs_match_string_with_gaps(e->items, e->num_items, buf); + ret = __sysfs_match_string(e->items, e->num_items, buf); if (ret < 0) return ret; diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index 6f23817fae6f..d74d2b5ff14c 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile @@ -39,7 +39,6 @@ obj-$(CONFIG_NOA1305) += noa1305.o obj-$(CONFIG_OPT3001) += opt3001.o obj-$(CONFIG_PA12203001) += pa12203001.o obj-$(CONFIG_RPR0521) += rpr0521.o -obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o obj-$(CONFIG_SI1133) += si1133.o obj-$(CONFIG_SI1145) += si1145.o obj-$(CONFIG_STK3310) += stk3310.o @@ -48,6 +47,7 @@ obj-$(CONFIG_ST_UVIS25_I2C) += st_uvis25_i2c.o obj-$(CONFIG_ST_UVIS25_SPI) += st_uvis25_spi.o obj-$(CONFIG_TCS3414) += tcs3414.o obj-$(CONFIG_TCS3472) += tcs3472.o +obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o obj-$(CONFIG_TSL2583) += tsl2583.o obj-$(CONFIG_TSL2591) += tsl2591.o obj-$(CONFIG_TSL2772) += tsl2772.o diff --git a/drivers/iio/light/max44009.c b/drivers/iio/light/max44009.c index 801e5a0ad496..3dadace09fe2 100644 --- a/drivers/iio/light/max44009.c +++ b/drivers/iio/light/max44009.c @@ -487,8 +487,7 @@ static irqreturn_t max44009_threaded_irq_handler(int irq, void *p) return IRQ_NONE; } -static int max44009_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max44009_probe(struct i2c_client *client) { struct max44009_data *data; struct iio_dev *indio_dev; @@ -538,7 +537,7 @@ static struct i2c_driver max44009_driver = { .driver = { .name = MAX44009_DRV_NAME, }, - .probe = max44009_probe, + .probe_new = max44009_probe, .id_table = max44009_id, }; module_i2c_driver(max44009_driver); diff --git a/drivers/iio/light/tsl2563.c b/drivers/iio/light/tsl2563.c index d0e42b73203a..f2f55239a072 100644 --- a/drivers/iio/light/tsl2563.c +++ b/drivers/iio/light/tsl2563.c @@ -11,69 +11,63 @@ * Amit Kucheria <amit.kucheria@verdurent.com> */ -#include <linux/module.h> -#include <linux/mod_devicetable.h> -#include <linux/property.h> +#include <linux/bits.h> +#include <linux/delay.h> +#include <linux/err.h> #include <linux/i2c.h> #include <linux/interrupt.h> #include <linux/irq.h> -#include <linux/sched.h> +#include <linux/math.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> #include <linux/mutex.h> -#include <linux/delay.h> #include <linux/pm.h> -#include <linux/err.h> +#include <linux/property.h> +#include <linux/sched.h> #include <linux/slab.h> +#include <linux/iio/events.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> -#include <linux/iio/events.h> -#include <linux/platform_data/tsl2563.h> /* Use this many bits for fraction part. */ #define ADC_FRAC_BITS 14 /* Given number of 1/10000's in ADC_FRAC_BITS precision. */ -#define FRAC10K(f) (((f) * (1L << (ADC_FRAC_BITS))) / (10000)) +#define FRAC10K(f) (((f) * BIT(ADC_FRAC_BITS)) / (10000)) /* Bits used for fraction in calibration coefficients.*/ #define CALIB_FRAC_BITS 10 -/* 0.5 in CALIB_FRAC_BITS precision */ -#define CALIB_FRAC_HALF (1 << (CALIB_FRAC_BITS - 1)) -/* Make a fraction from a number n that was multiplied with b. */ -#define CALIB_FRAC(n, b) (((n) << CALIB_FRAC_BITS) / (b)) /* Decimal 10^(digits in sysfs presentation) */ #define CALIB_BASE_SYSFS 1000 -#define TSL2563_CMD 0x80 -#define TSL2563_CLEARINT 0x40 +#define TSL2563_CMD BIT(7) +#define TSL2563_CLEARINT BIT(6) #define TSL2563_REG_CTRL 0x00 #define TSL2563_REG_TIMING 0x01 -#define TSL2563_REG_LOWLOW 0x02 /* data0 low threshold, 2 bytes */ -#define TSL2563_REG_LOWHIGH 0x03 -#define TSL2563_REG_HIGHLOW 0x04 /* data0 high threshold, 2 bytes */ -#define TSL2563_REG_HIGHHIGH 0x05 +#define TSL2563_REG_LOW 0x02 /* data0 low threshold, 2 bytes */ +#define TSL2563_REG_HIGH 0x04 /* data0 high threshold, 2 bytes */ #define TSL2563_REG_INT 0x06 #define TSL2563_REG_ID 0x0a -#define TSL2563_REG_DATA0LOW 0x0c /* broadband sensor value, 2 bytes */ -#define TSL2563_REG_DATA0HIGH 0x0d -#define TSL2563_REG_DATA1LOW 0x0e /* infrared sensor value, 2 bytes */ -#define TSL2563_REG_DATA1HIGH 0x0f +#define TSL2563_REG_DATA0 0x0c /* broadband sensor value, 2 bytes */ +#define TSL2563_REG_DATA1 0x0e /* infrared sensor value, 2 bytes */ #define TSL2563_CMD_POWER_ON 0x03 #define TSL2563_CMD_POWER_OFF 0x00 -#define TSL2563_CTRL_POWER_MASK 0x03 +#define TSL2563_CTRL_POWER_MASK GENMASK(1, 0) #define TSL2563_TIMING_13MS 0x00 #define TSL2563_TIMING_100MS 0x01 #define TSL2563_TIMING_400MS 0x02 -#define TSL2563_TIMING_MASK 0x03 +#define TSL2563_TIMING_MASK GENMASK(1, 0) #define TSL2563_TIMING_GAIN16 0x10 #define TSL2563_TIMING_GAIN1 0x00 #define TSL2563_INT_DISABLED 0x00 #define TSL2563_INT_LEVEL 0x10 -#define TSL2563_INT_PERSIST(n) ((n) & 0x0F) +#define TSL2563_INT_MASK GENMASK(5, 4) +#define TSL2563_INT_PERSIST(n) ((n) & GENMASK(3, 0)) struct tsl2563_gainlevel_coeff { u8 gaintime; @@ -161,24 +155,16 @@ static int tsl2563_configure(struct tsl2563_chip *chip) chip->gainlevel->gaintime); if (ret) goto error_ret; - ret = i2c_smbus_write_byte_data(chip->client, - TSL2563_CMD | TSL2563_REG_HIGHLOW, - chip->high_thres & 0xFF); - if (ret) - goto error_ret; - ret = i2c_smbus_write_byte_data(chip->client, - TSL2563_CMD | TSL2563_REG_HIGHHIGH, - (chip->high_thres >> 8) & 0xFF); + ret = i2c_smbus_write_word_data(chip->client, + TSL2563_CMD | TSL2563_REG_HIGH, + chip->high_thres); if (ret) goto error_ret; - ret = i2c_smbus_write_byte_data(chip->client, - TSL2563_CMD | TSL2563_REG_LOWLOW, - chip->low_thres & 0xFF); + ret = i2c_smbus_write_word_data(chip->client, + TSL2563_CMD | TSL2563_REG_LOW, + chip->low_thres); if (ret) goto error_ret; - ret = i2c_smbus_write_byte_data(chip->client, - TSL2563_CMD | TSL2563_REG_LOWHIGH, - (chip->low_thres >> 8) & 0xFF); /* * Interrupt register is automatically written anyway if it is relevant * so is not here. @@ -223,6 +209,24 @@ static int tsl2563_read_id(struct tsl2563_chip *chip, u8 *id) return 0; } +static int tsl2563_configure_irq(struct tsl2563_chip *chip, bool enable) +{ + int ret; + + chip->intr &= ~TSL2563_INT_MASK; + if (enable) + chip->intr |= TSL2563_INT_LEVEL; + + ret = i2c_smbus_write_byte_data(chip->client, + TSL2563_CMD | TSL2563_REG_INT, + chip->intr); + if (ret < 0) + return ret; + + chip->int_enabled = enable; + return 0; +} + /* * "Normalized" ADC value is one obtained with 400ms of integration time and * 16x gain. This function returns the number of bits of shift needed to @@ -325,13 +329,13 @@ static int tsl2563_get_adc(struct tsl2563_chip *chip) while (retry) { ret = i2c_smbus_read_word_data(client, - TSL2563_CMD | TSL2563_REG_DATA0LOW); + TSL2563_CMD | TSL2563_REG_DATA0); if (ret < 0) goto out; adc0 = ret; ret = i2c_smbus_read_word_data(client, - TSL2563_CMD | TSL2563_REG_DATA1LOW); + TSL2563_CMD | TSL2563_REG_DATA1); if (ret < 0) goto out; adc1 = ret; @@ -352,12 +356,12 @@ out: static inline int tsl2563_calib_to_sysfs(u32 calib) { - return (int) (((calib * CALIB_BASE_SYSFS) + - CALIB_FRAC_HALF) >> CALIB_FRAC_BITS); + return (int)DIV_ROUND_CLOSEST(calib * CALIB_BASE_SYSFS, BIT(CALIB_FRAC_BITS)); } static inline u32 tsl2563_calib_from_sysfs(int value) { + /* Make a fraction from a number n that was multiplied with b. */ return (((u32) value) << CALIB_FRAC_BITS) / CALIB_BASE_SYSFS; } @@ -584,20 +588,18 @@ static int tsl2563_write_thresh(struct iio_dev *indio_dev, { struct tsl2563_chip *chip = iio_priv(indio_dev); int ret; - u8 address; + + mutex_lock(&chip->lock); if (dir == IIO_EV_DIR_RISING) - address = TSL2563_REG_HIGHLOW; + ret = i2c_smbus_write_word_data(chip->client, + TSL2563_CMD | TSL2563_REG_HIGH, val); else - address = TSL2563_REG_LOWLOW; - mutex_lock(&chip->lock); - ret = i2c_smbus_write_byte_data(chip->client, TSL2563_CMD | address, - val & 0xFF); + ret = i2c_smbus_write_word_data(chip->client, + TSL2563_CMD | TSL2563_REG_LOW, val); if (ret) goto error_ret; - ret = i2c_smbus_write_byte_data(chip->client, - TSL2563_CMD | (address + 1), - (val >> 8) & 0xFF); + if (dir == IIO_EV_DIR_RISING) chip->high_thres = val; else @@ -634,9 +636,7 @@ static int tsl2563_write_interrupt_config(struct iio_dev *indio_dev, int ret = 0; mutex_lock(&chip->lock); - if (state && !(chip->intr & 0x30)) { - chip->intr &= ~0x30; - chip->intr |= 0x10; + if (state && !(chip->intr & TSL2563_INT_MASK)) { /* ensure the chip is actually on */ cancel_delayed_work_sync(&chip->poweroff_work); if (!tsl2563_get_power(chip)) { @@ -647,18 +647,11 @@ static int tsl2563_write_interrupt_config(struct iio_dev *indio_dev, if (ret) goto out; } - ret = i2c_smbus_write_byte_data(chip->client, - TSL2563_CMD | TSL2563_REG_INT, - chip->intr); - chip->int_enabled = true; + ret = tsl2563_configure_irq(chip, true); } - if (!state && (chip->intr & 0x30)) { - chip->intr &= ~0x30; - ret = i2c_smbus_write_byte_data(chip->client, - TSL2563_CMD | TSL2563_REG_INT, - chip->intr); - chip->int_enabled = false; + if (!state && (chip->intr & TSL2563_INT_MASK)) { + ret = tsl2563_configure_irq(chip, false); /* now the interrupt is not enabled, we can go to sleep */ schedule_delayed_work(&chip->poweroff_work, 5 * HZ); } @@ -682,7 +675,7 @@ static int tsl2563_read_interrupt_config(struct iio_dev *indio_dev, if (ret < 0) return ret; - return !!(ret & 0x30); + return !!(ret & TSL2563_INT_MASK); } static const struct iio_info tsl2563_info_no_irq = { @@ -701,13 +694,14 @@ static const struct iio_info tsl2563_info = { static int tsl2563_probe(struct i2c_client *client) { + struct device *dev = &client->dev; struct iio_dev *indio_dev; struct tsl2563_chip *chip; - struct tsl2563_platform_data *pdata = client->dev.platform_data; - int err = 0; + unsigned long irq_flags; u8 id = 0; + int err; - indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*chip)); if (!indio_dev) return -ENOMEM; @@ -717,16 +711,12 @@ static int tsl2563_probe(struct i2c_client *client) chip->client = client; err = tsl2563_detect(chip); - if (err) { - dev_err(&client->dev, "detect error %d\n", -err); - return err; - } + if (err) + return dev_err_probe(dev, err, "detect error\n"); err = tsl2563_read_id(chip, &id); - if (err) { - dev_err(&client->dev, "read id error %d\n", -err); - return err; - } + if (err) + return dev_err_probe(dev, err, "read id error\n"); mutex_init(&chip->lock); @@ -738,16 +728,10 @@ static int tsl2563_probe(struct i2c_client *client) chip->calib0 = tsl2563_calib_from_sysfs(CALIB_BASE_SYSFS); chip->calib1 = tsl2563_calib_from_sysfs(CALIB_BASE_SYSFS); - if (pdata) { - chip->cover_comp_gain = pdata->cover_comp_gain; - } else { - err = device_property_read_u32(&client->dev, "amstaos,cover-comp-gain", - &chip->cover_comp_gain); - if (err) - chip->cover_comp_gain = 1; - } + chip->cover_comp_gain = 1; + device_property_read_u32(dev, "amstaos,cover-comp-gain", &chip->cover_comp_gain); - dev_info(&client->dev, "model %d, rev. %d\n", id >> 4, id & 0x0f); + dev_info(dev, "model %d, rev. %d\n", id >> 4, id & 0x0f); indio_dev->name = client->name; indio_dev->channels = tsl2563_channels; indio_dev->num_channels = ARRAY_SIZE(tsl2563_channels); @@ -759,23 +743,24 @@ static int tsl2563_probe(struct i2c_client *client) indio_dev->info = &tsl2563_info_no_irq; if (client->irq) { - err = devm_request_threaded_irq(&client->dev, client->irq, + irq_flags = irq_get_trigger_type(client->irq); + if (irq_flags == IRQF_TRIGGER_NONE) + irq_flags = IRQF_TRIGGER_RISING; + irq_flags |= IRQF_ONESHOT; + + err = devm_request_threaded_irq(dev, client->irq, NULL, &tsl2563_event_handler, - IRQF_TRIGGER_RISING | IRQF_ONESHOT, + irq_flags, "tsl2563_event", indio_dev); - if (err) { - dev_err(&client->dev, "irq request error %d\n", -err); - return err; - } + if (err) + return dev_err_probe(dev, err, "irq request error\n"); } err = tsl2563_configure(chip); - if (err) { - dev_err(&client->dev, "configure error %d\n", -err); - return err; - } + if (err) + return dev_err_probe(dev, err, "configure error\n"); INIT_DELAYED_WORK(&chip->poweroff_work, tsl2563_poweroff_work); @@ -784,7 +769,7 @@ static int tsl2563_probe(struct i2c_client *client) err = iio_device_register(indio_dev); if (err) { - dev_err(&client->dev, "iio registration error %d\n", -err); + dev_err_probe(dev, err, "iio registration error\n"); goto fail; } @@ -804,15 +789,13 @@ static void tsl2563_remove(struct i2c_client *client) if (!chip->int_enabled) cancel_delayed_work_sync(&chip->poweroff_work); /* Ensure that interrupts are disabled - then flush any bottom halves */ - chip->intr &= ~0x30; - i2c_smbus_write_byte_data(chip->client, TSL2563_CMD | TSL2563_REG_INT, - chip->intr); + tsl2563_configure_irq(chip, false); tsl2563_set_power(chip, 0); } static int tsl2563_suspend(struct device *dev) { - struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct iio_dev *indio_dev = dev_get_drvdata(dev); struct tsl2563_chip *chip = iio_priv(indio_dev); int ret; @@ -831,7 +814,7 @@ out: static int tsl2563_resume(struct device *dev) { - struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct iio_dev *indio_dev = dev_get_drvdata(dev); struct tsl2563_chip *chip = iio_priv(indio_dev); int ret; diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c index cc1a2062e76d..6bdfce9747f9 100644 --- a/drivers/iio/light/vcnl4000.c +++ b/drivers/iio/light/vcnl4000.c @@ -60,8 +60,11 @@ #define VCNL4200_AL_CONF 0x00 /* Ambient light configuration */ #define VCNL4200_PS_CONF1 0x03 /* Proximity configuration */ +#define VCNL4040_PS_THDL_LM 0x06 /* Proximity threshold low */ +#define VCNL4040_PS_THDH_LM 0x07 /* Proximity threshold high */ #define VCNL4200_PS_DATA 0x08 /* Proximity data */ #define VCNL4200_AL_DATA 0x09 /* Ambient light data */ +#define VCNL4040_INT_FLAGS 0x0b /* Interrupt register */ #define VCNL4200_DEV_ID 0x0e /* Device ID, slave address and version */ #define VCNL4040_DEV_ID 0x0c /* Device ID and version */ @@ -78,6 +81,9 @@ #define VCNL4040_ALS_CONF_ALS_SHUTDOWN BIT(0) #define VCNL4040_PS_CONF1_PS_SHUTDOWN BIT(0) #define VCNL4040_PS_CONF2_PS_IT GENMASK(3, 1) /* Proximity integration time */ +#define VCNL4040_PS_CONF2_PS_INT GENMASK(9, 8) /* Proximity interrupt mode */ +#define VCNL4040_PS_IF_AWAY BIT(8) /* Proximity event cross low threshold */ +#define VCNL4040_PS_IF_CLOSE BIT(9) /* Proximity event cross high threshold */ /* Bit masks for interrupt registers. */ #define VCNL4010_INT_THR_SEL BIT(0) /* Select threshold interrupt source */ @@ -138,6 +144,7 @@ struct vcnl4000_data { enum vcnl4000_device_ids id; int rev; int al_scale; + u8 ps_int; /* proximity interrupt mode */ const struct vcnl4000_chip_spec *chip_spec; struct mutex vcnl4000_lock; struct vcnl4200_channel vcnl4200_al; @@ -150,11 +157,13 @@ struct vcnl4000_chip_spec { struct iio_chan_spec const *channels; const int num_channels; const struct iio_info *info; - bool irq_support; + const struct iio_buffer_setup_ops *buffer_setup_ops; int (*init)(struct vcnl4000_data *data); int (*measure_light)(struct vcnl4000_data *data, int *val); int (*measure_proximity)(struct vcnl4000_data *data, int *val); int (*set_power_state)(struct vcnl4000_data *data, bool on); + irqreturn_t (*irq_thread)(int irq, void *priv); + irqreturn_t (*trig_buffer_func)(int irq, void *priv); }; static const struct i2c_device_id vcnl4000_id[] = { @@ -254,6 +263,10 @@ static int vcnl4200_set_power_state(struct vcnl4000_data *data, bool on) { int ret; + /* Do not power down if interrupts are enabled */ + if (!on && data->ps_int) + return 0; + ret = vcnl4000_write_als_enable(data, on); if (ret < 0) return ret; @@ -295,6 +308,7 @@ static int vcnl4200_init(struct vcnl4000_data *data) dev_dbg(&data->client->dev, "device id 0x%x", id); data->rev = (ret >> 8) & 0xf; + data->ps_int = 0; data->vcnl4200_al.reg = VCNL4200_AL_DATA; data->vcnl4200_ps.reg = VCNL4200_PS_DATA; @@ -795,6 +809,64 @@ static int vcnl4010_write_event(struct iio_dev *indio_dev, } } +static int vcnl4040_read_event(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) +{ + int ret; + struct vcnl4000_data *data = iio_priv(indio_dev); + + switch (dir) { + case IIO_EV_DIR_RISING: + ret = i2c_smbus_read_word_data(data->client, + VCNL4040_PS_THDH_LM); + if (ret < 0) + return ret; + *val = ret; + return IIO_VAL_INT; + case IIO_EV_DIR_FALLING: + ret = i2c_smbus_read_word_data(data->client, + VCNL4040_PS_THDL_LM); + if (ret < 0) + return ret; + *val = ret; + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + +static int vcnl4040_write_event(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) +{ + int ret; + struct vcnl4000_data *data = iio_priv(indio_dev); + + switch (dir) { + case IIO_EV_DIR_RISING: + ret = i2c_smbus_write_word_data(data->client, + VCNL4040_PS_THDH_LM, val); + if (ret < 0) + return ret; + return IIO_VAL_INT; + case IIO_EV_DIR_FALLING: + ret = i2c_smbus_write_word_data(data->client, + VCNL4040_PS_THDL_LM, val); + if (ret < 0) + return ret; + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + static bool vcnl4010_is_thr_enabled(struct vcnl4000_data *data) { int ret; @@ -877,6 +949,86 @@ static int vcnl4010_write_event_config(struct iio_dev *indio_dev, } } +static int vcnl4040_read_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) +{ + int ret; + struct vcnl4000_data *data = iio_priv(indio_dev); + + ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1); + if (ret < 0) + return ret; + + data->ps_int = FIELD_GET(VCNL4040_PS_CONF2_PS_INT, ret); + + return (dir == IIO_EV_DIR_RISING) ? + FIELD_GET(VCNL4040_PS_IF_AWAY, ret) : + FIELD_GET(VCNL4040_PS_IF_CLOSE, ret); +} + +static int vcnl4040_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) +{ + int ret; + u16 val, mask; + struct vcnl4000_data *data = iio_priv(indio_dev); + + mutex_lock(&data->vcnl4000_lock); + + ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1); + if (ret < 0) + goto out; + + if (dir == IIO_EV_DIR_RISING) + mask = VCNL4040_PS_IF_AWAY; + else + mask = VCNL4040_PS_IF_CLOSE; + + val = state ? (ret | mask) : (ret & ~mask); + + data->ps_int = FIELD_GET(VCNL4040_PS_CONF2_PS_INT, val); + ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, val); + +out: + mutex_unlock(&data->vcnl4000_lock); + data->chip_spec->set_power_state(data, data->ps_int != 0); + + return ret; +} + +static irqreturn_t vcnl4040_irq_thread(int irq, void *p) +{ + struct iio_dev *indio_dev = p; + struct vcnl4000_data *data = iio_priv(indio_dev); + int ret; + + ret = i2c_smbus_read_word_data(data->client, VCNL4040_INT_FLAGS); + if (ret < 0) + return IRQ_HANDLED; + + if (ret & VCNL4040_PS_IF_CLOSE) { + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), + iio_get_time_ns(indio_dev)); + } + + if (ret & VCNL4040_PS_IF_AWAY) { + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING), + iio_get_time_ns(indio_dev)); + } + + return IRQ_HANDLED; +} + static ssize_t vcnl4000_read_near_level(struct iio_dev *indio_dev, uintptr_t priv, const struct iio_chan_spec *chan, @@ -887,6 +1039,134 @@ static ssize_t vcnl4000_read_near_level(struct iio_dev *indio_dev, return sprintf(buf, "%u\n", data->near_level); } +static irqreturn_t vcnl4010_irq_thread(int irq, void *p) +{ + struct iio_dev *indio_dev = p; + struct vcnl4000_data *data = iio_priv(indio_dev); + unsigned long isr; + int ret; + + ret = i2c_smbus_read_byte_data(data->client, VCNL4010_ISR); + if (ret < 0) + goto end; + + isr = ret; + + if (isr & VCNL4010_INT_THR) { + if (test_bit(VCNL4010_INT_THR_LOW, &isr)) { + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE( + IIO_PROXIMITY, + 1, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING), + iio_get_time_ns(indio_dev)); + } + + if (test_bit(VCNL4010_INT_THR_HIGH, &isr)) { + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE( + IIO_PROXIMITY, + 1, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), + iio_get_time_ns(indio_dev)); + } + + i2c_smbus_write_byte_data(data->client, VCNL4010_ISR, + isr & VCNL4010_INT_THR); + } + + if (isr & VCNL4010_INT_DRDY && iio_buffer_enabled(indio_dev)) + iio_trigger_poll_chained(indio_dev->trig); + +end: + return IRQ_HANDLED; +} + +static irqreturn_t vcnl4010_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct vcnl4000_data *data = iio_priv(indio_dev); + const unsigned long *active_scan_mask = indio_dev->active_scan_mask; + u16 buffer[8] __aligned(8) = {0}; /* 1x16-bit + naturally aligned ts */ + bool data_read = false; + unsigned long isr; + int val = 0; + int ret; + + ret = i2c_smbus_read_byte_data(data->client, VCNL4010_ISR); + if (ret < 0) + goto end; + + isr = ret; + + if (test_bit(0, active_scan_mask)) { + if (test_bit(VCNL4010_INT_PROXIMITY, &isr)) { + ret = vcnl4000_read_data(data, + VCNL4000_PS_RESULT_HI, + &val); + if (ret < 0) + goto end; + + buffer[0] = val; + data_read = true; + } + } + + ret = i2c_smbus_write_byte_data(data->client, VCNL4010_ISR, + isr & VCNL4010_INT_DRDY); + if (ret < 0) + goto end; + + if (!data_read) + goto end; + + iio_push_to_buffers_with_timestamp(indio_dev, buffer, + iio_get_time_ns(indio_dev)); + +end: + iio_trigger_notify_done(indio_dev->trig); + return IRQ_HANDLED; +} + +static int vcnl4010_buffer_postenable(struct iio_dev *indio_dev) +{ + struct vcnl4000_data *data = iio_priv(indio_dev); + int ret; + int cmd; + + /* Do not enable the buffer if we are already capturing events. */ + if (vcnl4010_is_in_periodic_mode(data)) + return -EBUSY; + + ret = i2c_smbus_write_byte_data(data->client, VCNL4010_INT_CTRL, + VCNL4010_INT_PROX_EN); + if (ret < 0) + return ret; + + cmd = VCNL4000_SELF_TIMED_EN | VCNL4000_PROX_EN; + return i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND, cmd); +} + +static int vcnl4010_buffer_predisable(struct iio_dev *indio_dev) +{ + struct vcnl4000_data *data = iio_priv(indio_dev); + int ret; + + ret = i2c_smbus_write_byte_data(data->client, VCNL4010_INT_CTRL, 0); + if (ret < 0) + return ret; + + return i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND, 0); +} + +static const struct iio_buffer_setup_ops vcnl4010_buffer_ops = { + .postenable = &vcnl4010_buffer_postenable, + .predisable = &vcnl4010_buffer_predisable, +}; + static const struct iio_chan_spec_ext_info vcnl4000_ext_info[] = { { .name = "nearlevel", @@ -912,6 +1192,18 @@ static const struct iio_event_spec vcnl4000_event_spec[] = { } }; +static const struct iio_event_spec vcnl4040_event_spec[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE), + }, { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE), + }, +}; + static const struct iio_chan_spec vcnl4000_channels[] = { { .type = IIO_LIGHT, @@ -960,6 +1252,8 @@ static const struct iio_chan_spec vcnl4040_channels[] = { BIT(IIO_CHAN_INFO_INT_TIME), .info_mask_separate_available = BIT(IIO_CHAN_INFO_INT_TIME), .ext_info = vcnl4000_ext_info, + .event_spec = vcnl4040_event_spec, + .num_event_specs = ARRAY_SIZE(vcnl4040_event_spec), } }; @@ -980,6 +1274,10 @@ static const struct iio_info vcnl4010_info = { static const struct iio_info vcnl4040_info = { .read_raw = vcnl4000_read_raw, .write_raw = vcnl4040_write_raw, + .read_event_value = vcnl4040_read_event, + .write_event_value = vcnl4040_write_event, + .read_event_config = vcnl4040_read_event_config, + .write_event_config = vcnl4040_write_event_config, .read_avail = vcnl4040_read_avail, }; @@ -993,7 +1291,6 @@ static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = { .channels = vcnl4000_channels, .num_channels = ARRAY_SIZE(vcnl4000_channels), .info = &vcnl4000_info, - .irq_support = false, }, [VCNL4010] = { .prod = "VCNL4010/4020", @@ -1004,7 +1301,9 @@ static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = { .channels = vcnl4010_channels, .num_channels = ARRAY_SIZE(vcnl4010_channels), .info = &vcnl4010_info, - .irq_support = true, + .irq_thread = vcnl4010_irq_thread, + .trig_buffer_func = vcnl4010_trigger_handler, + .buffer_setup_ops = &vcnl4010_buffer_ops, }, [VCNL4040] = { .prod = "VCNL4040", @@ -1015,7 +1314,7 @@ static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = { .channels = vcnl4040_channels, .num_channels = ARRAY_SIZE(vcnl4040_channels), .info = &vcnl4040_info, - .irq_support = false, + .irq_thread = vcnl4040_irq_thread, }, [VCNL4200] = { .prod = "VCNL4200", @@ -1026,138 +1325,9 @@ static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = { .channels = vcnl4000_channels, .num_channels = ARRAY_SIZE(vcnl4000_channels), .info = &vcnl4000_info, - .irq_support = false, }, }; -static irqreturn_t vcnl4010_irq_thread(int irq, void *p) -{ - struct iio_dev *indio_dev = p; - struct vcnl4000_data *data = iio_priv(indio_dev); - unsigned long isr; - int ret; - - ret = i2c_smbus_read_byte_data(data->client, VCNL4010_ISR); - if (ret < 0) - goto end; - - isr = ret; - - if (isr & VCNL4010_INT_THR) { - if (test_bit(VCNL4010_INT_THR_LOW, &isr)) { - iio_push_event(indio_dev, - IIO_UNMOD_EVENT_CODE( - IIO_PROXIMITY, - 1, - IIO_EV_TYPE_THRESH, - IIO_EV_DIR_FALLING), - iio_get_time_ns(indio_dev)); - } - - if (test_bit(VCNL4010_INT_THR_HIGH, &isr)) { - iio_push_event(indio_dev, - IIO_UNMOD_EVENT_CODE( - IIO_PROXIMITY, - 1, - IIO_EV_TYPE_THRESH, - IIO_EV_DIR_RISING), - iio_get_time_ns(indio_dev)); - } - - i2c_smbus_write_byte_data(data->client, VCNL4010_ISR, - isr & VCNL4010_INT_THR); - } - - if (isr & VCNL4010_INT_DRDY && iio_buffer_enabled(indio_dev)) - iio_trigger_poll_chained(indio_dev->trig); - -end: - return IRQ_HANDLED; -} - -static irqreturn_t vcnl4010_trigger_handler(int irq, void *p) -{ - struct iio_poll_func *pf = p; - struct iio_dev *indio_dev = pf->indio_dev; - struct vcnl4000_data *data = iio_priv(indio_dev); - const unsigned long *active_scan_mask = indio_dev->active_scan_mask; - u16 buffer[8] __aligned(8) = {0}; /* 1x16-bit + naturally aligned ts */ - bool data_read = false; - unsigned long isr; - int val = 0; - int ret; - - ret = i2c_smbus_read_byte_data(data->client, VCNL4010_ISR); - if (ret < 0) - goto end; - - isr = ret; - - if (test_bit(0, active_scan_mask)) { - if (test_bit(VCNL4010_INT_PROXIMITY, &isr)) { - ret = vcnl4000_read_data(data, - VCNL4000_PS_RESULT_HI, - &val); - if (ret < 0) - goto end; - - buffer[0] = val; - data_read = true; - } - } - - ret = i2c_smbus_write_byte_data(data->client, VCNL4010_ISR, - isr & VCNL4010_INT_DRDY); - if (ret < 0) - goto end; - - if (!data_read) - goto end; - - iio_push_to_buffers_with_timestamp(indio_dev, buffer, - iio_get_time_ns(indio_dev)); - -end: - iio_trigger_notify_done(indio_dev->trig); - return IRQ_HANDLED; -} - -static int vcnl4010_buffer_postenable(struct iio_dev *indio_dev) -{ - struct vcnl4000_data *data = iio_priv(indio_dev); - int ret; - int cmd; - - /* Do not enable the buffer if we are already capturing events. */ - if (vcnl4010_is_in_periodic_mode(data)) - return -EBUSY; - - ret = i2c_smbus_write_byte_data(data->client, VCNL4010_INT_CTRL, - VCNL4010_INT_PROX_EN); - if (ret < 0) - return ret; - - cmd = VCNL4000_SELF_TIMED_EN | VCNL4000_PROX_EN; - return i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND, cmd); -} - -static int vcnl4010_buffer_predisable(struct iio_dev *indio_dev) -{ - struct vcnl4000_data *data = iio_priv(indio_dev); - int ret; - - ret = i2c_smbus_write_byte_data(data->client, VCNL4010_INT_CTRL, 0); - if (ret < 0) - return ret; - - return i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND, 0); -} - -static const struct iio_buffer_setup_ops vcnl4010_buffer_ops = { - .postenable = &vcnl4010_buffer_postenable, - .predisable = &vcnl4010_buffer_predisable, -}; - static const struct iio_trigger_ops vcnl4010_trigger_ops = { .validate_device = iio_trigger_validate_own_device, }; @@ -1214,22 +1384,25 @@ static int vcnl4000_probe(struct i2c_client *client) indio_dev->name = VCNL4000_DRV_NAME; indio_dev->modes = INDIO_DIRECT_MODE; - if (client->irq && data->chip_spec->irq_support) { + if (data->chip_spec->trig_buffer_func && + data->chip_spec->buffer_setup_ops) { ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev, NULL, - vcnl4010_trigger_handler, - &vcnl4010_buffer_ops); + data->chip_spec->trig_buffer_func, + data->chip_spec->buffer_setup_ops); if (ret < 0) { dev_err(&client->dev, "unable to setup iio triggered buffer\n"); return ret; } + } + if (client->irq && data->chip_spec->irq_thread) { ret = devm_request_threaded_irq(&client->dev, client->irq, - NULL, vcnl4010_irq_thread, + NULL, data->chip_spec->irq_thread, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - "vcnl4010_irq", + "vcnl4000_irq", indio_dev); if (ret < 0) { dev_err(&client->dev, "irq request failed\n"); diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig index b91fc5e6a26e..38532d840f2a 100644 --- a/drivers/iio/magnetometer/Kconfig +++ b/drivers/iio/magnetometer/Kconfig @@ -119,7 +119,7 @@ config IIO_ST_MAGN_3AXIS select IIO_TRIGGERED_BUFFER if (IIO_BUFFER) help Say yes here to build support for STMicroelectronics magnetometers: - LSM303DLHC, LSM303DLM, LIS3MDL. + LSM303C, LSM303DLHC, LSM303DLM, LIS3MDL. Also need to enable at least one of I2C and SPI interface drivers below. @@ -208,6 +208,18 @@ config SENSORS_RM3100_SPI To compile this driver as a module, choose M here: the module will be called rm3100-spi. +config TI_TMAG5273 + tristate "TI TMAG5273 Low-Power Linear 3D Hall-Effect Sensor" + depends on I2C + select REGMAP_I2C + help + Say Y here to add support for the TI TMAG5273 Low-Power + Linear 3D Hall-Effect Sensor. + + This driver can also be compiled as a module. + To compile this driver as a module, choose M here: the module + will be called tmag5273. + config YAMAHA_YAS530 tristate "Yamaha YAS530 family of 3-Axis Magnetometers (I2C)" depends on I2C diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile index b9f45b7fafc3..b1c784ea71c8 100644 --- a/drivers/iio/magnetometer/Makefile +++ b/drivers/iio/magnetometer/Makefile @@ -29,4 +29,6 @@ obj-$(CONFIG_SENSORS_RM3100) += rm3100-core.o obj-$(CONFIG_SENSORS_RM3100_I2C) += rm3100-i2c.o obj-$(CONFIG_SENSORS_RM3100_SPI) += rm3100-spi.o +obj-$(CONFIG_TI_TMAG5273) += tmag5273.o + obj-$(CONFIG_YAMAHA_YAS530) += yamaha-yas530.o diff --git a/drivers/iio/magnetometer/st_magn.h b/drivers/iio/magnetometer/st_magn.h index 785b7f7b8b06..89945984d966 100644 --- a/drivers/iio/magnetometer/st_magn.h +++ b/drivers/iio/magnetometer/st_magn.h @@ -22,6 +22,7 @@ #define LIS2MDL_MAGN_DEV_NAME "lis2mdl" #define LSM9DS1_MAGN_DEV_NAME "lsm9ds1_magn" #define IIS2MDC_MAGN_DEV_NAME "iis2mdc" +#define LSM303C_MAGN_DEV_NAME "lsm303c_magn" #ifdef CONFIG_IIO_BUFFER int st_magn_allocate_ring(struct iio_dev *indio_dev); diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c index e2fd233b3626..8faa7409d9e1 100644 --- a/drivers/iio/magnetometer/st_magn_core.c +++ b/drivers/iio/magnetometer/st_magn_core.c @@ -305,6 +305,7 @@ static const struct st_sensor_settings st_magn_sensors_settings[] = { .sensors_supported = { [0] = LIS3MDL_MAGN_DEV_NAME, [1] = LSM9DS1_MAGN_DEV_NAME, + [2] = LSM303C_MAGN_DEV_NAME, }, .ch = (struct iio_chan_spec *)st_magn_2_16bit_channels, .odr = { diff --git a/drivers/iio/magnetometer/st_magn_i2c.c b/drivers/iio/magnetometer/st_magn_i2c.c index b4098d3b3813..cc0e0e94b129 100644 --- a/drivers/iio/magnetometer/st_magn_i2c.c +++ b/drivers/iio/magnetometer/st_magn_i2c.c @@ -50,6 +50,10 @@ static const struct of_device_id st_magn_of_match[] = { .compatible = "st,iis2mdc", .data = IIS2MDC_MAGN_DEV_NAME, }, + { + .compatible = "st,lsm303c-magn", + .data = LSM303C_MAGN_DEV_NAME, + }, {}, }; MODULE_DEVICE_TABLE(of, st_magn_of_match); @@ -97,6 +101,7 @@ static const struct i2c_device_id st_magn_id_table[] = { { LIS2MDL_MAGN_DEV_NAME }, { LSM9DS1_MAGN_DEV_NAME }, { IIS2MDC_MAGN_DEV_NAME }, + { LSM303C_MAGN_DEV_NAME }, {}, }; MODULE_DEVICE_TABLE(i2c, st_magn_id_table); diff --git a/drivers/iio/magnetometer/st_magn_spi.c b/drivers/iio/magnetometer/st_magn_spi.c index 6ddc4318564a..f203e1f87eec 100644 --- a/drivers/iio/magnetometer/st_magn_spi.c +++ b/drivers/iio/magnetometer/st_magn_spi.c @@ -45,6 +45,10 @@ static const struct of_device_id st_magn_of_match[] = { .compatible = "st,iis2mdc", .data = IIS2MDC_MAGN_DEV_NAME, }, + { + .compatible = "st,lsm303c-magn", + .data = LSM303C_MAGN_DEV_NAME, + }, {} }; MODULE_DEVICE_TABLE(of, st_magn_of_match); @@ -89,6 +93,7 @@ static const struct spi_device_id st_magn_id_table[] = { { LIS2MDL_MAGN_DEV_NAME }, { LSM9DS1_MAGN_DEV_NAME }, { IIS2MDC_MAGN_DEV_NAME }, + { LSM303C_MAGN_DEV_NAME }, {}, }; MODULE_DEVICE_TABLE(spi, st_magn_id_table); diff --git a/drivers/iio/magnetometer/tmag5273.c b/drivers/iio/magnetometer/tmag5273.c new file mode 100644 index 000000000000..28bb7efe8df8 --- /dev/null +++ b/drivers/iio/magnetometer/tmag5273.c @@ -0,0 +1,743 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Driver for the TI TMAG5273 Low-Power Linear 3D Hall-Effect Sensor + * + * Copyright (C) 2022 WolfVision GmbH + * + * Author: Gerald Loacker <gerald.loacker@wolfvision.net> + */ + +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/regmap.h> +#include <linux/pm_runtime.h> + +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> + +#define TMAG5273_DEVICE_CONFIG_1 0x00 +#define TMAG5273_DEVICE_CONFIG_2 0x01 +#define TMAG5273_SENSOR_CONFIG_1 0x02 +#define TMAG5273_SENSOR_CONFIG_2 0x03 +#define TMAG5273_X_THR_CONFIG 0x04 +#define TMAG5273_Y_THR_CONFIG 0x05 +#define TMAG5273_Z_THR_CONFIG 0x06 +#define TMAG5273_T_CONFIG 0x07 +#define TMAG5273_INT_CONFIG_1 0x08 +#define TMAG5273_MAG_GAIN_CONFIG 0x09 +#define TMAG5273_MAG_OFFSET_CONFIG_1 0x0A +#define TMAG5273_MAG_OFFSET_CONFIG_2 0x0B +#define TMAG5273_I2C_ADDRESS 0x0C +#define TMAG5273_DEVICE_ID 0x0D +#define TMAG5273_MANUFACTURER_ID_LSB 0x0E +#define TMAG5273_MANUFACTURER_ID_MSB 0x0F +#define TMAG5273_T_MSB_RESULT 0x10 +#define TMAG5273_T_LSB_RESULT 0x11 +#define TMAG5273_X_MSB_RESULT 0x12 +#define TMAG5273_X_LSB_RESULT 0x13 +#define TMAG5273_Y_MSB_RESULT 0x14 +#define TMAG5273_Y_LSB_RESULT 0x15 +#define TMAG5273_Z_MSB_RESULT 0x16 +#define TMAG5273_Z_LSB_RESULT 0x17 +#define TMAG5273_CONV_STATUS 0x18 +#define TMAG5273_ANGLE_RESULT_MSB 0x19 +#define TMAG5273_ANGLE_RESULT_LSB 0x1A +#define TMAG5273_MAGNITUDE_RESULT 0x1B +#define TMAG5273_DEVICE_STATUS 0x1C +#define TMAG5273_MAX_REG TMAG5273_DEVICE_STATUS + +#define TMAG5273_AUTOSLEEP_DELAY_MS 5000 +#define TMAG5273_MAX_AVERAGE 32 + +/* + * bits in the TMAG5273_MANUFACTURER_ID_LSB / MSB register + * 16-bit unique manufacturer ID 0x49 / 0x54 = "TI" + */ +#define TMAG5273_MANUFACTURER_ID 0x5449 + +/* bits in the TMAG5273_DEVICE_CONFIG_1 register */ +#define TMAG5273_AVG_MODE_MASK GENMASK(4, 2) +#define TMAG5273_AVG_1_MODE FIELD_PREP(TMAG5273_AVG_MODE_MASK, 0) +#define TMAG5273_AVG_2_MODE FIELD_PREP(TMAG5273_AVG_MODE_MASK, 1) +#define TMAG5273_AVG_4_MODE FIELD_PREP(TMAG5273_AVG_MODE_MASK, 2) +#define TMAG5273_AVG_8_MODE FIELD_PREP(TMAG5273_AVG_MODE_MASK, 3) +#define TMAG5273_AVG_16_MODE FIELD_PREP(TMAG5273_AVG_MODE_MASK, 4) +#define TMAG5273_AVG_32_MODE FIELD_PREP(TMAG5273_AVG_MODE_MASK, 5) + +/* bits in the TMAG5273_DEVICE_CONFIG_2 register */ +#define TMAG5273_OP_MODE_MASK GENMASK(1, 0) +#define TMAG5273_OP_MODE_STANDBY FIELD_PREP(TMAG5273_OP_MODE_MASK, 0) +#define TMAG5273_OP_MODE_SLEEP FIELD_PREP(TMAG5273_OP_MODE_MASK, 1) +#define TMAG5273_OP_MODE_CONT FIELD_PREP(TMAG5273_OP_MODE_MASK, 2) +#define TMAG5273_OP_MODE_WAKEUP FIELD_PREP(TMAG5273_OP_MODE_MASK, 3) + +/* bits in the TMAG5273_SENSOR_CONFIG_1 register */ +#define TMAG5273_MAG_CH_EN_MASK GENMASK(7, 4) +#define TMAG5273_MAG_CH_EN_X_Y_Z 7 + +/* bits in the TMAG5273_SENSOR_CONFIG_2 register */ +#define TMAG5273_Z_RANGE_MASK BIT(0) +#define TMAG5273_X_Y_RANGE_MASK BIT(1) +#define TMAG5273_ANGLE_EN_MASK GENMASK(3, 2) +#define TMAG5273_ANGLE_EN_OFF 0 +#define TMAG5273_ANGLE_EN_X_Y 1 +#define TMAG5273_ANGLE_EN_Y_Z 2 +#define TMAG5273_ANGLE_EN_X_Z 3 + +/* bits in the TMAG5273_T_CONFIG register */ +#define TMAG5273_T_CH_EN BIT(0) + +/* bits in the TMAG5273_DEVICE_ID register */ +#define TMAG5273_VERSION_MASK GENMASK(1, 0) + +/* bits in the TMAG5273_CONV_STATUS register */ +#define TMAG5273_CONV_STATUS_COMPLETE BIT(0) + +enum tmag5273_channels { + TEMPERATURE = 0, + AXIS_X, + AXIS_Y, + AXIS_Z, + ANGLE, + MAGNITUDE, +}; + +enum tmag5273_scale_index { + MAGN_RANGE_LOW = 0, + MAGN_RANGE_HIGH, + MAGN_RANGE_NUM +}; + +/* state container for the TMAG5273 driver */ +struct tmag5273_data { + struct device *dev; + unsigned int devid; + 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 + * involves several register transactions so the regmap lock is not + * enough) so that measurements get serialized in a + * first-come-first-serve manner. + */ + struct mutex lock; +}; + +static const char *const tmag5273_angle_names[] = { "off", "x-y", "y-z", "x-z" }; + +/* + * Averaging enables additional sampling of the sensor data to reduce the noise + * effect, but also increases conversion time. + */ +static const unsigned int tmag5273_avg_table[] = { + 1, 2, 4, 8, 16, 32, +}; + +/* + * Magnetic resolution in Gauss for different TMAG5273 versions. + * Scale[Gauss] = Range[mT] * 1000 / 2^15 * 10, (1 mT = 10 Gauss) + * Only version 1 and 2 are valid, version 0 and 3 are reserved. + */ +static const struct iio_val_int_plus_micro tmag5273_scale[][MAGN_RANGE_NUM] = { + { { 0, 0 }, { 0, 0 } }, + { { 0, 12200 }, { 0, 24400 } }, + { { 0, 40600 }, { 0, 81200 } }, + { { 0, 0 }, { 0, 0 } }, +}; + +static int tmag5273_get_measure(struct tmag5273_data *data, s16 *t, s16 *x, + s16 *y, s16 *z, u16 *angle, u16 *magnitude) +{ + unsigned int status, val; + __be16 reg_data[4]; + int ret; + + mutex_lock(&data->lock); + + /* + * Max. conversion time is 2425 us in 32x averaging mode for all three + * channels. Since we are in continuous measurement mode, a measurement + * may already be there, so poll for completed measurement with + * timeout. + */ + ret = regmap_read_poll_timeout(data->map, TMAG5273_CONV_STATUS, status, + status & TMAG5273_CONV_STATUS_COMPLETE, + 100, 10000); + if (ret) { + dev_err(data->dev, "timeout waiting for measurement\n"); + goto out_unlock; + } + + ret = regmap_bulk_read(data->map, TMAG5273_T_MSB_RESULT, reg_data, + sizeof(reg_data)); + if (ret) + goto out_unlock; + *t = be16_to_cpu(reg_data[0]); + *x = be16_to_cpu(reg_data[1]); + *y = be16_to_cpu(reg_data[2]); + *z = be16_to_cpu(reg_data[3]); + + ret = regmap_bulk_read(data->map, TMAG5273_ANGLE_RESULT_MSB, + ®_data[0], sizeof(reg_data[0])); + if (ret) + goto out_unlock; + /* + * angle has 9 bits integer value and 4 bits fractional part + * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + * 0 0 0 a a a a a a a a a f f f f + */ + *angle = be16_to_cpu(reg_data[0]); + + ret = regmap_read(data->map, TMAG5273_MAGNITUDE_RESULT, &val); + if (ret < 0) + goto out_unlock; + *magnitude = val; + +out_unlock: + mutex_unlock(&data->lock); + return ret; +} + +static int tmag5273_write_osr(struct tmag5273_data *data, int val) +{ + int i; + + if (val == data->conv_avg) + return 0; + + for (i = 0; i < ARRAY_SIZE(tmag5273_avg_table); i++) { + if (tmag5273_avg_table[i] == val) + break; + } + if (i == ARRAY_SIZE(tmag5273_avg_table)) + return -EINVAL; + data->conv_avg = val; + + return regmap_update_bits(data->map, TMAG5273_DEVICE_CONFIG_1, + TMAG5273_AVG_MODE_MASK, + FIELD_PREP(TMAG5273_AVG_MODE_MASK, i)); +} + +static int tmag5273_write_scale(struct tmag5273_data *data, int scale_micro) +{ + u32 value; + int i; + + for (i = 0; i < ARRAY_SIZE(tmag5273_scale[0]); i++) { + if (tmag5273_scale[data->version][i].micro == scale_micro) + break; + } + if (i == ARRAY_SIZE(tmag5273_scale[0])) + return -EINVAL; + data->scale_index = i; + + if (data->scale_index == MAGN_RANGE_LOW) + value = 0; + else + value = TMAG5273_Z_RANGE_MASK | TMAG5273_X_Y_RANGE_MASK; + + return regmap_update_bits(data->map, TMAG5273_SENSOR_CONFIG_2, + TMAG5273_Z_RANGE_MASK | TMAG5273_X_Y_RANGE_MASK, value); +} + +static int tmag5273_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + struct tmag5273_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + *vals = tmag5273_avg_table; + *type = IIO_VAL_INT; + *length = ARRAY_SIZE(tmag5273_avg_table); + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_MAGN: + *type = IIO_VAL_INT_PLUS_MICRO; + *vals = (int *)tmag5273_scale[data->version]; + *length = ARRAY_SIZE(tmag5273_scale[data->version]) * + MAGN_RANGE_NUM; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int tmag5273_read_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, int *val, + int *val2, long mask) +{ + struct tmag5273_data *data = iio_priv(indio_dev); + s16 t, x, y, z; + u16 angle, magnitude; + int ret; + + switch (mask) { + case IIO_CHAN_INFO_PROCESSED: + case IIO_CHAN_INFO_RAW: + ret = pm_runtime_resume_and_get(data->dev); + if (ret < 0) + return ret; + + ret = tmag5273_get_measure(data, &t, &x, &y, &z, &angle, &magnitude); + if (ret) + return ret; + + pm_runtime_mark_last_busy(data->dev); + pm_runtime_put_autosuspend(data->dev); + + switch (chan->address) { + case TEMPERATURE: + *val = t; + return IIO_VAL_INT; + case AXIS_X: + *val = x; + return IIO_VAL_INT; + case AXIS_Y: + *val = y; + return IIO_VAL_INT; + case AXIS_Z: + *val = z; + return IIO_VAL_INT; + case ANGLE: + *val = angle; + return IIO_VAL_INT; + case MAGNITUDE: + *val = magnitude; + return IIO_VAL_INT; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_TEMP: + /* + * Convert device specific value to millicelsius. + * Resolution from the sensor is 60.1 LSB/celsius and + * the reference value at 25 celsius is 17508 LSBs. + */ + *val = 10000; + *val2 = 601; + return IIO_VAL_FRACTIONAL; + case IIO_MAGN: + /* Magnetic resolution in uT */ + *val = 0; + *val2 = tmag5273_scale[data->version] + [data->scale_index].micro; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_ANGL: + /* + * Angle is in degrees and has four fractional bits, + * therefore use 1/16 * pi/180 to convert to radians. + */ + *val = 1000; + *val2 = 916732; + return IIO_VAL_FRACTIONAL; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_OFFSET: + switch (chan->type) { + case IIO_TEMP: + *val = -266314; + return IIO_VAL_INT; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + *val = data->conv_avg; + return IIO_VAL_INT; + + default: + return -EINVAL; + } +} + +static int tmag5273_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, + int val2, long mask) +{ + struct tmag5273_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + return tmag5273_write_osr(data, val); + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_MAGN: + if (val) + return -EINVAL; + return tmag5273_write_scale(data, val2); + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +#define TMAG5273_AXIS_CHANNEL(axis, index) \ + { \ + .type = IIO_MAGN, \ + .modified = 1, \ + .channel2 = IIO_MOD_##axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_type_available = \ + BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_all = \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + .info_mask_shared_by_all_available = \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + .address = index, \ + .scan_index = index, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_CPU, \ + }, \ + } + +static const struct iio_chan_spec tmag5273_channels[] = { + { + .type = IIO_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_OFFSET), + .address = TEMPERATURE, + .scan_index = TEMPERATURE, + .scan_type = { + .sign = 'u', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_CPU, + }, + }, + TMAG5273_AXIS_CHANNEL(X, AXIS_X), + TMAG5273_AXIS_CHANNEL(Y, AXIS_Y), + TMAG5273_AXIS_CHANNEL(Z, AXIS_Z), + { + .type = IIO_ANGL, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_all = + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .info_mask_shared_by_all_available = + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .address = ANGLE, + .scan_index = ANGLE, + .scan_type = { + .sign = 'u', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_CPU, + }, + }, + { + .type = IIO_DISTANCE, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_all = + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .info_mask_shared_by_all_available = + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .address = MAGNITUDE, + .scan_index = MAGNITUDE, + .scan_type = { + .sign = 'u', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_CPU, + }, + }, + IIO_CHAN_SOFT_TIMESTAMP(6), +}; + +static const struct iio_info tmag5273_info = { + .read_avail = tmag5273_read_avail, + .read_raw = tmag5273_read_raw, + .write_raw = tmag5273_write_raw, +}; + +static bool tmag5273_volatile_reg(struct device *dev, unsigned int reg) +{ + return reg >= TMAG5273_T_MSB_RESULT && reg <= TMAG5273_MAGNITUDE_RESULT; +} + +static const struct regmap_config tmag5273_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = TMAG5273_MAX_REG, + .volatile_reg = tmag5273_volatile_reg, +}; + +static int tmag5273_set_operating_mode(struct tmag5273_data *data, + unsigned int val) +{ + return regmap_write(data->map, TMAG5273_DEVICE_CONFIG_2, val); +} + +static void tmag5273_read_device_property(struct tmag5273_data *data) +{ + struct device *dev = data->dev; + const char *str; + int ret; + + data->angle_measurement = TMAG5273_ANGLE_EN_X_Y; + + ret = device_property_read_string(dev, "ti,angle-measurement", &str); + if (ret) + return; + + ret = match_string(tmag5273_angle_names, + ARRAY_SIZE(tmag5273_angle_names), str); + if (ret >= 0) + data->angle_measurement = ret; +} + +static void tmag5273_wake_up(struct tmag5273_data *data) +{ + int val; + + /* Wake up the chip by sending a dummy I2C command */ + regmap_read(data->map, TMAG5273_DEVICE_ID, &val); + /* + * Time to go to stand-by mode from sleep mode is 50us + * typically, during this time no I2C access is possible. + */ + usleep_range(80, 200); +} + +static int tmag5273_chip_init(struct tmag5273_data *data) +{ + int ret; + + ret = regmap_write(data->map, TMAG5273_DEVICE_CONFIG_1, + TMAG5273_AVG_32_MODE); + if (ret) + return ret; + data->conv_avg = 32; + + ret = regmap_write(data->map, TMAG5273_DEVICE_CONFIG_2, + TMAG5273_OP_MODE_CONT); + if (ret) + return ret; + + ret = regmap_write(data->map, TMAG5273_SENSOR_CONFIG_1, + FIELD_PREP(TMAG5273_MAG_CH_EN_MASK, + TMAG5273_MAG_CH_EN_X_Y_Z)); + if (ret) + return ret; + + ret = regmap_write(data->map, TMAG5273_SENSOR_CONFIG_2, + FIELD_PREP(TMAG5273_ANGLE_EN_MASK, + data->angle_measurement)); + if (ret) + return ret; + data->scale_index = MAGN_RANGE_LOW; + + return regmap_write(data->map, TMAG5273_T_CONFIG, TMAG5273_T_CH_EN); +} + +static int tmag5273_check_device_id(struct tmag5273_data *data) +{ + __le16 devid; + int val, ret; + + ret = regmap_read(data->map, TMAG5273_DEVICE_ID, &val); + if (ret) + return dev_err_probe(data->dev, ret, "failed to power on device\n"); + data->version = FIELD_PREP(TMAG5273_VERSION_MASK, val); + + ret = regmap_bulk_read(data->map, TMAG5273_MANUFACTURER_ID_LSB, &devid, + sizeof(devid)); + if (ret) + return dev_err_probe(data->dev, ret, "failed to read device ID\n"); + data->devid = le16_to_cpu(devid); + + switch (data->devid) { + case TMAG5273_MANUFACTURER_ID: + /* + * The device name matches the orderable part number. 'x' stands + * for A, B, C or D devices, which have different I2C addresses. + * Versions 1 or 2 (0 and 3 is reserved) stands for different + * magnetic strengths. + */ + snprintf(data->name, sizeof(data->name), "tmag5273x%1u", data->version); + if (data->version < 1 || data->version > 2) + dev_warn(data->dev, "Unsupported device %s\n", data->name); + return 0; + default: + /* + * Only print warning in case of unknown device ID to allow + * fallback compatible in device tree. + */ + dev_warn(data->dev, "Unknown device ID 0x%x\n", data->devid); + return 0; + } +} + +static void tmag5273_power_down(void *data) +{ + tmag5273_set_operating_mode(data, TMAG5273_OP_MODE_SLEEP); +} + +static int tmag5273_probe(struct i2c_client *i2c) +{ + struct device *dev = &i2c->dev; + struct tmag5273_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->dev = dev; + i2c_set_clientdata(i2c, indio_dev); + + data->map = devm_regmap_init_i2c(i2c, &tmag5273_regmap_config); + if (IS_ERR(data->map)) + return dev_err_probe(dev, PTR_ERR(data->map), + "failed to allocate register map\n"); + + mutex_init(&data->lock); + + ret = devm_regulator_get_enable(dev, "vcc"); + if (ret) + return dev_err_probe(dev, ret, "failed to enable regulator\n"); + + tmag5273_wake_up(data); + + ret = tmag5273_check_device_id(data); + if (ret) + return ret; + + ret = tmag5273_set_operating_mode(data, TMAG5273_OP_MODE_CONT); + if (ret) + return dev_err_probe(dev, ret, "failed to power on device\n"); + + /* + * Register powerdown deferred callback which suspends the chip + * after module unloaded. + * + * TMAG5273 should be in SUSPEND mode in the two cases: + * 1) When driver is loaded, but we do not have any data or + * configuration requests to it (we are solving it using + * autosuspend feature). + * 2) When driver is unloaded and device is not used (devm action is + * used in this case). + */ + ret = devm_add_action_or_reset(dev, tmag5273_power_down, data); + if (ret) + return dev_err_probe(dev, ret, "failed to add powerdown action\n"); + + ret = pm_runtime_set_active(dev); + if (ret < 0) + return ret; + + ret = devm_pm_runtime_enable(dev); + if (ret) + return ret; + + pm_runtime_get_noresume(dev); + pm_runtime_set_autosuspend_delay(dev, TMAG5273_AUTOSLEEP_DELAY_MS); + pm_runtime_use_autosuspend(dev); + + tmag5273_read_device_property(data); + + ret = tmag5273_chip_init(data); + if (ret) + return dev_err_probe(dev, ret, "failed to init device\n"); + + indio_dev->info = &tmag5273_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->name = data->name; + indio_dev->channels = tmag5273_channels; + indio_dev->num_channels = ARRAY_SIZE(tmag5273_channels); + + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + + ret = devm_iio_device_register(dev, indio_dev); + if (ret) + return dev_err_probe(dev, ret, "device register failed\n"); + + return 0; +} + +static int tmag5273_runtime_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct tmag5273_data *data = iio_priv(indio_dev); + int ret; + + ret = tmag5273_set_operating_mode(data, TMAG5273_OP_MODE_SLEEP); + if (ret) + dev_err(dev, "failed to power off device (%pe)\n", ERR_PTR(ret)); + + return ret; +} + +static int tmag5273_runtime_resume(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct tmag5273_data *data = iio_priv(indio_dev); + int ret; + + tmag5273_wake_up(data); + + ret = tmag5273_set_operating_mode(data, TMAG5273_OP_MODE_CONT); + if (ret) + dev_err(dev, "failed to power on device (%pe)\n", ERR_PTR(ret)); + + return ret; +} + +static DEFINE_RUNTIME_DEV_PM_OPS(tmag5273_pm_ops, + tmag5273_runtime_suspend, tmag5273_runtime_resume, + NULL); + +static const struct i2c_device_id tmag5273_id[] = { + { "tmag5273" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(i2c, tmag5273_id); + +static const struct of_device_id tmag5273_of_match[] = { + { .compatible = "ti,tmag5273" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, tmag5273_of_match); + +static struct i2c_driver tmag5273_driver = { + .driver = { + .name = "tmag5273", + .of_match_table = tmag5273_of_match, + .pm = pm_ptr(&tmag5273_pm_ops), + }, + .probe_new = tmag5273_probe, + .id_table = tmag5273_id, +}; +module_i2c_driver(tmag5273_driver); + +MODULE_DESCRIPTION("TI TMAG5273 Low-Power Linear 3D Hall-Effect Sensor driver"); +MODULE_AUTHOR("Gerald Loacker <gerald.loacker@wolfvision.net>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/pressure/ms5611.h b/drivers/iio/pressure/ms5611.h index 550b75b7186f..a78acd3fb18f 100644 --- a/drivers/iio/pressure/ms5611.h +++ b/drivers/iio/pressure/ms5611.h @@ -13,8 +13,6 @@ #include <linux/iio/iio.h> #include <linux/mutex.h> -struct regulator; - #define MS5611_RESET 0x1e #define MS5611_READ_ADC 0x00 #define MS5611_READ_PROM_WORD 0xA0 @@ -52,11 +50,9 @@ struct ms5611_state { int (*compensate_temp_and_pressure)(struct ms5611_state *st, s32 *temp, s32 *pressure); - struct regulator *vdd; }; int ms5611_probe(struct iio_dev *indio_dev, struct device *dev, const char *name, int type); -void ms5611_remove(struct iio_dev *indio_dev); #endif /* _MS5611_H */ diff --git a/drivers/iio/pressure/ms5611_core.c b/drivers/iio/pressure/ms5611_core.c index c564a1d6cafe..627497e61a63 100644 --- a/drivers/iio/pressure/ms5611_core.c +++ b/drivers/iio/pressure/ms5611_core.c @@ -380,40 +380,21 @@ static const struct iio_info ms5611_info = { static int ms5611_init(struct iio_dev *indio_dev) { int ret; - struct ms5611_state *st = iio_priv(indio_dev); /* Enable attached regulator if any. */ - st->vdd = devm_regulator_get(indio_dev->dev.parent, "vdd"); - if (IS_ERR(st->vdd)) - return PTR_ERR(st->vdd); - - ret = regulator_enable(st->vdd); - if (ret) { - dev_err(indio_dev->dev.parent, - "failed to enable Vdd supply: %d\n", ret); + ret = devm_regulator_get_enable(indio_dev->dev.parent, "vdd"); + if (ret) return ret; - } ret = ms5611_reset(indio_dev); if (ret < 0) - goto err_regulator_disable; + return ret; ret = ms5611_read_prom(indio_dev); if (ret < 0) - goto err_regulator_disable; + return ret; return 0; - -err_regulator_disable: - regulator_disable(st->vdd); - return ret; -} - -static void ms5611_fini(const struct iio_dev *indio_dev) -{ - const struct ms5611_state *st = iio_priv(indio_dev); - - regulator_disable(st->vdd); } int ms5611_probe(struct iio_dev *indio_dev, struct device *dev, @@ -453,37 +434,23 @@ int ms5611_probe(struct iio_dev *indio_dev, struct device *dev, if (ret < 0) return ret; - ret = iio_triggered_buffer_setup(indio_dev, NULL, + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, ms5611_trigger_handler, NULL); if (ret < 0) { dev_err(dev, "iio triggered buffer setup failed\n"); - goto err_fini; + return ret; } - ret = iio_device_register(indio_dev); + ret = devm_iio_device_register(dev, indio_dev); if (ret < 0) { dev_err(dev, "unable to register iio device\n"); - goto err_buffer_cleanup; + return ret; } return 0; - -err_buffer_cleanup: - iio_triggered_buffer_cleanup(indio_dev); -err_fini: - ms5611_fini(indio_dev); - return ret; } EXPORT_SYMBOL_NS(ms5611_probe, IIO_MS5611); -void ms5611_remove(struct iio_dev *indio_dev) -{ - iio_device_unregister(indio_dev); - iio_triggered_buffer_cleanup(indio_dev); - ms5611_fini(indio_dev); -} -EXPORT_SYMBOL_NS(ms5611_remove, IIO_MS5611); - MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>"); MODULE_DESCRIPTION("MS5611 core driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/pressure/ms5611_i2c.c b/drivers/iio/pressure/ms5611_i2c.c index caf882497656..e3c68a3ed76a 100644 --- a/drivers/iio/pressure/ms5611_i2c.c +++ b/drivers/iio/pressure/ms5611_i2c.c @@ -105,11 +105,6 @@ static int ms5611_i2c_probe(struct i2c_client *client) return ms5611_probe(indio_dev, &client->dev, id->name, id->driver_data); } -static void ms5611_i2c_remove(struct i2c_client *client) -{ - ms5611_remove(i2c_get_clientdata(client)); -} - static const struct of_device_id ms5611_i2c_matches[] = { { .compatible = "meas,ms5611" }, { .compatible = "meas,ms5607" }, @@ -131,7 +126,6 @@ static struct i2c_driver ms5611_driver = { }, .id_table = ms5611_id, .probe_new = ms5611_i2c_probe, - .remove = ms5611_i2c_remove, }; module_i2c_driver(ms5611_driver); diff --git a/drivers/iio/pressure/ms5611_spi.c b/drivers/iio/pressure/ms5611_spi.c index a0a7205c9c3a..cc9d1f68c53c 100644 --- a/drivers/iio/pressure/ms5611_spi.c +++ b/drivers/iio/pressure/ms5611_spi.c @@ -107,11 +107,6 @@ static int ms5611_spi_probe(struct spi_device *spi) spi_get_device_id(spi)->driver_data); } -static void ms5611_spi_remove(struct spi_device *spi) -{ - ms5611_remove(spi_get_drvdata(spi)); -} - static const struct of_device_id ms5611_spi_matches[] = { { .compatible = "meas,ms5611" }, { .compatible = "meas,ms5607" }, @@ -133,7 +128,6 @@ static struct spi_driver ms5611_driver = { }, .id_table = ms5611_id, .probe = ms5611_spi_probe, - .remove = ms5611_spi_remove, }; module_spi_driver(ms5611_driver); diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index 8e0afaaa3f75..81413cd3a3e7 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -381,6 +381,11 @@ s64 iio_get_time_ns(const struct iio_dev *indio_dev); #define INDIO_MAX_RAW_ELEMENTS 4 +struct iio_val_int_plus_micro { + int integer; + int micro; +}; + struct iio_trigger; /* forward declaration */ /** diff --git a/include/linux/platform_data/tsl2563.h b/include/linux/platform_data/tsl2563.h deleted file mode 100644 index 9cf9309c3f24..000000000000 --- a/include/linux/platform_data/tsl2563.h +++ /dev/null @@ -1,9 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __LINUX_TSL2563_H -#define __LINUX_TSL2563_H - -struct tsl2563_platform_data { - int cover_comp_gain; -}; - -#endif /* __LINUX_TSL2563_H */ diff --git a/tools/iio/iio_utils.c b/tools/iio/iio_utils.c index 8d35893b2fa8..6a00a6eecaef 100644 --- a/tools/iio/iio_utils.c +++ b/tools/iio/iio_utils.c @@ -264,6 +264,7 @@ int iioutils_get_param_float(float *output, const char *param_name, if (fscanf(sysfsfp, "%f", output) != 1) ret = errno ? -errno : -ENODATA; + fclose(sysfsfp); break; } error_free_filename: @@ -345,9 +346,9 @@ int build_channel_array(const char *device_dir, int buffer_idx, } sysfsfp = fopen(filename, "r"); + free(filename); if (!sysfsfp) { ret = -errno; - free(filename); goto error_close_dir; } @@ -357,7 +358,6 @@ int build_channel_array(const char *device_dir, int buffer_idx, if (fclose(sysfsfp)) perror("build_channel_array(): Failed to close file"); - free(filename); goto error_close_dir; } if (ret == 1) @@ -365,11 +365,9 @@ int build_channel_array(const char *device_dir, int buffer_idx, if (fclose(sysfsfp)) { ret = -errno; - free(filename); goto error_close_dir; } - free(filename); } *ci_array = malloc(sizeof(**ci_array) * (*counter)); @@ -395,9 +393,9 @@ int build_channel_array(const char *device_dir, int buffer_idx, } sysfsfp = fopen(filename, "r"); + free(filename); if (!sysfsfp) { ret = -errno; - free(filename); count--; goto error_cleanup_array; } @@ -405,20 +403,17 @@ int build_channel_array(const char *device_dir, int buffer_idx, errno = 0; if (fscanf(sysfsfp, "%i", ¤t_enabled) != 1) { ret = errno ? -errno : -ENODATA; - free(filename); count--; goto error_cleanup_array; } if (fclose(sysfsfp)) { ret = -errno; - free(filename); count--; goto error_cleanup_array; } if (!current_enabled) { - free(filename); count--; continue; } @@ -429,7 +424,6 @@ int build_channel_array(const char *device_dir, int buffer_idx, strlen(ent->d_name) - strlen("_en")); if (!current->name) { - free(filename); ret = -ENOMEM; count--; goto error_cleanup_array; @@ -439,7 +433,6 @@ int build_channel_array(const char *device_dir, int buffer_idx, ret = iioutils_break_up_name(current->name, ¤t->generic_name); if (ret) { - free(filename); free(current->name); count--; goto error_cleanup_array; @@ -450,17 +443,16 @@ int build_channel_array(const char *device_dir, int buffer_idx, scan_el_dir, current->name); if (ret < 0) { - free(filename); ret = -ENOMEM; goto error_cleanup_array; } sysfsfp = fopen(filename, "r"); + free(filename); if (!sysfsfp) { ret = -errno; - fprintf(stderr, "failed to open %s\n", - filename); - free(filename); + fprintf(stderr, "failed to open %s/%s_index\n", + scan_el_dir, current->name); goto error_cleanup_array; } @@ -470,17 +462,14 @@ int build_channel_array(const char *device_dir, int buffer_idx, if (fclose(sysfsfp)) perror("build_channel_array(): Failed to close file"); - free(filename); goto error_cleanup_array; } if (fclose(sysfsfp)) { ret = -errno; - free(filename); goto error_cleanup_array; } - free(filename); /* Find the scale */ ret = iioutils_get_param_float(¤t->scale, "scale", |