summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/iio/adc/adc.yaml11
-rw-r--r--Documentation/devicetree/bindings/iio/adc/adi,ad7173.yaml194
-rw-r--r--Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml5
-rw-r--r--Documentation/devicetree/bindings/iio/adc/mediatek,mt6359-auxadc.yaml33
-rw-r--r--Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.yaml4
-rw-r--r--Documentation/devicetree/bindings/iio/adc/ti,ads1119.yaml155
-rw-r--r--Documentation/devicetree/bindings/iio/frequency/adi,adf4350.yaml6
-rw-r--r--Documentation/devicetree/bindings/iio/st,st-sensors.yaml1
-rw-r--r--Documentation/driver-api/dmaengine/client.rst9
-rw-r--r--Documentation/driver-api/dmaengine/provider.rst10
-rw-r--r--Documentation/driver-api/driver-model/devres.rst3
-rw-r--r--Documentation/iio/iio_dmabuf_api.rst54
-rw-r--r--Documentation/iio/index.rst1
-rw-r--r--MAINTAINERS17
-rw-r--r--drivers/dma/dma-axi-dmac.c40
-rw-r--r--drivers/hwmon/iio_hwmon.c45
-rw-r--r--drivers/iio/Kconfig1
-rw-r--r--drivers/iio/accel/fxls8962af-core.c18
-rw-r--r--drivers/iio/accel/kxsd9.c5
-rw-r--r--drivers/iio/accel/msa311.c8
-rw-r--r--drivers/iio/accel/st_accel.h1
-rw-r--r--drivers/iio/accel/st_accel_core.c81
-rw-r--r--drivers/iio/accel/st_accel_i2c.c5
-rw-r--r--drivers/iio/accel/st_accel_spi.c5
-rw-r--r--drivers/iio/adc/Kconfig24
-rw-r--r--drivers/iio/adc/Makefile2
-rw-r--r--drivers/iio/adc/ad4130.c4
-rw-r--r--drivers/iio/adc/ad7124.c14
-rw-r--r--drivers/iio/adc/ad7173.c676
-rw-r--r--drivers/iio/adc/ad7192.c134
-rw-r--r--drivers/iio/adc/ad7266.c33
-rw-r--r--drivers/iio/adc/ad7292.c36
-rw-r--r--drivers/iio/adc/ad7793.c24
-rw-r--r--drivers/iio/adc/ad7944.c80
-rw-r--r--drivers/iio/adc/ad_sigma_delta.c1
-rw-r--r--drivers/iio/adc/adi-axi-adc.c9
-rw-r--r--drivers/iio/adc/aspeed_adc.c30
-rw-r--r--drivers/iio/adc/axp20x_adc.c5
-rw-r--r--drivers/iio/adc/axp288_adc.c4
-rw-r--r--drivers/iio/adc/bcm_iproc_adc.c8
-rw-r--r--drivers/iio/adc/berlin2-adc.c24
-rw-r--r--drivers/iio/adc/cpcap-adc.c46
-rw-r--r--drivers/iio/adc/fsl-imx25-gcq.c16
-rw-r--r--drivers/iio/adc/hx711.c78
-rw-r--r--drivers/iio/adc/ina2xx-adc.c3
-rw-r--r--drivers/iio/adc/intel_mrfld_adc.c4
-rw-r--r--drivers/iio/adc/ltc2309.c45
-rw-r--r--drivers/iio/adc/max1363.c28
-rw-r--r--drivers/iio/adc/meson_saradc.c101
-rw-r--r--drivers/iio/adc/mp2629_adc.c19
-rw-r--r--drivers/iio/adc/mt6359-auxadc.c606
-rw-r--r--drivers/iio/adc/qcom-spmi-rradc.c50
-rw-r--r--drivers/iio/adc/rn5t618-adc.c5
-rw-r--r--drivers/iio/adc/sc27xx_adc.c41
-rw-r--r--drivers/iio/adc/stm32-dfsdm-adc.c29
-rw-r--r--drivers/iio/adc/ti-adc108s102.c28
-rw-r--r--drivers/iio/adc/ti-ads1119.c825
-rw-r--r--drivers/iio/adc/ti-ads8688.c59
-rw-r--r--drivers/iio/adc/xilinx-ams.c107
-rw-r--r--drivers/iio/buffer/industrialio-buffer-dma.c178
-rw-r--r--drivers/iio/buffer/industrialio-buffer-dmaengine.c62
-rw-r--r--drivers/iio/common/scmi_sensors/scmi_iio.c45
-rw-r--r--drivers/iio/common/st_sensors/st_sensors_core.c3
-rw-r--r--drivers/iio/dac/ad3552r.c28
-rw-r--r--drivers/iio/dac/adi-axi-dac.c9
-rw-r--r--drivers/iio/dac/ltc2688.c5
-rw-r--r--drivers/iio/dac/stm32-dac-core.c5
-rw-r--r--drivers/iio/frequency/adf4350.c124
-rw-r--r--drivers/iio/gyro/adis16136.c26
-rw-r--r--drivers/iio/gyro/adis16260.c19
-rw-r--r--drivers/iio/gyro/bmg160_core.c4
-rw-r--r--drivers/iio/gyro/mpu3050-core.c35
-rw-r--r--drivers/iio/health/afe4403.c9
-rw-r--r--drivers/iio/health/afe4404.c9
-rw-r--r--drivers/iio/health/max30100.c5
-rw-r--r--drivers/iio/health/max30102.c5
-rw-r--r--drivers/iio/iio_core.h4
-rw-r--r--drivers/iio/imu/adis.c11
-rw-r--r--drivers/iio/imu/adis16400.c72
-rw-r--r--drivers/iio/imu/adis16475.c44
-rw-r--r--drivers/iio/imu/adis16480.c63
-rw-r--r--drivers/iio/imu/adis_buffer.c41
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c14
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_core.c9
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c4
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c4
-rw-r--r--drivers/iio/industrialio-backend.c8
-rw-r--r--drivers/iio/industrialio-buffer.c459
-rw-r--r--drivers/iio/industrialio-core.c23
-rw-r--r--drivers/iio/inkern.c6
-rw-r--r--drivers/iio/light/adux1020.c13
-rw-r--r--drivers/iio/light/iqs621-als.c4
-rw-r--r--drivers/iio/light/isl29018.c6
-rw-r--r--drivers/iio/light/st_uvis25_core.c4
-rw-r--r--drivers/iio/light/veml6030.c4
-rw-r--r--drivers/iio/magnetometer/ak8974.c10
-rw-r--r--drivers/iio/magnetometer/mmc35240.c8
-rw-r--r--drivers/iio/pressure/bmp280-core.c4
-rw-r--r--drivers/iio/proximity/sx9324.c5
-rw-r--r--drivers/iio/proximity/sx9360.c5
-rw-r--r--drivers/iio/proximity/sx9500.c12
-rw-r--r--drivers/iio/proximity/sx_common.c9
-rw-r--r--drivers/iio/temperature/ltc2983.c262
-rw-r--r--drivers/iio/temperature/mlx90632.c4
-rw-r--r--drivers/iio/trigger/stm32-timer-trigger.c34
-rw-r--r--drivers/spi/spi.c28
-rw-r--r--include/dt-bindings/iio/adc/mediatek,mt6357-auxadc.h21
-rw-r--r--include/dt-bindings/iio/adc/mediatek,mt6358-auxadc.h22
-rw-r--r--include/dt-bindings/iio/adc/mediatek,mt6359-auxadc.h22
-rw-r--r--include/linux/dev_printk.h8
-rw-r--r--include/linux/dmaengine.h33
-rw-r--r--include/linux/iio/adc/ad_sigma_delta.h14
-rw-r--r--include/linux/iio/buffer-dma.h31
-rw-r--r--include/linux/iio/buffer_impl.h33
-rw-r--r--include/linux/iio/consumer.h10
-rw-r--r--include/linux/iio/imu/adis.h66
-rw-r--r--include/linux/math.h2
-rw-r--r--include/linux/spi/spi.h2
-rw-r--r--include/uapi/linux/iio/buffer.h22
119 files changed, 4447 insertions, 1494 deletions
diff --git a/Documentation/devicetree/bindings/iio/adc/adc.yaml b/Documentation/devicetree/bindings/iio/adc/adc.yaml
index 0a77592f7388..8e7835cf36fd 100644
--- a/Documentation/devicetree/bindings/iio/adc/adc.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/adc.yaml
@@ -46,6 +46,17 @@ properties:
differential channels). If this and diff-channels are not present reg
shall be used instead.
+ common-mode-channel:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ Some ADCs have differential input pins that can be used to measure
+ single-ended or pseudo-differential inputs. This property can be used
+ in addition to single-channel to signal software that this channel is
+ not differential but still specify two inputs.
+
+ The input pair is specified by setting single-channel to the positive
+ input pin and common-mode-channel to the negative pin.
+
settling-time-us:
description:
Time between enabling the channel and first stable readings.
diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7173.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7173.yaml
index ea6cfcd0aff4..17c5d39cc2c1 100644
--- a/Documentation/devicetree/bindings/iio/adc/adi,ad7173.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7173.yaml
@@ -19,7 +19,18 @@ description: |
primarily for measurement of signals close to DC but also delivers
outstanding performance with input bandwidths out to ~10kHz.
+ Analog Devices AD411x ADC's:
+ The AD411X family encompasses a series of low power, low noise, 24-bit,
+ sigma-delta analog-to-digital converters that offer a versatile range of
+ specifications. They integrate an analog front end suitable for processing
+ fully differential/single-ended and bipolar voltage inputs.
+
Datasheets for supported chips:
+ https://www.analog.com/media/en/technical-documentation/data-sheets/AD4111.pdf
+ https://www.analog.com/media/en/technical-documentation/data-sheets/AD4112.pdf
+ https://www.analog.com/media/en/technical-documentation/data-sheets/AD4114.pdf
+ https://www.analog.com/media/en/technical-documentation/data-sheets/AD4115.pdf
+ https://www.analog.com/media/en/technical-documentation/data-sheets/AD4116.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/AD7172-2.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/AD7172-4.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/AD7173-8.pdf
@@ -31,6 +42,11 @@ description: |
properties:
compatible:
enum:
+ - adi,ad4111
+ - adi,ad4112
+ - adi,ad4114
+ - adi,ad4115
+ - adi,ad4116
- adi,ad7172-2
- adi,ad7172-4
- adi,ad7173-8
@@ -129,10 +145,56 @@ patternProperties:
maximum: 15
diff-channels:
+ description: |
+ This property is used for defining the inputs of a differential
+ voltage channel. The first value is the positive input and the second
+ value is the negative input of the channel.
+
+ Family AD411x supports a dedicated VINCOM voltage input.
+ To select it set the second channel to 16.
+ (VIN2, VINCOM) -> diff-channels = <2 16>
+
+ There are special values that can be selected besides the voltage
+ analog inputs:
+ 21: REF+
+ 22: REF−
+
+ Supported only by AD7172-2, AD7172-4, AD7175-2, AD7175-8, AD7177-2,
+ must be paired together and can be used to monitor the power supply
+ of the ADC:
+ 19: ((AVDD1 − AVSS)/5)+
+ 20: ((AVDD1 − AVSS)/5)−
+
items:
minimum: 0
maximum: 31
+ single-channel:
+ description: |
+ This property is used for defining a current channel or the positive
+ input of a voltage channel (single-ended or pseudo-differential).
+
+ Models AD4111 and AD4112 support current channels.
+ Example: (IIN2+, IIN2−) -> single-channel = <2>
+ To correctly configure a current channel set the "adi,current-channel"
+ property to true.
+
+ To configure a single-ended/pseudo-differential channel set the
+ "common-mode-channel" property to the desired negative voltage input.
+
+ When used as a voltage channel, special inputs are valid as well.
+ minimum: 0
+ maximum: 31
+
+ common-mode-channel:
+ description:
+ This property is used for defining the negative input of a
+ single-ended or pseudo-differential voltage channel.
+
+ Special inputs are valid as well.
+ minimum: 0
+ maximum: 31
+
adi,reference-select:
description: |
Select the reference source to use when converting on
@@ -154,9 +216,31 @@ patternProperties:
- avdd
default: refout-avss
+ adi,current-channel:
+ $ref: /schemas/types.yaml#/definitions/flag
+ description: |
+ Signal that the selected inputs are current channels.
+ Only available on AD4111 and AD4112.
+
required:
- reg
- - diff-channels
+
+ allOf:
+ - oneOf:
+ - required: [single-channel]
+ properties:
+ diff-channels: false
+ - required: [diff-channels]
+ properties:
+ single-channel: false
+ adi,current-channel: false
+ common-mode-channel: false
+
+ - if:
+ required: [common-mode-channel]
+ then:
+ properties:
+ adi,current-channel: false
required:
- compatible
@@ -166,7 +250,6 @@ allOf:
- $ref: /schemas/spi/spi-peripheral-props.yaml#
# Only ad7172-4, ad7173-8 and ad7175-8 support vref2
- # Other models have [0-3] channel registers
- if:
properties:
compatible:
@@ -187,6 +270,37 @@ allOf:
- vref
- refout-avss
- avdd
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - adi,ad4114
+ - adi,ad4115
+ - adi,ad4116
+ - adi,ad7173-8
+ - adi,ad7175-8
+ then:
+ patternProperties:
+ "^channel@[0-9a-f]$":
+ properties:
+ reg:
+ maximum: 15
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - adi,ad7172-2
+ - adi,ad7175-2
+ - adi,ad7176-2
+ - adi,ad7177-2
+ then:
+ patternProperties:
+ "^channel@[0-9a-f]$":
+ properties:
reg:
maximum: 3
@@ -211,6 +325,34 @@ allOf:
- adi,reference-select
- if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - adi,ad4111
+ - adi,ad4112
+ - adi,ad4114
+ - adi,ad4115
+ - adi,ad4116
+ then:
+ properties:
+ avdd2-supply: false
+
+ - if:
+ properties:
+ compatible:
+ not:
+ contains:
+ enum:
+ - adi,ad4111
+ - adi,ad4112
+ then:
+ patternProperties:
+ "^channel@[0-9a-f]$":
+ properties:
+ adi,current-channel: false
+
+ - if:
anyOf:
- required: [clock-names]
- required: [clocks]
@@ -221,6 +363,7 @@ allOf:
unevaluatedProperties: false
examples:
+ # Example AD7173-8 with external reference connected to REF+/REF-:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
@@ -277,3 +420,50 @@ examples:
};
};
};
+
+ # Example AD4111 with current channel and single-ended channel:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ adc@0 {
+ compatible = "adi,ad4111";
+ reg = <0>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
+ interrupt-names = "rdy";
+ interrupt-parent = <&gpio>;
+ spi-max-frequency = <5000000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ #clock-cells = <0>;
+
+ channel@0 {
+ reg = <0>;
+ bipolar;
+ diff-channels = <4 5>;
+ };
+
+ // Single ended channel VIN2/VINCOM
+ channel@1 {
+ reg = <1>;
+ bipolar;
+ single-channel = <2>;
+ common-mode-channel = <16>;
+ };
+
+ // Current channel IN2+/IN2-
+ channel@2 {
+ reg = <2>;
+ single-channel = <2>;
+ adi,current-channel;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml
index 7fa46df1f4fb..00fdaed11cbd 100644
--- a/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml
@@ -11,6 +11,7 @@ maintainers:
description: |
Analog Devices AD7606 Simultaneous Sampling ADC
+ https://www.analog.com/media/en/technical-documentation/data-sheets/AD7605-4.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7606_7606-6_7606-4.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/AD7606B.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/AD7616.pdf
@@ -19,9 +20,9 @@ properties:
compatible:
enum:
- adi,ad7605-4
- - adi,ad7606-8
- - adi,ad7606-6
- adi,ad7606-4
+ - adi,ad7606-6
+ - adi,ad7606-8 # Referred to as AD7606 (without -8) in the datasheet
- adi,ad7606b
- adi,ad7616
diff --git a/Documentation/devicetree/bindings/iio/adc/mediatek,mt6359-auxadc.yaml b/Documentation/devicetree/bindings/iio/adc/mediatek,mt6359-auxadc.yaml
new file mode 100644
index 000000000000..6497c416094d
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/mediatek,mt6359-auxadc.yaml
@@ -0,0 +1,33 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/adc/mediatek,mt6359-auxadc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek MT6350 series PMIC AUXADC
+
+maintainers:
+ - AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+
+description:
+ The Auxiliary Analog/Digital Converter (AUXADC) is an ADC found
+ in some MediaTek PMICs, performing various PMIC related measurements
+ such as battery and PMIC internal voltage regulators temperatures,
+ accessory detection resistance (usually, for a 3.5mm audio jack)
+ other than voltages for various PMIC internal components.
+
+properties:
+ compatible:
+ enum:
+ - mediatek,mt6357-auxadc
+ - mediatek,mt6358-auxadc
+ - mediatek,mt6359-auxadc
+
+ "#io-channel-cells":
+ const: 1
+
+required:
+ - compatible
+ - "#io-channel-cells"
+
+additionalProperties: false
diff --git a/Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.yaml b/Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.yaml
index c1b1324fa132..2722edab1d9a 100644
--- a/Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.yaml
@@ -246,6 +246,10 @@ patternProperties:
From common IIO binding. Used to pipe external sigma delta
modulator or internal ADC output to DFSDM channel.
+ port:
+ $ref: /schemas/sound/audio-graph-port.yaml#
+ unevaluatedProperties: false
+
required:
- compatible
- "#sound-dai-cells"
diff --git a/Documentation/devicetree/bindings/iio/adc/ti,ads1119.yaml b/Documentation/devicetree/bindings/iio/adc/ti,ads1119.yaml
new file mode 100644
index 000000000000..ba6850ab1f90
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/ti,ads1119.yaml
@@ -0,0 +1,155 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/adc/ti,ads1119.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Texas Instruments ADS1119 ADC
+
+maintainers:
+ - João Paulo Gonçalves <jpaulo.silvagoncalves@gmail.com>
+
+description:
+ The TI ADS1119 is a precision 16-bit ADC over I2C that offers single-ended and
+ differential measurements using a multiplexed input. It features a programmable
+ gain, a programmable sample rate, an internal oscillator and voltage reference,
+ and a 50/60Hz rejection filter.
+
+properties:
+ compatible:
+ const: ti,ads1119
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ reset-gpios:
+ maxItems: 1
+
+ avdd-supply: true
+ dvdd-supply: true
+
+ vref-supply:
+ description:
+ ADC external reference voltage (VREF).
+
+ "#address-cells":
+ const: 1
+
+ "#size-cells":
+ const: 0
+
+ "#io-channel-cells":
+ const: 1
+
+required:
+ - compatible
+ - reg
+ - "#address-cells"
+ - "#size-cells"
+ - avdd-supply
+ - dvdd-supply
+
+patternProperties:
+ "^channel@([0-6])$":
+ $ref: adc.yaml
+ type: object
+ properties:
+ reg:
+ minimum: 0
+ maximum: 6
+
+ diff-channels:
+ description:
+ Differential input channels AIN0-AIN1, AIN2-AIN3 and AIN1-AIN2.
+ oneOf:
+ - items:
+ - const: 0
+ - const: 1
+ - items:
+ - const: 2
+ - const: 3
+ - items:
+ - const: 1
+ - const: 2
+
+ single-channel:
+ description:
+ Single-ended input channels AIN0, AIN1, AIN2 and AIN3.
+ minimum: 0
+ maximum: 3
+
+ oneOf:
+ - required:
+ - diff-channels
+ - required:
+ - single-channel
+
+ required:
+ - reg
+
+ unevaluatedProperties: false
+
+additionalProperties: false
+
+examples:
+ - |
+
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ adc@40 {
+ compatible = "ti,ads1119";
+ reg = <0x40>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
+ reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
+ avdd-supply = <&reg_avdd_ads1119>;
+ dvdd-supply = <&reg_dvdd_ads1119>;
+ vref-supply = <&reg_vref_ads1119>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #io-channel-cells = <1>;
+
+ channel@0 {
+ reg = <0>;
+ single-channel = <0>;
+ };
+
+ channel@1 {
+ reg = <1>;
+ diff-channels = <0 1>;
+ };
+
+ channel@2 {
+ reg = <2>;
+ single-channel = <3>;
+ };
+
+ channel@3 {
+ reg = <3>;
+ single-channel = <1>;
+ };
+
+ channel@4 {
+ reg = <4>;
+ single-channel = <2>;
+ };
+
+ channel@5 {
+ reg = <5>;
+ diff-channels = <1 2>;
+ };
+
+ channel@6 {
+ reg = <6>;
+ diff-channels = <2 3>;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/iio/frequency/adi,adf4350.yaml b/Documentation/devicetree/bindings/iio/frequency/adi,adf4350.yaml
index 43cbf27114c7..d1d1311332f8 100644
--- a/Documentation/devicetree/bindings/iio/frequency/adi,adf4350.yaml
+++ b/Documentation/devicetree/bindings/iio/frequency/adi,adf4350.yaml
@@ -28,6 +28,12 @@ properties:
clock-names:
const: clkin
+ '#clock-cells':
+ const: 0
+
+ clock-output-names:
+ maxItems: 1
+
gpios:
maxItems: 1
description: Lock detect GPIO.
diff --git a/Documentation/devicetree/bindings/iio/st,st-sensors.yaml b/Documentation/devicetree/bindings/iio/st,st-sensors.yaml
index fff7e3d83a02..71c1ee33a393 100644
--- a/Documentation/devicetree/bindings/iio/st,st-sensors.yaml
+++ b/Documentation/devicetree/bindings/iio/st,st-sensors.yaml
@@ -26,6 +26,7 @@ properties:
- st,lis2dw12
- st,lis2hh12
- st,lis2dh12-accel
+ - st,lis2ds12
- st,lis302dl
- st,lis331dl-accel
- st,lis331dlh-accel
diff --git a/Documentation/driver-api/dmaengine/client.rst b/Documentation/driver-api/dmaengine/client.rst
index ecf139f73da4..d491e385d61a 100644
--- a/Documentation/driver-api/dmaengine/client.rst
+++ b/Documentation/driver-api/dmaengine/client.rst
@@ -80,6 +80,10 @@ The details of these operations are:
- slave_sg: DMA a list of scatter gather buffers from/to a peripheral
+ - peripheral_dma_vec: DMA an array of scatter gather buffers from/to a
+ peripheral. Similar to slave_sg, but uses an array of dma_vec
+ structures instead of a scatterlist.
+
- dma_cyclic: Perform a cyclic DMA operation from/to a peripheral till the
operation is explicitly stopped.
@@ -102,6 +106,11 @@ The details of these operations are:
unsigned int sg_len, enum dma_data_direction direction,
unsigned long flags);
+ struct dma_async_tx_descriptor *dmaengine_prep_peripheral_dma_vec(
+ struct dma_chan *chan, const struct dma_vec *vecs,
+ size_t nents, enum dma_data_direction direction,
+ unsigned long flags);
+
struct dma_async_tx_descriptor *dmaengine_prep_dma_cyclic(
struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
size_t period_len, enum dma_data_direction direction);
diff --git a/Documentation/driver-api/dmaengine/provider.rst b/Documentation/driver-api/dmaengine/provider.rst
index ceac2a300e32..3085f8b460fa 100644
--- a/Documentation/driver-api/dmaengine/provider.rst
+++ b/Documentation/driver-api/dmaengine/provider.rst
@@ -433,6 +433,12 @@ supported.
- residue: Provides the residue bytes of the transfer for those that
support residue.
+- ``device_prep_peripheral_dma_vec``
+
+ - Similar to ``device_prep_slave_sg``, but it takes a pointer to a
+ array of ``dma_vec`` structures, which (in the long run) will replace
+ scatterlists.
+
- ``device_issue_pending``
- Takes the first transaction descriptor in the pending queue,
@@ -544,6 +550,10 @@ dma_cookie_t
- Not really relevant any more since the introduction of ``virt-dma``
that abstracts it away.
+dma_vec
+
+- A small structure that contains a DMA address and length.
+
DMA_CTRL_ACK
- If clear, the descriptor cannot be reused by provider until the
diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst
index 18caebad7376..ac9ee7441887 100644
--- a/Documentation/driver-api/driver-model/devres.rst
+++ b/Documentation/driver-api/driver-model/devres.rst
@@ -464,7 +464,10 @@ SLAVE DMA ENGINE
SPI
devm_spi_alloc_master()
devm_spi_alloc_slave()
+ devm_spi_optimize_message()
devm_spi_register_controller()
+ devm_spi_register_host()
+ devm_spi_register_target()
WATCHDOG
devm_watchdog_register_device()
diff --git a/Documentation/iio/iio_dmabuf_api.rst b/Documentation/iio/iio_dmabuf_api.rst
new file mode 100644
index 000000000000..2836cadbd495
--- /dev/null
+++ b/Documentation/iio/iio_dmabuf_api.rst
@@ -0,0 +1,54 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+===================================
+High-speed DMABUF interface for IIO
+===================================
+
+1. Overview
+===========
+
+The Industrial I/O subsystem supports access to buffers through a
+file-based interface, with read() and write() access calls through the
+IIO device's dev node.
+
+It additionally supports a DMABUF based interface, where the userspace
+can attach DMABUF objects (externally created) to an IIO buffer, and
+subsequently use them for data transfers.
+
+A userspace application can then use this interface to share DMABUF
+objects between several interfaces, allowing it to transfer data in a
+zero-copy fashion, for instance between IIO and the USB stack.
+
+The userspace application can also memory-map the DMABUF objects, and
+access the sample data directly. The advantage of doing this vs. the
+read() interface is that it avoids an extra copy of the data between the
+kernel and userspace. This is particularly useful for high-speed devices
+which produce several megabytes or even gigabytes of data per second.
+It does however increase the userspace-kernelspace synchronization
+overhead, as the DMA_BUF_SYNC_START and DMA_BUF_SYNC_END IOCTLs have to
+be used for data integrity.
+
+2. User API
+===========
+
+As part of this interface, three new IOCTLs have been added. These three
+IOCTLs have to be performed on the IIO buffer's file descriptor, which
+can be obtained using the IIO_BUFFER_GET_FD_IOCTL() ioctl.
+
+ ``IIO_BUFFER_DMABUF_ATTACH_IOCTL(int fd)``
+ Attach the DMABUF object, identified by its file descriptor, to the
+ IIO buffer. Returns zero on success, and a negative errno value on
+ error.
+
+ ``IIO_BUFFER_DMABUF_DETACH_IOCTL(int fd)``
+ Detach the given DMABUF object, identified by its file descriptor,
+ from the IIO buffer. Returns zero on success, and a negative errno
+ value on error.
+
+ Note that closing the IIO buffer's file descriptor will
+ automatically detach all previously attached DMABUF objects.
+
+ ``IIO_BUFFER_DMABUF_ENQUEUE_IOCTL(struct iio_dmabuf *iio_dmabuf)``
+ Enqueue a previously attached DMABUF object to the buffer queue.
+ Enqueued DMABUFs will be read from (if output buffer) or written to
+ (if input buffer) as long as the buffer is enabled.
diff --git a/Documentation/iio/index.rst b/Documentation/iio/index.rst
index 4c13bfa2865c..9cb4c50cb20d 100644
--- a/Documentation/iio/index.rst
+++ b/Documentation/iio/index.rst
@@ -9,6 +9,7 @@ Industrial I/O
iio_configfs
iio_devbuf
+ iio_dmabuf_api
iio_tools
Industrial I/O Kernel Drivers
diff --git a/MAINTAINERS b/MAINTAINERS
index 9102fe0bc393..aae88b7a6c32 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1217,7 +1217,7 @@ F: Documentation/devicetree/bindings/iio/adc/adi,ad7091r*
F: drivers/iio/adc/ad7091r*
ANALOG DEVICES INC AD7192 DRIVER
-M: Alexandru Tachici <alexandru.tachici@analog.com>
+M: Alisa-Dariana Roman <alisa.roman@analog.com>
L: linux-iio@vger.kernel.org
S: Supported
W: https://ez.analog.com/linux-software-drivers
@@ -3531,6 +3531,13 @@ F: include/linux/cfag12864b.h
F: include/uapi/linux/map_to_14segment.h
F: include/uapi/linux/map_to_7segment.h
+AVAGO APDS9306 AMBIENT LIGHT SENSOR DRIVER
+M: Subhajit Ghosh <subhajit.ghosh@tweaklogic.com>
+L: linux-iio@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/iio/light/avago,apds9300.yaml
+F: drivers/iio/light/apds9306.c
+
AVIA HX711 ANALOG DIGITAL CONVERTER IIO DRIVER
M: Andreas Klinger <ak@it-klinger.de>
L: linux-iio@vger.kernel.org
@@ -22397,6 +22404,14 @@ M: Robert Richter <rric@kernel.org>
S: Odd Fixes
F: drivers/gpio/gpio-thunderx.c
+TI ADS1119 ADC DRIVER
+M: Francesco Dolcini <francesco@dolcini.it>
+M: João Paulo Gonçalves <jpaulo.silvagoncalves@gmail.com>
+L: linux-iio@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/iio/adc/ti,ads1119.yaml
+F: drivers/iio/adc/ti-ads1119.c
+
TI ADS7924 ADC DRIVER
M: Hugo Villeneuve <hvilleneuve@dimonoff.com>
L: linux-iio@vger.kernel.org
diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c
index bdb752f11869..36943b0c6d60 100644
--- a/drivers/dma/dma-axi-dmac.c
+++ b/drivers/dma/dma-axi-dmac.c
@@ -620,6 +620,45 @@ static struct axi_dmac_sg *axi_dmac_fill_linear_sg(struct axi_dmac_chan *chan,
return sg;
}
+static struct dma_async_tx_descriptor *
+axi_dmac_prep_peripheral_dma_vec(struct dma_chan *c, const struct dma_vec *vecs,
+ size_t nb, enum dma_transfer_direction direction,
+ unsigned long flags)
+{
+ struct axi_dmac_chan *chan = to_axi_dmac_chan(c);
+ struct axi_dmac_desc *desc;
+ unsigned int num_sgs = 0;
+ struct axi_dmac_sg *dsg;
+ size_t i;
+
+ if (direction != chan->direction)
+ return NULL;
+
+ for (i = 0; i < nb; i++)
+ num_sgs += DIV_ROUND_UP(vecs[i].len, chan->max_length);
+
+ desc = axi_dmac_alloc_desc(chan, num_sgs);
+ if (!desc)
+ return NULL;
+
+ dsg = desc->sg;
+
+ for (i = 0; i < nb; i++) {
+ if (!axi_dmac_check_addr(chan, vecs[i].addr) ||
+ !axi_dmac_check_len(chan, vecs[i].len)) {
+ kfree(desc);
+ return NULL;
+ }
+
+ dsg = axi_dmac_fill_linear_sg(chan, direction, vecs[i].addr, 1,
+ vecs[i].len, dsg);
+ }
+
+ desc->cyclic = false;
+
+ return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags);
+}
+
static struct dma_async_tx_descriptor *axi_dmac_prep_slave_sg(
struct dma_chan *c, struct scatterlist *sgl,
unsigned int sg_len, enum dma_transfer_direction direction,
@@ -1061,6 +1100,7 @@ static int axi_dmac_probe(struct platform_device *pdev)
dma_dev->device_tx_status = dma_cookie_status;
dma_dev->device_issue_pending = axi_dmac_issue_pending;
dma_dev->device_prep_slave_sg = axi_dmac_prep_slave_sg;
+ dma_dev->device_prep_peripheral_dma_vec = axi_dmac_prep_peripheral_dma_vec;
dma_dev->device_prep_dma_cyclic = axi_dmac_prep_dma_cyclic;
dma_dev->device_prep_interleaved_dma = axi_dmac_prep_interleaved;
dma_dev->device_terminate_all = axi_dmac_terminate_all;
diff --git a/drivers/hwmon/iio_hwmon.c b/drivers/hwmon/iio_hwmon.c
index 4c8a80847891..5722cb9d81f9 100644
--- a/drivers/hwmon/iio_hwmon.c
+++ b/drivers/hwmon/iio_hwmon.c
@@ -33,6 +33,17 @@ struct iio_hwmon_state {
struct attribute **attrs;
};
+static ssize_t iio_hwmon_read_label(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+ struct iio_hwmon_state *state = dev_get_drvdata(dev);
+ struct iio_channel *chan = &state->channels[sattr->index];
+
+ return iio_read_channel_label(chan, buf);
+}
+
/*
* Assumes that IIO and hwmon operate in the same base units.
* This is supposed to be true, but needs verification for
@@ -68,12 +79,13 @@ static int iio_hwmon_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct iio_hwmon_state *st;
struct sensor_device_attribute *a;
- int ret, i;
+ int ret, i, attr = 0;
int in_i = 1, temp_i = 1, curr_i = 1, humidity_i = 1, power_i = 1;
enum iio_chan_type type;
struct iio_channel *channels;
struct device *hwmon_dev;
char *sname;
+ void *buf;
channels = devm_iio_channel_get_all(dev);
if (IS_ERR(channels)) {
@@ -85,17 +97,18 @@ static int iio_hwmon_probe(struct platform_device *pdev)
}
st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
- if (st == NULL)
+ buf = (void *)devm_get_free_pages(dev, GFP_KERNEL, 0);
+ if (!st || !buf)
return -ENOMEM;
st->channels = channels;
- /* count how many attributes we have */
+ /* count how many channels we have */
while (st->channels[st->num_channels].indio_dev)
st->num_channels++;
st->attrs = devm_kcalloc(dev,
- st->num_channels + 1, sizeof(*st->attrs),
+ 2 * st->num_channels + 1, sizeof(*st->attrs),
GFP_KERNEL);
if (st->attrs == NULL)
return -ENOMEM;
@@ -147,9 +160,31 @@ static int iio_hwmon_probe(struct platform_device *pdev)
a->dev_attr.show = iio_hwmon_read_val;
a->dev_attr.attr.mode = 0444;
a->index = i;
- st->attrs[i] = &a->dev_attr.attr;
+ st->attrs[attr++] = &a->dev_attr.attr;
+
+ /* Let's see if we have a label... */
+ if (iio_read_channel_label(&st->channels[i], buf) < 0)
+ continue;
+
+ a = devm_kzalloc(dev, sizeof(*a), GFP_KERNEL);
+ if (a == NULL)
+ return -ENOMEM;
+
+ sysfs_attr_init(&a->dev_attr.attr);
+ a->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL,
+ "%s%d_label",
+ prefix, n);
+ if (!a->dev_attr.attr.name)
+ return -ENOMEM;
+
+ a->dev_attr.show = iio_hwmon_read_label;
+ a->dev_attr.attr.mode = 0444;
+ a->index = i;
+ st->attrs[attr++] = &a->dev_attr.attr;
}
+ devm_free_pages(dev, (unsigned long)buf);
+
st->attr_group.attrs = st->attrs;
st->groups[0] = &st->attr_group;
diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
index 9c351ffc7bed..661127aed2f9 100644
--- a/drivers/iio/Kconfig
+++ b/drivers/iio/Kconfig
@@ -14,6 +14,7 @@ if IIO
config IIO_BUFFER
bool "Enable buffer support within IIO"
+ select DMA_SHARED_BUFFER
help
Provide core support for various buffer based data
acquisition methods.
diff --git a/drivers/iio/accel/fxls8962af-core.c b/drivers/iio/accel/fxls8962af-core.c
index 4fbc01bda62e..d25e31613413 100644
--- a/drivers/iio/accel/fxls8962af-core.c
+++ b/drivers/iio/accel/fxls8962af-core.c
@@ -228,8 +228,8 @@ static int fxls8962af_power_off(struct fxls8962af_data *data)
static int fxls8962af_standby(struct fxls8962af_data *data)
{
- return regmap_update_bits(data->regmap, FXLS8962AF_SENS_CONFIG1,
- FXLS8962AF_SENS_CONFIG1_ACTIVE, 0);
+ return regmap_clear_bits(data->regmap, FXLS8962AF_SENS_CONFIG1,
+ FXLS8962AF_SENS_CONFIG1_ACTIVE);
}
static int fxls8962af_active(struct fxls8962af_data *data)
@@ -785,9 +785,8 @@ static int fxls8962af_reset(struct fxls8962af_data *data)
unsigned int reg;
int ret;
- ret = regmap_update_bits(data->regmap, FXLS8962AF_SENS_CONFIG1,
- FXLS8962AF_SENS_CONFIG1_RST,
- FXLS8962AF_SENS_CONFIG1_RST);
+ ret = regmap_set_bits(data->regmap, FXLS8962AF_SENS_CONFIG1,
+ FXLS8962AF_SENS_CONFIG1_RST);
if (ret)
return ret;
@@ -830,9 +829,8 @@ static int fxls8962af_buffer_postenable(struct iio_dev *indio_dev)
fxls8962af_standby(data);
/* Enable buffer interrupt */
- ret = regmap_update_bits(data->regmap, FXLS8962AF_INT_EN,
- FXLS8962AF_INT_EN_BUF_EN,
- FXLS8962AF_INT_EN_BUF_EN);
+ ret = regmap_set_bits(data->regmap, FXLS8962AF_INT_EN,
+ FXLS8962AF_INT_EN_BUF_EN);
if (ret)
return ret;
@@ -851,8 +849,8 @@ static int fxls8962af_buffer_predisable(struct iio_dev *indio_dev)
fxls8962af_standby(data);
/* Disable buffer interrupt */
- ret = regmap_update_bits(data->regmap, FXLS8962AF_INT_EN,
- FXLS8962AF_INT_EN_BUF_EN, 0);
+ ret = regmap_clear_bits(data->regmap, FXLS8962AF_INT_EN,
+ FXLS8962AF_INT_EN_BUF_EN);
if (ret)
return ret;
diff --git a/drivers/iio/accel/kxsd9.c b/drivers/iio/accel/kxsd9.c
index ba99649fe195..70dfd6e354db 100644
--- a/drivers/iio/accel/kxsd9.c
+++ b/drivers/iio/accel/kxsd9.c
@@ -370,10 +370,7 @@ static int kxsd9_power_down(struct kxsd9_state *st)
* make sure we conserve power even if there are others users on the
* regulators.
*/
- ret = regmap_update_bits(st->map,
- KXSD9_REG_CTRL_B,
- KXSD9_CTRL_B_ENABLE,
- 0);
+ ret = regmap_clear_bits(st->map, KXSD9_REG_CTRL_B, KXSD9_CTRL_B_ENABLE);
if (ret)
return ret;
diff --git a/drivers/iio/accel/msa311.c b/drivers/iio/accel/msa311.c
index b8ddbfd98f11..4cdbf5424a53 100644
--- a/drivers/iio/accel/msa311.c
+++ b/drivers/iio/accel/msa311.c
@@ -1034,10 +1034,10 @@ static int msa311_chip_init(struct msa311_priv *msa311)
"failed to unmap map0/map1 interrupts\n");
/* Disable all axes by default */
- err = regmap_update_bits(msa311->regs, MSA311_ODR_REG,
- MSA311_GENMASK(F_X_AXIS_DIS) |
- MSA311_GENMASK(F_Y_AXIS_DIS) |
- MSA311_GENMASK(F_Z_AXIS_DIS), 0);
+ err = regmap_clear_bits(msa311->regs, MSA311_ODR_REG,
+ MSA311_GENMASK(F_X_AXIS_DIS) |
+ MSA311_GENMASK(F_Y_AXIS_DIS) |
+ MSA311_GENMASK(F_Z_AXIS_DIS));
if (err)
return dev_err_probe(dev, err, "can't enable all axes\n");
diff --git a/drivers/iio/accel/st_accel.h b/drivers/iio/accel/st_accel.h
index e7525615712b..2659f536cef6 100644
--- a/drivers/iio/accel/st_accel.h
+++ b/drivers/iio/accel/st_accel.h
@@ -35,6 +35,7 @@
#define LIS3DHH_ACCEL_DEV_NAME "lis3dhh"
#define LIS3DE_ACCEL_DEV_NAME "lis3de"
#define LIS2DE12_ACCEL_DEV_NAME "lis2de12"
+#define LIS2DS12_ACCEL_DEV_NAME "lis2ds12"
#define LIS2HH12_ACCEL_DEV_NAME "lis2hh12"
#define LIS302DL_ACCEL_DEV_NAME "lis302dl"
#define LSM303C_ACCEL_DEV_NAME "lsm303c_accel"
diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c
index d2104e14e255..0e371efbda70 100644
--- a/drivers/iio/accel/st_accel_core.c
+++ b/drivers/iio/accel/st_accel_core.c
@@ -926,6 +926,87 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
.bootime = 2,
},
{
+ .wai = 0x43,
+ .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
+ .sensors_supported = {
+ [0] = LIS2DS12_ACCEL_DEV_NAME,
+ },
+ .ch = (struct iio_chan_spec *)st_accel_16bit_channels,
+ .odr = {
+ .addr = 0x20,
+ .mask = 0xf0,
+ .odr_avl = {
+ { .hz = 10, .value = 0x01, },
+ { .hz = 50, .value = 0x02, },
+ { .hz = 100, .value = 0x03, },
+ { .hz = 200, .value = 0x04, },
+ { .hz = 400, .value = 0x05, },
+ { .hz = 800, .value = 0x06, },
+ },
+ },
+ .pw = {
+ .addr = 0x20,
+ .mask = 0xf0,
+ .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
+ },
+ .enable_axis = {
+ .addr = ST_SENSORS_DEFAULT_AXIS_ADDR,
+ .mask = ST_SENSORS_DEFAULT_AXIS_MASK,
+ },
+ .fs = {
+ .addr = 0x20,
+ .mask = 0x0c,
+ .fs_avl = {
+ [0] = {
+ .num = ST_ACCEL_FS_AVL_2G,
+ .value = 0x00,
+ .gain = IIO_G_TO_M_S_2(61),
+ },
+ [1] = {
+ .num = ST_ACCEL_FS_AVL_4G,
+ .value = 0x02,
+ .gain = IIO_G_TO_M_S_2(122),
+ },
+ [2] = {
+ .num = ST_ACCEL_FS_AVL_8G,
+ .value = 0x03,
+ .gain = IIO_G_TO_M_S_2(244),
+ },
+ [3] = {
+ .num = ST_ACCEL_FS_AVL_16G,
+ .value = 0x01,
+ .gain = IIO_G_TO_M_S_2(488),
+ },
+ },
+ },
+ .bdu = {
+ .addr = 0x20,
+ .mask = 0x01,
+ },
+ .drdy_irq = {
+ .int1 = {
+ .addr = 0x23,
+ .mask = 0x01,
+ },
+ .int2 = {
+ .addr = 0x24,
+ .mask = 0x01,
+ },
+ .addr_ihl = 0x22,
+ .mask_ihl = 0x02,
+ .stat_drdy = {
+ .addr = ST_SENSORS_DEFAULT_STAT_ADDR,
+ .mask = 0x01,
+ },
+ },
+ .sim = {
+ .addr = 0x21,
+ .value = BIT(0),
+ },
+ .multi_read_bit = true,
+ .bootime = 2,
+ },
+ {
.wai = 0x41,
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
.sensors_supported = {
diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c
index fd3749871121..329a4d6fb2ec 100644
--- a/drivers/iio/accel/st_accel_i2c.c
+++ b/drivers/iio/accel/st_accel_i2c.c
@@ -103,6 +103,10 @@ static const struct of_device_id st_accel_of_match[] = {
.data = LIS2DE12_ACCEL_DEV_NAME,
},
{
+ .compatible = "st,lis2ds12",
+ .data = LIS2DS12_ACCEL_DEV_NAME,
+ },
+ {
.compatible = "st,lis2hh12",
.data = LIS2HH12_ACCEL_DEV_NAME,
},
@@ -154,6 +158,7 @@ static const struct i2c_device_id st_accel_id_table[] = {
{ LIS2DW12_ACCEL_DEV_NAME },
{ LIS3DE_ACCEL_DEV_NAME },
{ LIS2DE12_ACCEL_DEV_NAME },
+ { LIS2DS12_ACCEL_DEV_NAME },
{ LIS2HH12_ACCEL_DEV_NAME },
{ LIS302DL_ACCEL_DEV_NAME },
{ LSM303C_ACCEL_DEV_NAME },
diff --git a/drivers/iio/accel/st_accel_spi.c b/drivers/iio/accel/st_accel_spi.c
index f72a24f45322..825adab37105 100644
--- a/drivers/iio/accel/st_accel_spi.c
+++ b/drivers/iio/accel/st_accel_spi.c
@@ -65,6 +65,10 @@ static const struct of_device_id st_accel_of_match[] = {
.data = LIS2DH12_ACCEL_DEV_NAME,
},
{
+ .compatible = "st,lis2ds12",
+ .data = LIS2DS12_ACCEL_DEV_NAME,
+ },
+ {
.compatible = "st,lis3l02dq",
.data = LIS3L02DQ_ACCEL_DEV_NAME,
},
@@ -151,6 +155,7 @@ static const struct spi_device_id st_accel_id_table[] = {
{ LSM330_ACCEL_DEV_NAME },
{ LSM303AGR_ACCEL_DEV_NAME },
{ LIS2DH12_ACCEL_DEV_NAME },
+ { LIS2DS12_ACCEL_DEV_NAME },
{ LIS3L02DQ_ACCEL_DEV_NAME },
{ LNG2DM_ACCEL_DEV_NAME },
{ H3LIS331DL_ACCEL_DEV_NAME },
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 3d91015af6ea..f60fe85a30d5 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -892,6 +892,18 @@ config MCP3911
This driver can also be built as a module. If so, the module will be
called mcp3911.
+config MEDIATEK_MT6359_AUXADC
+ tristate "MediaTek MT6359 PMIC AUXADC driver"
+ depends on MFD_MT6397
+ help
+ Say yes here to enable support for MediaTek MT6357, MT6358 and
+ MT6359 PMICs Auxiliary ADC.
+ This driver provides multiple channels for system monitoring,
+ such as battery voltage, PMIC temperature, and others.
+
+ This driver can also be built as a module. If so, the module will be
+ called mt6359-auxadc.
+
config MEDIATEK_MT6360_ADC
tristate "Mediatek MT6360 ADC driver"
depends on MFD_MT6360
@@ -1351,6 +1363,18 @@ config TI_ADS1015
This driver can also be built as a module. If so, the module will be
called ti-ads1015.
+config TI_ADS1119
+ tristate "Texas Instruments ADS1119 ADC"
+ depends on I2C
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ help
+ If you say yes here you get support for Texas Instruments ADS1119
+ ADC chip.
+
+ This driver can also be built as a module. If so, the module will be
+ called ti-ads1119.
+
config TI_ADS7924
tristate "Texas Instruments ADS7924 ADC"
depends on I2C
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 37ac689a0209..d370e066544e 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -80,6 +80,7 @@ obj-$(CONFIG_MCP320X) += mcp320x.o
obj-$(CONFIG_MCP3422) += mcp3422.o
obj-$(CONFIG_MCP3564) += mcp3564.o
obj-$(CONFIG_MCP3911) += mcp3911.o
+obj-$(CONFIG_MEDIATEK_MT6359_AUXADC) += mt6359-auxadc.o
obj-$(CONFIG_MEDIATEK_MT6360_ADC) += mt6360-adc.o
obj-$(CONFIG_MEDIATEK_MT6370_ADC) += mt6370-adc.o
obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o
@@ -121,6 +122,7 @@ obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o
obj-$(CONFIG_TI_ADC161S626) += ti-adc161s626.o
obj-$(CONFIG_TI_ADS1015) += ti-ads1015.o
obj-$(CONFIG_TI_ADS1100) += ti-ads1100.o
+obj-$(CONFIG_TI_ADS1119) += ti-ads1119.o
obj-$(CONFIG_TI_ADS124S08) += ti-ads124s08.o
obj-$(CONFIG_TI_ADS1298) += ti-ads1298.o
obj-$(CONFIG_TI_ADS131E08) += ti-ads131e08.o
diff --git a/drivers/iio/adc/ad4130.c b/drivers/iio/adc/ad4130.c
index aaf1fb0ac447..e134d6497827 100644
--- a/drivers/iio/adc/ad4130.c
+++ b/drivers/iio/adc/ad4130.c
@@ -1883,8 +1883,8 @@ static int ad4130_setup(struct iio_dev *indio_dev)
if (ret)
return ret;
- ret = regmap_update_bits(st->regmap, AD4130_FIFO_CONTROL_REG,
- AD4130_FIFO_CONTROL_HEADER_MASK, 0);
+ ret = regmap_clear_bits(st->regmap, AD4130_FIFO_CONTROL_REG,
+ AD4130_FIFO_CONTROL_HEADER_MASK);
if (ret)
return ret;
diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c
index e7b1d517d3de..3beed78496c5 100644
--- a/drivers/iio/adc/ad7124.c
+++ b/drivers/iio/adc/ad7124.c
@@ -555,10 +555,18 @@ static int ad7124_disable_all(struct ad_sigma_delta *sd)
return 0;
}
+static int ad7124_disable_one(struct ad_sigma_delta *sd, unsigned int chan)
+{
+ struct ad7124_state *st = container_of(sd, struct ad7124_state, sd);
+
+ return ad7124_spi_write_mask(st, AD7124_CHANNEL(chan), AD7124_CHANNEL_EN_MSK, 0, 2);
+}
+
static const struct ad_sigma_delta_info ad7124_sigma_delta_info = {
.set_channel = ad7124_set_channel,
.append_status = ad7124_append_status,
.disable_all = ad7124_disable_all,
+ .disable_one = ad7124_disable_one,
.set_mode = ad7124_set_mode,
.has_registers = true,
.addr_shift = 0,
@@ -582,12 +590,6 @@ static int ad7124_read_raw(struct iio_dev *indio_dev,
if (ret < 0)
return ret;
- /* After the conversion is performed, disable the channel */
- ret = ad_sd_write_reg(&st->sd, AD7124_CHANNEL(chan->address), 2,
- st->channels[chan->address].ain | AD7124_CHANNEL_EN(0));
- if (ret < 0)
- return ret;
-
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
mutex_lock(&st->cfgs_lock);
diff --git a/drivers/iio/adc/ad7173.c b/drivers/iio/adc/ad7173.c
index b26d4575e256..9544bf7142ad 100644
--- a/drivers/iio/adc/ad7173.c
+++ b/drivers/iio/adc/ad7173.c
@@ -1,8 +1,9 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * AD717x family SPI ADC driver
+ * AD717x and AD411x family SPI ADC driver
*
* Supported devices:
+ * AD4111/AD4112/AD4114/AD4115/AD4116
* AD7172-2/AD7172-4/AD7173-8/AD7175-2
* AD7175-8/AD7176-2/AD7177-2
*
@@ -60,11 +61,19 @@
#define AD7173_CH_SETUP_AINPOS_MASK GENMASK(9, 5)
#define AD7173_CH_SETUP_AINNEG_MASK GENMASK(4, 0)
+#define AD7173_NO_AINS_PER_CHANNEL 2
#define AD7173_CH_ADDRESS(pos, neg) \
(FIELD_PREP(AD7173_CH_SETUP_AINPOS_MASK, pos) | \
FIELD_PREP(AD7173_CH_SETUP_AINNEG_MASK, neg))
#define AD7173_AIN_TEMP_POS 17
#define AD7173_AIN_TEMP_NEG 18
+#define AD7173_AIN_POW_MON_POS 19
+#define AD7173_AIN_POW_MON_NEG 20
+#define AD7173_AIN_REF_POS 21
+#define AD7173_AIN_REF_NEG 22
+
+#define AD7173_IS_REF_INPUT(x) ((x) == AD7173_AIN_REF_POS || \
+ (x) == AD7173_AIN_REF_NEG)
#define AD7172_2_ID 0x00d0
#define AD7175_ID 0x0cd0
@@ -72,6 +81,11 @@
#define AD7175_2_ID 0x0cd0
#define AD7172_4_ID 0x2050
#define AD7173_ID 0x30d0
+#define AD4111_ID AD7173_ID
+#define AD4112_ID AD7173_ID
+#define AD4114_ID AD7173_ID
+#define AD4116_ID 0x34d0
+#define AD4115_ID 0x38d0
#define AD7175_8_ID 0x3cd0
#define AD7177_ID 0x4fd0
#define AD7173_ID_MASK GENMASK(15, 4)
@@ -102,6 +116,7 @@
#define AD7173_GPO12_DATA(x) BIT((x) + 0)
#define AD7173_GPO23_DATA(x) BIT((x) + 4)
+#define AD4111_GPO01_DATA(x) BIT((x) + 6)
#define AD7173_GPO_DATA(x) ((x) < 2 ? AD7173_GPO12_DATA(x) : AD7173_GPO23_DATA(x))
#define AD7173_INTERFACE_DATA_STAT BIT(6)
@@ -120,34 +135,45 @@
#define AD7173_VOLTAGE_INT_REF_uV 2500000
#define AD7173_TEMP_SENSIIVITY_uV_per_C 477
#define AD7177_ODR_START_VALUE 0x07
+#define AD4111_SHUNT_RESISTOR_OHM 50
+#define AD4111_DIVIDER_RATIO 10
+#define AD4111_CURRENT_CHAN_CUTOFF 16
+#define AD4111_VINCOM_INPUT 0x10
+
+/* pin < num_voltage_in is a normal voltage input */
+/* pin >= num_voltage_in_div is a voltage input without a divider */
+#define AD4111_IS_VINCOM_MISMATCH(pin1, pin2) ((pin1) == AD4111_VINCOM_INPUT && \
+ (pin2) < st->info->num_voltage_in && \
+ (pin2) >= st->info->num_voltage_in_div)
#define AD7173_FILTER_ODR0_MASK GENMASK(5, 0)
#define AD7173_MAX_CONFIGS 8
-enum ad7173_ids {
- ID_AD7172_2,
- ID_AD7172_4,
- ID_AD7173_8,
- ID_AD7175_2,
- ID_AD7175_8,
- ID_AD7176_2,
- ID_AD7177_2,
-};
-
struct ad7173_device_info {
const unsigned int *sinc5_data_rates;
unsigned int num_sinc5_data_rates;
unsigned int odr_start_value;
+ /*
+ * AD4116 has both inputs with a voltage divider and without.
+ * These inputs cannot be mixed in the channel configuration.
+ * Does not include the VINCOM input.
+ */
+ unsigned int num_voltage_in_div;
unsigned int num_channels;
unsigned int num_configs;
- unsigned int num_inputs;
+ unsigned int num_voltage_in;
unsigned int clock;
unsigned int id;
char *name;
+ bool has_current_inputs;
+ bool has_vincom_input;
bool has_temp;
+ /* ((AVDD1 − AVSS)/5) */
+ bool has_pow_supply_monitoring;
bool has_input_buf;
bool has_int_ref;
bool has_ref2;
+ bool higher_gpio_bits;
u8 num_gpios;
};
@@ -189,6 +215,24 @@ struct ad7173_state {
#endif
};
+static unsigned int ad4115_sinc5_data_rates[] = {
+ 24845000, 24845000, 20725000, 20725000, /* 0-3 */
+ 15564000, 13841000, 10390000, 10390000, /* 4-7 */
+ 4994000, 2499000, 1000000, 500000, /* 8-11 */
+ 395500, 200000, 100000, 59890, /* 12-15 */
+ 49920, 20000, 16660, 10000, /* 16-19 */
+ 5000, 2500, 2500, /* 20-22 */
+};
+
+static unsigned int ad4116_sinc5_data_rates[] = {
+ 12422360, 12422360, 12422360, 12422360, /* 0-3 */
+ 10362690, 10362690, 7782100, 6290530, /* 4-7 */
+ 5194800, 2496900, 1007600, 499900, /* 8-11 */
+ 390600, 200300, 100000, 59750, /* 12-15 */
+ 49840, 20000, 16650, 10000, /* 16-19 */
+ 5000, 2500, 1250, /* 20-22 */
+};
+
static const unsigned int ad7173_sinc5_data_rates[] = {
6211000, 6211000, 6211000, 6211000, 6211000, 6211000, 5181000, 4444000, /* 0-7 */
3115000, 2597000, 1007000, 503800, 381000, 200300, 100500, 59520, /* 8-15 */
@@ -204,108 +248,214 @@ static const unsigned int ad7175_sinc5_data_rates[] = {
5000, /* 20 */
};
-static const struct ad7173_device_info ad7173_device_info[] = {
- [ID_AD7172_2] = {
- .name = "ad7172-2",
- .id = AD7172_2_ID,
- .num_inputs = 5,
- .num_channels = 4,
- .num_configs = 4,
- .num_gpios = 2,
- .has_temp = true,
- .has_input_buf = true,
- .has_int_ref = true,
- .clock = 2 * HZ_PER_MHZ,
- .sinc5_data_rates = ad7173_sinc5_data_rates,
- .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates),
- },
- [ID_AD7172_4] = {
- .name = "ad7172-4",
- .id = AD7172_4_ID,
- .num_inputs = 9,
- .num_channels = 8,
- .num_configs = 8,
- .num_gpios = 4,
- .has_temp = false,
- .has_input_buf = true,
- .has_ref2 = true,
- .clock = 2 * HZ_PER_MHZ,
- .sinc5_data_rates = ad7173_sinc5_data_rates,
- .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates),
- },
- [ID_AD7173_8] = {
- .name = "ad7173-8",
- .id = AD7173_ID,
- .num_inputs = 17,
- .num_channels = 16,
- .num_configs = 8,
- .num_gpios = 4,
- .has_temp = true,
- .has_input_buf = true,
- .has_int_ref = true,
- .has_ref2 = true,
- .clock = 2 * HZ_PER_MHZ,
- .sinc5_data_rates = ad7173_sinc5_data_rates,
- .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates),
- },
- [ID_AD7175_2] = {
- .name = "ad7175-2",
- .id = AD7175_2_ID,
- .num_inputs = 5,
- .num_channels = 4,
- .num_configs = 4,
- .num_gpios = 2,
- .has_temp = true,
- .has_input_buf = true,
- .has_int_ref = true,
- .clock = 16 * HZ_PER_MHZ,
- .sinc5_data_rates = ad7175_sinc5_data_rates,
- .num_sinc5_data_rates = ARRAY_SIZE(ad7175_sinc5_data_rates),
- },
- [ID_AD7175_8] = {
- .name = "ad7175-8",
- .id = AD7175_8_ID,
- .num_inputs = 17,
- .num_channels = 16,
- .num_configs = 8,
- .num_gpios = 4,
- .has_temp = true,
- .has_input_buf = true,
- .has_int_ref = true,
- .has_ref2 = true,
- .clock = 16 * HZ_PER_MHZ,
- .sinc5_data_rates = ad7175_sinc5_data_rates,
- .num_sinc5_data_rates = ARRAY_SIZE(ad7175_sinc5_data_rates),
- },
- [ID_AD7176_2] = {
- .name = "ad7176-2",
- .id = AD7176_ID,
- .num_inputs = 5,
- .num_channels = 4,
- .num_configs = 4,
- .num_gpios = 2,
- .has_temp = false,
- .has_input_buf = false,
- .has_int_ref = true,
- .clock = 16 * HZ_PER_MHZ,
- .sinc5_data_rates = ad7175_sinc5_data_rates,
- .num_sinc5_data_rates = ARRAY_SIZE(ad7175_sinc5_data_rates),
- },
- [ID_AD7177_2] = {
- .name = "ad7177-2",
- .id = AD7177_ID,
- .num_inputs = 5,
- .num_channels = 4,
- .num_configs = 4,
- .num_gpios = 2,
- .has_temp = true,
- .has_input_buf = true,
- .has_int_ref = true,
- .clock = 16 * HZ_PER_MHZ,
- .odr_start_value = AD7177_ODR_START_VALUE,
- .sinc5_data_rates = ad7175_sinc5_data_rates,
- .num_sinc5_data_rates = ARRAY_SIZE(ad7175_sinc5_data_rates),
- },
+static unsigned int ad4111_current_channel_config[] = {
+ /* Ain sel: pos neg */
+ 0x1E8, /* 15:IIN0+ 8:IIN0− */
+ 0x1C9, /* 14:IIN1+ 9:IIN1− */
+ 0x1AA, /* 13:IIN2+ 10:IIN2− */
+ 0x18B, /* 12:IIN3+ 11:IIN3− */
+};
+
+static const struct ad7173_device_info ad4111_device_info = {
+ .name = "ad4111",
+ .id = AD4111_ID,
+ .num_voltage_in_div = 8,
+ .num_channels = 16,
+ .num_configs = 8,
+ .num_voltage_in = 8,
+ .num_gpios = 2,
+ .higher_gpio_bits = true,
+ .has_temp = true,
+ .has_vincom_input = true,
+ .has_input_buf = true,
+ .has_current_inputs = true,
+ .has_int_ref = true,
+ .clock = 2 * HZ_PER_MHZ,
+ .sinc5_data_rates = ad7173_sinc5_data_rates,
+ .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates),
+};
+
+static const struct ad7173_device_info ad4112_device_info = {
+ .name = "ad4112",
+ .id = AD4112_ID,
+ .num_voltage_in_div = 8,
+ .num_channels = 16,
+ .num_configs = 8,
+ .num_voltage_in = 8,
+ .num_gpios = 2,
+ .higher_gpio_bits = true,
+ .has_vincom_input = true,
+ .has_temp = true,
+ .has_input_buf = true,
+ .has_current_inputs = true,
+ .has_int_ref = true,
+ .clock = 2 * HZ_PER_MHZ,
+ .sinc5_data_rates = ad7173_sinc5_data_rates,
+ .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates),
+};
+
+static const struct ad7173_device_info ad4114_device_info = {
+ .name = "ad4114",
+ .id = AD4114_ID,
+ .num_voltage_in_div = 16,
+ .num_channels = 16,
+ .num_configs = 8,
+ .num_voltage_in = 16,
+ .num_gpios = 4,
+ .higher_gpio_bits = true,
+ .has_vincom_input = true,
+ .has_temp = true,
+ .has_input_buf = true,
+ .has_int_ref = true,
+ .clock = 2 * HZ_PER_MHZ,
+ .sinc5_data_rates = ad7173_sinc5_data_rates,
+ .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates),
+};
+
+static const struct ad7173_device_info ad4115_device_info = {
+ .name = "ad4115",
+ .id = AD4115_ID,
+ .num_voltage_in_div = 16,
+ .num_channels = 16,
+ .num_configs = 8,
+ .num_voltage_in = 16,
+ .num_gpios = 4,
+ .higher_gpio_bits = true,
+ .has_vincom_input = true,
+ .has_temp = true,
+ .has_input_buf = true,
+ .has_int_ref = true,
+ .clock = 8 * HZ_PER_MHZ,
+ .sinc5_data_rates = ad4115_sinc5_data_rates,
+ .num_sinc5_data_rates = ARRAY_SIZE(ad4115_sinc5_data_rates),
+};
+
+static const struct ad7173_device_info ad4116_device_info = {
+ .name = "ad4116",
+ .id = AD4116_ID,
+ .num_voltage_in_div = 11,
+ .num_channels = 16,
+ .num_configs = 8,
+ .num_voltage_in = 16,
+ .num_gpios = 4,
+ .higher_gpio_bits = true,
+ .has_vincom_input = true,
+ .has_temp = true,
+ .has_input_buf = true,
+ .has_int_ref = true,
+ .clock = 4 * HZ_PER_MHZ,
+ .sinc5_data_rates = ad4116_sinc5_data_rates,
+ .num_sinc5_data_rates = ARRAY_SIZE(ad4116_sinc5_data_rates),
+};
+
+static const struct ad7173_device_info ad7172_2_device_info = {
+ .name = "ad7172-2",
+ .id = AD7172_2_ID,
+ .num_voltage_in = 5,
+ .num_channels = 4,
+ .num_configs = 4,
+ .num_gpios = 2,
+ .has_temp = true,
+ .has_input_buf = true,
+ .has_int_ref = true,
+ .has_pow_supply_monitoring = true,
+ .clock = 2 * HZ_PER_MHZ,
+ .sinc5_data_rates = ad7173_sinc5_data_rates,
+ .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates),
+};
+
+static const struct ad7173_device_info ad7172_4_device_info = {
+ .name = "ad7172-4",
+ .id = AD7172_4_ID,
+ .num_voltage_in = 9,
+ .num_channels = 8,
+ .num_configs = 8,
+ .num_gpios = 4,
+ .has_input_buf = true,
+ .has_ref2 = true,
+ .has_pow_supply_monitoring = true,
+ .clock = 2 * HZ_PER_MHZ,
+ .sinc5_data_rates = ad7173_sinc5_data_rates,
+ .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates),
+};
+
+static const struct ad7173_device_info ad7173_8_device_info = {
+ .name = "ad7173-8",
+ .id = AD7173_ID,
+ .num_voltage_in = 17,
+ .num_channels = 16,
+ .num_configs = 8,
+ .num_gpios = 4,
+ .has_temp = true,
+ .has_input_buf = true,
+ .has_int_ref = true,
+ .has_ref2 = true,
+ .clock = 2 * HZ_PER_MHZ,
+ .sinc5_data_rates = ad7173_sinc5_data_rates,
+ .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates),
+};
+
+static const struct ad7173_device_info ad7175_2_device_info = {
+ .name = "ad7175-2",
+ .id = AD7175_2_ID,
+ .num_voltage_in = 5,
+ .num_channels = 4,
+ .num_configs = 4,
+ .num_gpios = 2,
+ .has_temp = true,
+ .has_input_buf = true,
+ .has_int_ref = true,
+ .has_pow_supply_monitoring = true,
+ .clock = 16 * HZ_PER_MHZ,
+ .sinc5_data_rates = ad7175_sinc5_data_rates,
+ .num_sinc5_data_rates = ARRAY_SIZE(ad7175_sinc5_data_rates),
+};
+
+static const struct ad7173_device_info ad7175_8_device_info = {
+ .name = "ad7175-8",
+ .id = AD7175_8_ID,
+ .num_voltage_in = 17,
+ .num_channels = 16,
+ .num_configs = 8,
+ .num_gpios = 4,
+ .has_temp = true,
+ .has_input_buf = true,
+ .has_int_ref = true,
+ .has_ref2 = true,
+ .has_pow_supply_monitoring = true,
+ .clock = 16 * HZ_PER_MHZ,
+ .sinc5_data_rates = ad7175_sinc5_data_rates,
+ .num_sinc5_data_rates = ARRAY_SIZE(ad7175_sinc5_data_rates),
+};
+
+static const struct ad7173_device_info ad7176_2_device_info = {
+ .name = "ad7176-2",
+ .id = AD7176_ID,
+ .num_voltage_in = 5,
+ .num_channels = 4,
+ .num_configs = 4,
+ .num_gpios = 2,
+ .has_int_ref = true,
+ .clock = 16 * HZ_PER_MHZ,
+ .sinc5_data_rates = ad7175_sinc5_data_rates,
+ .num_sinc5_data_rates = ARRAY_SIZE(ad7175_sinc5_data_rates),
+};
+
+static const struct ad7173_device_info ad7177_2_device_info = {
+ .name = "ad7177-2",
+ .id = AD7177_ID,
+ .num_voltage_in = 5,
+ .num_channels = 4,
+ .num_configs = 4,
+ .num_gpios = 2,
+ .has_temp = true,
+ .has_input_buf = true,
+ .has_int_ref = true,
+ .has_pow_supply_monitoring = true,
+ .clock = 16 * HZ_PER_MHZ,
+ .odr_start_value = AD7177_ODR_START_VALUE,
+ .sinc5_data_rates = ad7175_sinc5_data_rates,
+ .num_sinc5_data_rates = ARRAY_SIZE(ad7175_sinc5_data_rates),
};
static const char *const ad7173_ref_sel_str[] = {
@@ -347,6 +497,15 @@ static int ad7173_mask_xlate(struct gpio_regmap *gpio, unsigned int base,
return 0;
}
+static int ad4111_mask_xlate(struct gpio_regmap *gpio, unsigned int base,
+ unsigned int offset, unsigned int *reg,
+ unsigned int *mask)
+{
+ *mask = AD4111_GPO01_DATA(offset);
+ *reg = base;
+ return 0;
+}
+
static void ad7173_gpio_disable(void *data)
{
struct ad7173_state *st = data;
@@ -379,7 +538,10 @@ static int ad7173_gpio_init(struct ad7173_state *st)
gpio_regmap.regmap = st->reg_gpiocon_regmap;
gpio_regmap.ngpio = st->info->num_gpios;
gpio_regmap.reg_set_base = AD7173_REG_GPIO;
- gpio_regmap.reg_mask_xlate = ad7173_mask_xlate;
+ if (st->info->higher_gpio_bits)
+ gpio_regmap.reg_mask_xlate = ad4111_mask_xlate;
+ else
+ gpio_regmap.reg_mask_xlate = ad7173_mask_xlate;
st->gpio_regmap = devm_gpio_regmap_register(dev, &gpio_regmap);
ret = PTR_ERR_OR_ZERO(st->gpio_regmap);
@@ -569,10 +731,16 @@ static int ad7173_disable_all(struct ad_sigma_delta *sd)
return 0;
}
+static int ad7173_disable_one(struct ad_sigma_delta *sd, unsigned int chan)
+{
+ return ad_sd_write_reg(sd, AD7173_REG_CH(chan), 2, 0);
+}
+
static struct ad_sigma_delta_info ad7173_sigma_delta_info = {
.set_channel = ad7173_set_channel,
.append_status = ad7173_append_status,
.disable_all = ad7173_disable_all,
+ .disable_one = ad7173_disable_one,
.set_mode = ad7173_set_mode,
.has_registers = true,
.addr_shift = 0,
@@ -668,25 +836,35 @@ static int ad7173_read_raw(struct iio_dev *indio_dev,
if (ret < 0)
return ret;
- /* disable channel after single conversion */
- ret = ad_sd_write_reg(&st->sd, AD7173_REG_CH(chan->address), 2, 0);
- if (ret < 0)
- return ret;
-
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
- if (chan->type == IIO_TEMP) {
+
+ switch (chan->type) {
+ case IIO_TEMP:
temp = AD7173_VOLTAGE_INT_REF_uV * MILLI;
temp /= AD7173_TEMP_SENSIIVITY_uV_per_C;
*val = temp;
*val2 = chan->scan_type.realbits;
- } else {
+ return IIO_VAL_FRACTIONAL_LOG2;
+ case IIO_VOLTAGE:
*val = ad7173_get_ref_voltage_milli(st, ch->cfg.ref_sel);
*val2 = chan->scan_type.realbits - !!(ch->cfg.bipolar);
+
+ if (chan->channel < st->info->num_voltage_in_div)
+ *val *= AD4111_DIVIDER_RATIO;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ case IIO_CURRENT:
+ *val = ad7173_get_ref_voltage_milli(st, ch->cfg.ref_sel);
+ *val /= AD4111_SHUNT_RESISTOR_OHM;
+ *val2 = chan->scan_type.realbits - ch->cfg.bipolar;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ default:
+ return -EINVAL;
}
- return IIO_VAL_FRACTIONAL_LOG2;
case IIO_CHAN_INFO_OFFSET:
- if (chan->type == IIO_TEMP) {
+
+ switch (chan->type) {
+ case IIO_TEMP:
/* 0 Kelvin -> raw sample */
temp = -ABSOLUTE_ZERO_MILLICELSIUS;
temp *= AD7173_TEMP_SENSIIVITY_uV_per_C;
@@ -695,10 +873,14 @@ static int ad7173_read_raw(struct iio_dev *indio_dev,
AD7173_VOLTAGE_INT_REF_uV *
MILLI);
*val = -temp;
- } else {
+ return IIO_VAL_INT;
+ case IIO_VOLTAGE:
+ case IIO_CURRENT:
*val = -BIT(chan->scan_type.realbits - 1);
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
}
- return IIO_VAL_INT;
case IIO_CHAN_INFO_SAMP_FREQ:
reg = st->channels[chan->address].cfg.odr;
@@ -725,6 +907,21 @@ static int ad7173_write_raw(struct iio_dev *indio_dev,
return ret;
switch (info) {
+ /*
+ * This attribute sets the sampling frequency for each channel individually.
+ * There are no issues for raw or buffered reads of an individual channel.
+ *
+ * When multiple channels are enabled in buffered mode, the effective
+ * sampling rate of a channel is lowered in correlation to the number
+ * of channels enabled and the sampling rate of the other channels.
+ *
+ * Example: 3 channels enabled with rates CH1:6211sps CH2,CH3:10sps
+ * While the reading of CH1 takes only 0.16ms, the reading of CH2 and CH3
+ * will take 100ms each.
+ *
+ * This will cause the reading of CH1 to be actually done once every
+ * 200.16ms, an effective rate of 4.99sps.
+ */
case IIO_CHAN_INFO_SAMP_FREQ:
freq = val * MILLI + val2 / MILLI;
for (i = st->info->odr_start_value; i < st->info->num_sinc5_data_rates - 1; i++)
@@ -904,14 +1101,110 @@ static int ad7173_register_clk_provider(struct iio_dev *indio_dev)
&st->int_clk_hw);
}
+static int ad4111_validate_current_ain(struct ad7173_state *st,
+ const unsigned int ain[AD7173_NO_AINS_PER_CHANNEL])
+{
+ struct device *dev = &st->sd.spi->dev;
+
+ if (!st->info->has_current_inputs)
+ return dev_err_probe(dev, -EINVAL,
+ "Model %s does not support current channels\n",
+ st->info->name);
+
+ if (ain[0] >= ARRAY_SIZE(ad4111_current_channel_config))
+ return dev_err_probe(dev, -EINVAL,
+ "For current channels single-channel must be <[0-3]>\n");
+
+ return 0;
+}
+
+static int ad7173_validate_voltage_ain_inputs(struct ad7173_state *st,
+ unsigned int ain0, unsigned int ain1)
+{
+ struct device *dev = &st->sd.spi->dev;
+ bool special_input0, special_input1;
+
+ /* (AVDD1-AVSS)/5 power supply monitoring */
+ if (ain0 == AD7173_AIN_POW_MON_POS && ain1 == AD7173_AIN_POW_MON_NEG &&
+ st->info->has_pow_supply_monitoring)
+ return 0;
+
+ special_input0 = AD7173_IS_REF_INPUT(ain0) ||
+ (ain0 == AD4111_VINCOM_INPUT && st->info->has_vincom_input);
+ special_input1 = AD7173_IS_REF_INPUT(ain1) ||
+ (ain1 == AD4111_VINCOM_INPUT && st->info->has_vincom_input);
+
+ if ((ain0 >= st->info->num_voltage_in && !special_input0) ||
+ (ain1 >= st->info->num_voltage_in && !special_input1)) {
+ if (ain0 == AD4111_VINCOM_INPUT || ain1 == AD4111_VINCOM_INPUT)
+ return dev_err_probe(dev, -EINVAL,
+ "VINCOM not supported for %s\n", st->info->name);
+
+ return dev_err_probe(dev, -EINVAL,
+ "Input pin number out of range for pair (%d %d).\n",
+ ain0, ain1);
+ }
+
+ if (AD4111_IS_VINCOM_MISMATCH(ain0, ain1) ||
+ AD4111_IS_VINCOM_MISMATCH(ain1, ain0))
+ return dev_err_probe(dev, -EINVAL,
+ "VINCOM must be paired with inputs having divider.\n");
+
+ if (!special_input0 && !special_input1 &&
+ ((ain0 >= st->info->num_voltage_in_div) !=
+ (ain1 >= st->info->num_voltage_in_div)))
+ return dev_err_probe(dev, -EINVAL,
+ "Both inputs must either have a voltage divider or not have: (%d %d).\n",
+ ain0, ain1);
+
+ return 0;
+}
+
+static int ad7173_validate_reference(struct ad7173_state *st, int ref_sel)
+{
+ struct device *dev = &st->sd.spi->dev;
+ int ret;
+
+ if (ref_sel == AD7173_SETUP_REF_SEL_INT_REF && !st->info->has_int_ref)
+ return dev_err_probe(dev, -EINVAL,
+ "Internal reference is not available on current model.\n");
+
+ if (ref_sel == AD7173_SETUP_REF_SEL_EXT_REF2 && !st->info->has_ref2)
+ return dev_err_probe(dev, -EINVAL,
+ "External reference 2 is not available on current model.\n");
+
+ ret = ad7173_get_ref_voltage_milli(st, ref_sel);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Cannot use reference %u\n",
+ ref_sel);
+
+ return 0;
+}
+
static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev)
{
struct ad7173_channel *chans_st_arr, *chan_st_priv;
struct ad7173_state *st = iio_priv(indio_dev);
struct device *dev = indio_dev->dev.parent;
struct iio_chan_spec *chan_arr, *chan;
- unsigned int ain[2], chan_index = 0;
- int ref_sel, ret;
+ unsigned int ain[AD7173_NO_AINS_PER_CHANNEL], chan_index = 0;
+ int ref_sel, ret, num_channels;
+
+ num_channels = device_get_child_node_count(dev);
+
+ if (st->info->has_temp)
+ num_channels++;
+
+ if (num_channels == 0)
+ return dev_err_probe(dev, -ENODATA, "No channels specified\n");
+
+ if (num_channels > st->info->num_channels)
+ return dev_err_probe(dev, -EINVAL,
+ "Too many channels specified. Maximum is %d, not including temperature channel if supported.\n",
+ st->info->num_channels);
+
+ indio_dev->num_channels = num_channels;
+ st->num_channels = num_channels;
chan_arr = devm_kcalloc(dev, sizeof(*indio_dev->channels),
st->num_channels, GFP_KERNEL);
@@ -941,18 +1234,41 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev)
}
device_for_each_child_node_scoped(dev, child) {
+ bool is_current_chan = false;
+
chan = &chan_arr[chan_index];
+ *chan = ad7173_channel_template;
chan_st_priv = &chans_st_arr[chan_index];
ret = fwnode_property_read_u32_array(child, "diff-channels",
ain, ARRAY_SIZE(ain));
- if (ret)
- return ret;
+ if (ret) {
+ ret = fwnode_property_read_u32(child, "single-channel",
+ ain);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Channel must define one of diff-channels or single-channel.\n");
- if (ain[0] >= st->info->num_inputs ||
- ain[1] >= st->info->num_inputs)
- return dev_err_probe(dev, -EINVAL,
- "Input pin number out of range for pair (%d %d).\n",
- ain[0], ain[1]);
+ is_current_chan = fwnode_property_read_bool(child, "adi,current-channel");
+ } else {
+ chan->differential = true;
+ }
+
+ if (is_current_chan) {
+ ret = ad4111_validate_current_ain(st, ain);
+ if (ret)
+ return ret;
+ } else {
+ if (!chan->differential) {
+ ret = fwnode_property_read_u32(child,
+ "common-mode-channel", ain + 1);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "common-mode-channel must be defined for single-ended channels.\n");
+ }
+ ret = ad7173_validate_voltage_ain_inputs(st, ain[0], ain[1]);
+ if (ret)
+ return ret;
+ }
ret = fwnode_property_match_property_string(child,
"adi,reference-select",
@@ -963,32 +1279,17 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev)
else
ref_sel = ret;
- if (ref_sel == AD7173_SETUP_REF_SEL_INT_REF &&
- !st->info->has_int_ref)
- return dev_err_probe(dev, -EINVAL,
- "Internal reference is not available on current model.\n");
-
- if (ref_sel == AD7173_SETUP_REF_SEL_EXT_REF2 && !st->info->has_ref2)
- return dev_err_probe(dev, -EINVAL,
- "External reference 2 is not available on current model.\n");
-
- ret = ad7173_get_ref_voltage_milli(st, ref_sel);
- if (ret < 0)
- return dev_err_probe(dev, ret,
- "Cannot use reference %u\n", ref_sel);
+ ret = ad7173_validate_reference(st, ref_sel);
+ if (ret)
+ return ret;
if (ref_sel == AD7173_SETUP_REF_SEL_INT_REF)
st->adc_mode |= AD7173_ADC_MODE_REF_EN;
chan_st_priv->cfg.ref_sel = ref_sel;
- *chan = ad7173_channel_template;
chan->address = chan_index;
chan->scan_index = chan_index;
chan->channel = ain[0];
- chan->channel2 = ain[1];
- chan->differential = true;
-
- chan_st_priv->ain = AD7173_CH_ADDRESS(ain[0], ain[1]);
chan_st_priv->chan_reg = chan_index;
chan_st_priv->cfg.input_buf = st->info->has_input_buf;
chan_st_priv->cfg.odr = 0;
@@ -997,6 +1298,17 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev)
if (chan_st_priv->cfg.bipolar)
chan->info_mask_separate |= BIT(IIO_CHAN_INFO_OFFSET);
+ if (is_current_chan) {
+ chan->type = IIO_CURRENT;
+ chan->differential = false;
+ chan->channel2 = 0;
+ chan_st_priv->ain = ad4111_current_channel_config[ain[0]];
+ } else {
+ chan_st_priv->cfg.input_buf = st->info->has_input_buf;
+ chan->channel2 = ain[1];
+ chan_st_priv->ain = AD7173_CH_ADDRESS(ain[0], ain[1]);
+ }
+
chan_index++;
}
return 0;
@@ -1006,7 +1318,6 @@ static int ad7173_fw_parse_device_config(struct iio_dev *indio_dev)
{
struct ad7173_state *st = iio_priv(indio_dev);
struct device *dev = indio_dev->dev.parent;
- unsigned int num_channels;
int ret;
st->regulators[0].supply = ad7173_ref_sel_str[AD7173_SETUP_REF_SEL_EXT_REF];
@@ -1065,16 +1376,6 @@ static int ad7173_fw_parse_device_config(struct iio_dev *indio_dev)
ad7173_sigma_delta_info.irq_line = ret;
- num_channels = device_get_child_node_count(dev);
-
- if (st->info->has_temp)
- num_channels++;
-
- if (num_channels == 0)
- return dev_err_probe(dev, -ENODATA, "No channels specified\n");
- indio_dev->num_channels = num_channels;
- st->num_channels = num_channels;
-
return ad7173_fw_parse_channel_config(indio_dev);
}
@@ -1134,32 +1435,35 @@ static int ad7173_probe(struct spi_device *spi)
}
static const struct of_device_id ad7173_of_match[] = {
- { .compatible = "adi,ad7172-2",
- .data = &ad7173_device_info[ID_AD7172_2]},
- { .compatible = "adi,ad7172-4",
- .data = &ad7173_device_info[ID_AD7172_4]},
- { .compatible = "adi,ad7173-8",
- .data = &ad7173_device_info[ID_AD7173_8]},
- { .compatible = "adi,ad7175-2",
- .data = &ad7173_device_info[ID_AD7175_2]},
- { .compatible = "adi,ad7175-8",
- .data = &ad7173_device_info[ID_AD7175_8]},
- { .compatible = "adi,ad7176-2",
- .data = &ad7173_device_info[ID_AD7176_2]},
- { .compatible = "adi,ad7177-2",
- .data = &ad7173_device_info[ID_AD7177_2]},
+ { .compatible = "ad4111", .data = &ad4111_device_info },
+ { .compatible = "ad4112", .data = &ad4112_device_info },
+ { .compatible = "ad4114", .data = &ad4114_device_info },
+ { .compatible = "ad4115", .data = &ad4115_device_info },
+ { .compatible = "ad4116", .data = &ad4116_device_info },
+ { .compatible = "adi,ad7172-2", .data = &ad7172_2_device_info },
+ { .compatible = "adi,ad7172-4", .data = &ad7172_4_device_info },
+ { .compatible = "adi,ad7173-8", .data = &ad7173_8_device_info },
+ { .compatible = "adi,ad7175-2", .data = &ad7175_2_device_info },
+ { .compatible = "adi,ad7175-8", .data = &ad7175_8_device_info },
+ { .compatible = "adi,ad7176-2", .data = &ad7176_2_device_info },
+ { .compatible = "adi,ad7177-2", .data = &ad7177_2_device_info },
{ }
};
MODULE_DEVICE_TABLE(of, ad7173_of_match);
static const struct spi_device_id ad7173_id_table[] = {
- { "ad7172-2", (kernel_ulong_t)&ad7173_device_info[ID_AD7172_2]},
- { "ad7172-4", (kernel_ulong_t)&ad7173_device_info[ID_AD7172_4]},
- { "ad7173-8", (kernel_ulong_t)&ad7173_device_info[ID_AD7173_8]},
- { "ad7175-2", (kernel_ulong_t)&ad7173_device_info[ID_AD7175_2]},
- { "ad7175-8", (kernel_ulong_t)&ad7173_device_info[ID_AD7175_8]},
- { "ad7176-2", (kernel_ulong_t)&ad7173_device_info[ID_AD7176_2]},
- { "ad7177-2", (kernel_ulong_t)&ad7173_device_info[ID_AD7177_2]},
+ { "ad4111", (kernel_ulong_t)&ad4111_device_info },
+ { "ad4112", (kernel_ulong_t)&ad4112_device_info },
+ { "ad4114", (kernel_ulong_t)&ad4114_device_info },
+ { "ad4115", (kernel_ulong_t)&ad4115_device_info },
+ { "ad4116", (kernel_ulong_t)&ad4116_device_info },
+ { "ad7172-2", (kernel_ulong_t)&ad7172_2_device_info },
+ { "ad7172-4", (kernel_ulong_t)&ad7172_4_device_info },
+ { "ad7173-8", (kernel_ulong_t)&ad7173_8_device_info },
+ { "ad7175-2", (kernel_ulong_t)&ad7175_2_device_info },
+ { "ad7175-8", (kernel_ulong_t)&ad7175_8_device_info },
+ { "ad7176-2", (kernel_ulong_t)&ad7176_2_device_info },
+ { "ad7177-2", (kernel_ulong_t)&ad7177_2_device_info },
{ }
};
MODULE_DEVICE_TABLE(spi, ad7173_id_table);
@@ -1177,5 +1481,5 @@ module_spi_driver(ad7173_driver);
MODULE_IMPORT_NS(IIO_AD_SIGMA_DELTA);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafo.de>");
MODULE_AUTHOR("Dumitru Ceclan <dumitru.ceclan@analog.com>");
-MODULE_DESCRIPTION("Analog Devices AD7172/AD7173/AD7175/AD7176 ADC driver");
+MODULE_DESCRIPTION("Analog Devices AD7173 and similar ADC driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/iio/adc/ad7192.c b/drivers/iio/adc/ad7192.c
index 0789121236d6..334ab90991d4 100644
--- a/drivers/iio/adc/ad7192.c
+++ b/drivers/iio/adc/ad7192.c
@@ -200,8 +200,6 @@ struct ad7192_chip_info {
struct ad7192_state {
const struct ad7192_chip_info *chip_info;
- struct regulator *avdd;
- struct regulator *vref;
struct clk *mclk;
u16 int_vref_mv;
u32 aincom_mv;
@@ -1189,24 +1187,17 @@ static const struct ad7192_chip_info ad7192_chip_info_tbl[] = {
},
};
-static void ad7192_reg_disable(void *reg)
-{
- regulator_disable(reg);
-}
-
static int ad7192_probe(struct spi_device *spi)
{
+ struct device *dev = &spi->dev;
struct ad7192_state *st;
struct iio_dev *indio_dev;
- struct regulator *aincom;
- int ret;
+ int ret, avdd_mv;
- if (!spi->irq) {
- dev_err(&spi->dev, "no IRQ?\n");
- return -ENODEV;
- }
+ if (!spi->irq)
+ return dev_err_probe(dev, -ENODEV, "Failed to get IRQ\n");
- indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
@@ -1219,74 +1210,49 @@ static int ad7192_probe(struct spi_device *spi)
* Newer firmware should provide a zero volt fixed supply if wired to
* ground.
*/
- aincom = devm_regulator_get_optional(&spi->dev, "aincom");
- if (IS_ERR(aincom)) {
- if (PTR_ERR(aincom) != -ENODEV)
- return dev_err_probe(&spi->dev, PTR_ERR(aincom),
- "Failed to get AINCOM supply\n");
-
- st->aincom_mv = 0;
- } else {
- ret = regulator_enable(aincom);
- if (ret)
- return dev_err_probe(&spi->dev, ret,
- "Failed to enable specified AINCOM supply\n");
-
- ret = devm_add_action_or_reset(&spi->dev, ad7192_reg_disable, aincom);
- if (ret)
- return ret;
-
- ret = regulator_get_voltage(aincom);
- if (ret < 0)
- return dev_err_probe(&spi->dev, ret,
- "Device tree error, AINCOM voltage undefined\n");
- st->aincom_mv = ret / MILLI;
- }
-
- st->avdd = devm_regulator_get(&spi->dev, "avdd");
- if (IS_ERR(st->avdd))
- return PTR_ERR(st->avdd);
-
- ret = regulator_enable(st->avdd);
- if (ret) {
- dev_err(&spi->dev, "Failed to enable specified AVdd supply\n");
- return ret;
+ ret = devm_regulator_get_enable_read_voltage(dev, "aincom");
+ if (ret < 0 && ret != -ENODEV)
+ return dev_err_probe(dev, ret, "Failed to get AINCOM voltage\n");
+
+ st->aincom_mv = ret == -ENODEV ? 0 : ret / MILLI;
+
+ /* AVDD can optionally be used as reference voltage */
+ ret = devm_regulator_get_enable_read_voltage(dev, "avdd");
+ if (ret == -ENODEV || ret == -EINVAL) {
+ int ret2;
+
+ /*
+ * We get -EINVAL if avdd is a supply with unknown voltage. We
+ * still need to enable it since it is also a power supply.
+ */
+ ret2 = devm_regulator_get_enable(dev, "avdd");
+ if (ret2)
+ return dev_err_probe(dev, ret2,
+ "Failed to enable AVDD supply\n");
+ } else if (ret < 0) {
+ return dev_err_probe(dev, ret, "Failed to get AVDD voltage\n");
}
- ret = devm_add_action_or_reset(&spi->dev, ad7192_reg_disable, st->avdd);
- if (ret)
- return ret;
+ avdd_mv = ret == -ENODEV || ret == -EINVAL ? 0 : ret / MILLI;
- ret = devm_regulator_get_enable(&spi->dev, "dvdd");
+ ret = devm_regulator_get_enable(dev, "dvdd");
if (ret)
- return dev_err_probe(&spi->dev, ret, "Failed to enable specified DVdd supply\n");
-
- st->vref = devm_regulator_get_optional(&spi->dev, "vref");
- if (IS_ERR(st->vref)) {
- if (PTR_ERR(st->vref) != -ENODEV)
- return PTR_ERR(st->vref);
-
- ret = regulator_get_voltage(st->avdd);
- if (ret < 0)
- return dev_err_probe(&spi->dev, ret,
- "Device tree error, AVdd voltage undefined\n");
- } else {
- ret = regulator_enable(st->vref);
- if (ret) {
- dev_err(&spi->dev, "Failed to enable specified Vref supply\n");
- return ret;
- }
-
- ret = devm_add_action_or_reset(&spi->dev, ad7192_reg_disable, st->vref);
- if (ret)
- return ret;
+ return dev_err_probe(dev, ret, "Failed to enable specified DVdd supply\n");
- ret = regulator_get_voltage(st->vref);
- if (ret < 0)
- return dev_err_probe(&spi->dev, ret,
- "Device tree error, Vref voltage undefined\n");
+ /*
+ * This is either REFIN1 or REFIN2 depending on adi,refin2-pins-enable.
+ * If this supply is not present, fall back to AVDD as reference.
+ */
+ ret = devm_regulator_get_enable_read_voltage(dev, "vref");
+ if (ret == -ENODEV) {
+ if (avdd_mv == 0)
+ return dev_err_probe(dev, -ENODEV,
+ "No reference voltage available\n");
+ } else if (ret < 0) {
+ return ret;
}
- st->int_vref_mv = ret / 1000;
+
+ st->int_vref_mv = ret == -ENODEV ? avdd_mv : ret / MILLI;
st->chip_info = spi_get_device_match_data(spi);
indio_dev->name = st->chip_info->name;
@@ -1305,13 +1271,13 @@ static int ad7192_probe(struct spi_device *spi)
if (ret)
return ret;
- ret = devm_ad_sd_setup_buffer_and_trigger(&spi->dev, indio_dev);
+ ret = devm_ad_sd_setup_buffer_and_trigger(dev, indio_dev);
if (ret)
return ret;
st->fclk = AD7192_INT_FREQ_MHZ;
- st->mclk = devm_clk_get_optional_enabled(&spi->dev, "mclk");
+ st->mclk = devm_clk_get_optional_enabled(dev, "mclk");
if (IS_ERR(st->mclk))
return PTR_ERR(st->mclk);
@@ -1320,18 +1286,16 @@ static int ad7192_probe(struct spi_device *spi)
if (st->clock_sel == AD7192_CLK_EXT_MCLK1_2 ||
st->clock_sel == AD7192_CLK_EXT_MCLK2) {
st->fclk = clk_get_rate(st->mclk);
- if (!ad7192_valid_external_frequency(st->fclk)) {
- dev_err(&spi->dev,
- "External clock frequency out of bounds\n");
- return -EINVAL;
- }
+ if (!ad7192_valid_external_frequency(st->fclk))
+ return dev_err_probe(dev, -EINVAL,
+ "External clock frequency out of bounds\n");
}
- ret = ad7192_setup(indio_dev, &spi->dev);
+ ret = ad7192_setup(indio_dev, dev);
if (ret)
return ret;
- return devm_iio_device_register(&spi->dev, indio_dev);
+ return devm_iio_device_register(dev, indio_dev);
}
static const struct of_device_id ad7192_of_match[] = {
diff --git a/drivers/iio/adc/ad7266.c b/drivers/iio/adc/ad7266.c
index 13ea8a1073d2..bdac020045b4 100644
--- a/drivers/iio/adc/ad7266.c
+++ b/drivers/iio/adc/ad7266.c
@@ -23,9 +23,10 @@
#include <linux/platform_data/ad7266.h>
+#define AD7266_INTERNAL_REF_MV 2500
+
struct ad7266_state {
struct spi_device *spi;
- struct regulator *reg;
unsigned long vref_mv;
struct spi_transfer single_xfer[3];
@@ -379,11 +380,6 @@ static const char * const ad7266_gpio_labels[] = {
"ad0", "ad1", "ad2",
};
-static void ad7266_reg_disable(void *reg)
-{
- regulator_disable(reg);
-}
-
static int ad7266_probe(struct spi_device *spi)
{
struct ad7266_platform_data *pdata = spi->dev.platform_data;
@@ -398,28 +394,11 @@ static int ad7266_probe(struct spi_device *spi)
st = iio_priv(indio_dev);
- st->reg = devm_regulator_get_optional(&spi->dev, "vref");
- if (!IS_ERR(st->reg)) {
- ret = regulator_enable(st->reg);
- if (ret)
- return ret;
-
- ret = devm_add_action_or_reset(&spi->dev, ad7266_reg_disable, st->reg);
- if (ret)
- return ret;
-
- ret = regulator_get_voltage(st->reg);
- if (ret < 0)
- return ret;
+ ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref");
+ if (ret < 0 && ret != -ENODEV)
+ return ret;
- st->vref_mv = ret / 1000;
- } else {
- /* Any other error indicates that the regulator does exist */
- if (PTR_ERR(st->reg) != -ENODEV)
- return PTR_ERR(st->reg);
- /* Use internal reference */
- st->vref_mv = 2500;
- }
+ st->vref_mv = ret == -ENODEV ? AD7266_INTERNAL_REF_MV : ret / 1000;
if (pdata) {
st->fixed_addr = pdata->fixed_addr;
diff --git a/drivers/iio/adc/ad7292.c b/drivers/iio/adc/ad7292.c
index 6aadd14f459d..ede80f380911 100644
--- a/drivers/iio/adc/ad7292.c
+++ b/drivers/iio/adc/ad7292.c
@@ -17,6 +17,8 @@
#define ADI_VENDOR_ID 0x0018
+#define AD7292_INTERNAL_REF_MV 1250
+
/* AD7292 registers definition */
#define AD7292_REG_VENDOR_ID 0x00
#define AD7292_REG_CONF_BANK 0x05
@@ -79,7 +81,6 @@ static const struct iio_chan_spec ad7292_channels_diff[] = {
struct ad7292_state {
struct spi_device *spi;
- struct regulator *reg;
unsigned short vref_mv;
__be16 d16 __aligned(IIO_DMA_MINALIGN);
@@ -250,13 +251,6 @@ static const struct iio_info ad7292_info = {
.read_raw = ad7292_read_raw,
};
-static void ad7292_regulator_disable(void *data)
-{
- struct ad7292_state *st = data;
-
- regulator_disable(st->reg);
-}
-
static int ad7292_probe(struct spi_device *spi)
{
struct ad7292_state *st;
@@ -277,29 +271,11 @@ static int ad7292_probe(struct spi_device *spi)
return -EINVAL;
}
- st->reg = devm_regulator_get_optional(&spi->dev, "vref");
- if (!IS_ERR(st->reg)) {
- ret = regulator_enable(st->reg);
- if (ret) {
- dev_err(&spi->dev,
- "Failed to enable external vref supply\n");
- return ret;
- }
-
- ret = devm_add_action_or_reset(&spi->dev,
- ad7292_regulator_disable, st);
- if (ret)
- return ret;
-
- ret = regulator_get_voltage(st->reg);
- if (ret < 0)
- return ret;
+ ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref");
+ if (ret < 0 && ret != -ENODEV)
+ return ret;
- st->vref_mv = ret / 1000;
- } else {
- /* Use the internal voltage reference. */
- st->vref_mv = 1250;
- }
+ st->vref_mv = ret == -ENODEV ? AD7292_INTERNAL_REF_MV : ret / 1000;
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->modes = INDIO_DIRECT_MODE;
diff --git a/drivers/iio/adc/ad7793.c b/drivers/iio/adc/ad7793.c
index 5f8cb9aaac70..d4ad7e0b515a 100644
--- a/drivers/iio/adc/ad7793.c
+++ b/drivers/iio/adc/ad7793.c
@@ -152,7 +152,6 @@ struct ad7793_chip_info {
struct ad7793_state {
const struct ad7793_chip_info *chip_info;
- struct regulator *reg;
u16 int_vref_mv;
u16 mode;
u16 conf;
@@ -769,11 +768,6 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
},
};
-static void ad7793_reg_disable(void *reg)
-{
- regulator_disable(reg);
-}
-
static int ad7793_probe(struct spi_device *spi)
{
const struct ad7793_platform_data *pdata = spi->dev.platform_data;
@@ -800,23 +794,11 @@ static int ad7793_probe(struct spi_device *spi)
ad_sd_init(&st->sd, indio_dev, spi, &ad7793_sigma_delta_info);
if (pdata->refsel != AD7793_REFSEL_INTERNAL) {
- st->reg = devm_regulator_get(&spi->dev, "refin");
- if (IS_ERR(st->reg))
- return PTR_ERR(st->reg);
-
- ret = regulator_enable(st->reg);
- if (ret)
- return ret;
-
- ret = devm_add_action_or_reset(&spi->dev, ad7793_reg_disable, st->reg);
- if (ret)
+ ret = devm_regulator_get_enable_read_voltage(&spi->dev, "refin");
+ if (ret < 0)
return ret;
- vref_mv = regulator_get_voltage(st->reg);
- if (vref_mv < 0)
- return vref_mv;
-
- vref_mv /= 1000;
+ vref_mv = ret / 1000;
} else {
vref_mv = 1170; /* Build-in ref */
}
diff --git a/drivers/iio/adc/ad7944.c b/drivers/iio/adc/ad7944.c
index e2cb64cef476..0f36138a7144 100644
--- a/drivers/iio/adc/ad7944.c
+++ b/drivers/iio/adc/ad7944.c
@@ -134,18 +134,12 @@ AD7944_DEFINE_CHIP_INFO(ad7985, ad7944, 16, 0);
/* fully differential */
AD7944_DEFINE_CHIP_INFO(ad7986, ad7986, 18, 1);
-static void ad7944_unoptimize_msg(void *msg)
-{
- spi_unoptimize_message(msg);
-}
-
static int ad7944_3wire_cs_mode_init_msg(struct device *dev, struct ad7944_adc *adc,
const struct iio_chan_spec *chan)
{
unsigned int t_conv_ns = adc->always_turbo ? adc->timing_spec->turbo_conv_ns
: adc->timing_spec->conv_ns;
struct spi_transfer *xfers = adc->xfers;
- int ret;
/*
* NB: can get better performance from some SPI controllers if we use
@@ -175,11 +169,7 @@ static int ad7944_3wire_cs_mode_init_msg(struct device *dev, struct ad7944_adc *
spi_message_init_with_transfers(&adc->msg, xfers, 3);
- ret = spi_optimize_message(adc->spi, &adc->msg);
- if (ret)
- return ret;
-
- return devm_add_action_or_reset(dev, ad7944_unoptimize_msg, &adc->msg);
+ return devm_spi_optimize_message(dev, adc->spi, &adc->msg);
}
static int ad7944_4wire_mode_init_msg(struct device *dev, struct ad7944_adc *adc,
@@ -188,7 +178,6 @@ static int ad7944_4wire_mode_init_msg(struct device *dev, struct ad7944_adc *adc
unsigned int t_conv_ns = adc->always_turbo ? adc->timing_spec->turbo_conv_ns
: adc->timing_spec->conv_ns;
struct spi_transfer *xfers = adc->xfers;
- int ret;
/*
* NB: can get better performance from some SPI controllers if we use
@@ -209,11 +198,7 @@ static int ad7944_4wire_mode_init_msg(struct device *dev, struct ad7944_adc *adc
spi_message_init_with_transfers(&adc->msg, xfers, 2);
- ret = spi_optimize_message(adc->spi, &adc->msg);
- if (ret)
- return ret;
-
- return devm_add_action_or_reset(dev, ad7944_unoptimize_msg, &adc->msg);
+ return devm_spi_optimize_message(dev, adc->spi, &adc->msg);
}
static int ad7944_chain_mode_init_msg(struct device *dev, struct ad7944_adc *adc,
@@ -221,7 +206,6 @@ static int ad7944_chain_mode_init_msg(struct device *dev, struct ad7944_adc *adc
u32 n_chain_dev)
{
struct spi_transfer *xfers = adc->xfers;
- int ret;
/*
* NB: SCLK has to be low before we toggle CS to avoid triggering the
@@ -249,11 +233,7 @@ static int ad7944_chain_mode_init_msg(struct device *dev, struct ad7944_adc *adc
spi_message_init_with_transfers(&adc->msg, xfers, 2);
- ret = spi_optimize_message(adc->spi, &adc->msg);
- if (ret)
- return ret;
-
- return devm_add_action_or_reset(dev, ad7944_unoptimize_msg, &adc->msg);
+ return devm_spi_optimize_message(dev, adc->spi, &adc->msg);
}
/**
@@ -464,23 +444,17 @@ static const char * const ad7944_power_supplies[] = {
"avdd", "dvdd", "bvdd", "vio"
};
-static void ad7944_ref_disable(void *ref)
-{
- regulator_disable(ref);
-}
-
static int ad7944_probe(struct spi_device *spi)
{
const struct ad7944_chip_info *chip_info;
struct device *dev = &spi->dev;
struct iio_dev *indio_dev;
struct ad7944_adc *adc;
- bool have_refin = false;
- struct regulator *ref;
+ bool have_refin;
struct iio_chan_spec *chain_chan;
unsigned long *chain_scan_masks;
u32 n_chain_dev;
- int ret;
+ int ret, ref_mv;
indio_dev = devm_iio_device_alloc(dev, sizeof(*adc));
if (!indio_dev)
@@ -531,47 +505,23 @@ static int ad7944_probe(struct spi_device *spi)
* - external reference: REF is connected, REFIN is not connected
*/
- ref = devm_regulator_get_optional(dev, "ref");
- if (IS_ERR(ref)) {
- if (PTR_ERR(ref) != -ENODEV)
- return dev_err_probe(dev, PTR_ERR(ref),
- "failed to get REF supply\n");
+ ret = devm_regulator_get_enable_read_voltage(dev, "ref");
+ if (ret < 0 && ret != -ENODEV)
+ return dev_err_probe(dev, ret, "failed to get REF voltage\n");
- ref = NULL;
- }
+ ref_mv = ret == -ENODEV ? 0 : ret / 1000;
ret = devm_regulator_get_enable_optional(dev, "refin");
- if (ret == 0)
- have_refin = true;
- else if (ret != -ENODEV)
- return dev_err_probe(dev, ret,
- "failed to get and enable REFIN supply\n");
+ if (ret < 0 && ret != -ENODEV)
+ return dev_err_probe(dev, ret, "failed to get REFIN voltage\n");
+
+ have_refin = ret != -ENODEV;
- if (have_refin && ref)
+ if (have_refin && ref_mv)
return dev_err_probe(dev, -EINVAL,
"cannot have both refin and ref supplies\n");
- if (ref) {
- ret = regulator_enable(ref);
- if (ret)
- return dev_err_probe(dev, ret,
- "failed to enable REF supply\n");
-
- ret = devm_add_action_or_reset(dev, ad7944_ref_disable, ref);
- if (ret)
- return ret;
-
- ret = regulator_get_voltage(ref);
- if (ret < 0)
- return dev_err_probe(dev, ret,
- "failed to get REF voltage\n");
-
- /* external reference */
- adc->ref_mv = ret / 1000;
- } else {
- /* internal reference */
- adc->ref_mv = AD7944_INTERNAL_REF_MV;
- }
+ adc->ref_mv = ref_mv ?: AD7944_INTERNAL_REF_MV;
adc->cnv = devm_gpiod_get_optional(dev, "cnv", GPIOD_OUT_LOW);
if (IS_ERR(adc->cnv))
diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c
index a2b87f6b7a07..8c062b0d26e3 100644
--- a/drivers/iio/adc/ad_sigma_delta.c
+++ b/drivers/iio/adc/ad_sigma_delta.c
@@ -321,6 +321,7 @@ out:
sigma_delta->keep_cs_asserted = false;
ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
+ ad_sigma_delta_disable_one(sigma_delta, chan->address);
sigma_delta->bus_locked = false;
spi_bus_unlock(sigma_delta->spi->controller);
iio_device_release_direct_mode(indio_dev);
diff --git a/drivers/iio/adc/adi-axi-adc.c b/drivers/iio/adc/adi-axi-adc.c
index 0f8bd1d75131..21ce7564e83d 100644
--- a/drivers/iio/adc/adi-axi-adc.c
+++ b/drivers/iio/adc/adi-axi-adc.c
@@ -308,7 +308,8 @@ static int adi_axi_adc_probe(struct platform_device *pdev)
st->regmap = devm_regmap_init_mmio(&pdev->dev, base,
&axi_adc_regmap_config);
if (IS_ERR(st->regmap))
- return PTR_ERR(st->regmap);
+ return dev_err_probe(&pdev->dev, PTR_ERR(st->regmap),
+ "failed to init register map\n");
expected_ver = device_get_match_data(&pdev->dev);
if (!expected_ver)
@@ -316,7 +317,8 @@ static int adi_axi_adc_probe(struct platform_device *pdev)
clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(clk))
- return PTR_ERR(clk);
+ return dev_err_probe(&pdev->dev, PTR_ERR(clk),
+ "failed to get clock\n");
/*
* Force disable the core. Up to the frontend to enable us. And we can
@@ -344,7 +346,8 @@ static int adi_axi_adc_probe(struct platform_device *pdev)
ret = devm_iio_backend_register(&pdev->dev, &adi_axi_adc_generic, st);
if (ret)
- return ret;
+ return dev_err_probe(&pdev->dev, ret,
+ "failed to register iio backend\n");
dev_info(&pdev->dev, "AXI ADC IP core (%d.%.2d.%c) probed\n",
ADI_AXI_PCORE_VER_MAJOR(ver),
diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c
index 998e8bcc06e1..090416c0d622 100644
--- a/drivers/iio/adc/aspeed_adc.c
+++ b/drivers/iio/adc/aspeed_adc.c
@@ -108,7 +108,6 @@ struct adc_gain {
struct aspeed_adc_data {
struct device *dev;
const struct aspeed_adc_model_data *model_data;
- struct regulator *regulator;
void __iomem *base;
spinlock_t clk_lock;
struct clk_hw *fixed_div_clk;
@@ -404,13 +403,6 @@ static void aspeed_adc_power_down(void *data)
priv_data->base + ASPEED_REG_ENGINE_CONTROL);
}
-static void aspeed_adc_reg_disable(void *data)
-{
- struct regulator *reg = data;
-
- regulator_disable(reg);
-}
-
static int aspeed_adc_vref_config(struct iio_dev *indio_dev)
{
struct aspeed_adc_data *data = iio_priv(indio_dev);
@@ -423,18 +415,14 @@ static int aspeed_adc_vref_config(struct iio_dev *indio_dev)
}
adc_engine_control_reg_val =
readl(data->base + ASPEED_REG_ENGINE_CONTROL);
- data->regulator = devm_regulator_get_optional(data->dev, "vref");
- if (!IS_ERR(data->regulator)) {
- ret = regulator_enable(data->regulator);
- if (ret)
- return ret;
- ret = devm_add_action_or_reset(
- data->dev, aspeed_adc_reg_disable, data->regulator);
- if (ret)
- return ret;
- data->vref_mv = regulator_get_voltage(data->regulator);
- /* Conversion from uV to mV */
- data->vref_mv /= 1000;
+
+ ret = devm_regulator_get_enable_read_voltage(data->dev, "vref");
+ if (ret < 0 && ret != -ENODEV)
+ return ret;
+
+ if (ret != -ENODEV) {
+ data->vref_mv = ret / 1000;
+
if ((data->vref_mv >= 1550) && (data->vref_mv <= 2700))
writel(adc_engine_control_reg_val |
FIELD_PREP(
@@ -453,8 +441,6 @@ static int aspeed_adc_vref_config(struct iio_dev *indio_dev)
return -EOPNOTSUPP;
}
} else {
- if (PTR_ERR(data->regulator) != -ENODEV)
- return PTR_ERR(data->regulator);
data->vref_mv = 2500000;
of_property_read_u32(data->dev->of_node,
"aspeed,int-vref-microvolt",
diff --git a/drivers/iio/adc/axp20x_adc.c b/drivers/iio/adc/axp20x_adc.c
index 913ea9e5d9c5..b487e577befb 100644
--- a/drivers/iio/adc/axp20x_adc.c
+++ b/drivers/iio/adc/axp20x_adc.c
@@ -991,9 +991,8 @@ static int axp20x_probe(struct platform_device *pdev)
regmap_write(info->regmap, AXP20X_ADC_EN1, info->data->adc_en1_mask);
if (info->data->adc_en2_mask)
- regmap_update_bits(info->regmap, AXP20X_ADC_EN2,
- info->data->adc_en2_mask,
- info->data->adc_en2_mask);
+ regmap_set_bits(info->regmap, AXP20X_ADC_EN2,
+ info->data->adc_en2_mask);
/* Configure ADCs rate */
info->data->adc_rate(info, 100);
diff --git a/drivers/iio/adc/axp288_adc.c b/drivers/iio/adc/axp288_adc.c
index 49fff1cabd0d..f135cf2362df 100644
--- a/drivers/iio/adc/axp288_adc.c
+++ b/drivers/iio/adc/axp288_adc.c
@@ -247,8 +247,8 @@ static int axp288_adc_initialize(struct axp288_adc_info *info)
return ret;
/* Turn on the ADC for all channels except TS, leave TS as is */
- return regmap_update_bits(info->regmap, AXP20X_ADC_EN1,
- AXP288_ADC_EN_MASK, AXP288_ADC_EN_MASK);
+ return regmap_set_bits(info->regmap, AXP20X_ADC_EN1,
+ AXP288_ADC_EN_MASK);
}
static const struct iio_info axp288_adc_iio_info = {
diff --git a/drivers/iio/adc/bcm_iproc_adc.c b/drivers/iio/adc/bcm_iproc_adc.c
index 5bc514bd5ebc..6bc149c51414 100644
--- a/drivers/iio/adc/bcm_iproc_adc.c
+++ b/drivers/iio/adc/bcm_iproc_adc.c
@@ -357,8 +357,8 @@ static int iproc_adc_enable(struct iio_dev *indio_dev)
int ret;
/* Set i_amux = 3b'000, select channel 0 */
- ret = regmap_update_bits(adc_priv->regmap, IPROC_ANALOG_CONTROL,
- IPROC_ADC_CHANNEL_SEL_MASK, 0);
+ ret = regmap_clear_bits(adc_priv->regmap, IPROC_ANALOG_CONTROL,
+ IPROC_ADC_CHANNEL_SEL_MASK);
if (ret) {
dev_err(&indio_dev->dev,
"failed to write IPROC_ANALOG_CONTROL %d\n", ret);
@@ -543,8 +543,8 @@ static int iproc_adc_probe(struct platform_device *pdev)
if (adc_priv->irqno < 0)
return adc_priv->irqno;
- ret = regmap_update_bits(adc_priv->regmap, IPROC_REGCTL2,
- IPROC_ADC_AUXIN_SCAN_ENA, 0);
+ ret = regmap_clear_bits(adc_priv->regmap, IPROC_REGCTL2,
+ IPROC_ADC_AUXIN_SCAN_ENA);
if (ret) {
dev_err(&pdev->dev, "failed to write IPROC_REGCTL2 %d\n", ret);
return ret;
diff --git a/drivers/iio/adc/berlin2-adc.c b/drivers/iio/adc/berlin2-adc.c
index a4e7c7eff5ac..4cdddc6e36e9 100644
--- a/drivers/iio/adc/berlin2-adc.c
+++ b/drivers/iio/adc/berlin2-adc.c
@@ -129,8 +129,8 @@ static int berlin2_adc_read(struct iio_dev *indio_dev, int channel)
msecs_to_jiffies(1000));
/* Disable the interrupts */
- regmap_update_bits(priv->regmap, BERLIN2_SM_ADC_STATUS,
- BERLIN2_SM_ADC_STATUS_INT_EN(channel), 0);
+ regmap_clear_bits(priv->regmap, BERLIN2_SM_ADC_STATUS,
+ BERLIN2_SM_ADC_STATUS_INT_EN(channel));
if (ret == 0)
ret = -ETIMEDOUT;
@@ -139,8 +139,8 @@ static int berlin2_adc_read(struct iio_dev *indio_dev, int channel)
return ret;
}
- regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
- BERLIN2_SM_CTRL_ADC_START, 0);
+ regmap_clear_bits(priv->regmap, BERLIN2_SM_CTRL,
+ BERLIN2_SM_CTRL_ADC_START);
data = priv->data;
priv->data_available = false;
@@ -180,8 +180,8 @@ static int berlin2_adc_tsen_read(struct iio_dev *indio_dev)
msecs_to_jiffies(1000));
/* Disable interrupts */
- regmap_update_bits(priv->regmap, BERLIN2_SM_TSEN_STATUS,
- BERLIN2_SM_TSEN_STATUS_INT_EN, 0);
+ regmap_clear_bits(priv->regmap, BERLIN2_SM_TSEN_STATUS,
+ BERLIN2_SM_TSEN_STATUS_INT_EN);
if (ret == 0)
ret = -ETIMEDOUT;
@@ -190,8 +190,8 @@ static int berlin2_adc_tsen_read(struct iio_dev *indio_dev)
return ret;
}
- regmap_update_bits(priv->regmap, BERLIN2_SM_TSEN_CTRL,
- BERLIN2_SM_TSEN_CTRL_START, 0);
+ regmap_clear_bits(priv->regmap, BERLIN2_SM_TSEN_CTRL,
+ BERLIN2_SM_TSEN_CTRL_START);
data = priv->data;
priv->data_available = false;
@@ -284,8 +284,7 @@ static const struct iio_info berlin2_adc_info = {
static void berlin2_adc_powerdown(void *regmap)
{
- regmap_update_bits(regmap, BERLIN2_SM_CTRL,
- BERLIN2_SM_CTRL_ADC_POWER, 0);
+ regmap_clear_bits(regmap, BERLIN2_SM_CTRL, BERLIN2_SM_CTRL_ADC_POWER);
}
@@ -339,9 +338,8 @@ static int berlin2_adc_probe(struct platform_device *pdev)
indio_dev->num_channels = ARRAY_SIZE(berlin2_adc_channels);
/* Power up the ADC */
- regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
- BERLIN2_SM_CTRL_ADC_POWER,
- BERLIN2_SM_CTRL_ADC_POWER);
+ regmap_set_bits(priv->regmap, BERLIN2_SM_CTRL,
+ BERLIN2_SM_CTRL_ADC_POWER);
ret = devm_add_action_or_reset(&pdev->dev, berlin2_adc_powerdown,
priv->regmap);
diff --git a/drivers/iio/adc/cpcap-adc.c b/drivers/iio/adc/cpcap-adc.c
index b6c4ef70484e..c218acf6c9c6 100644
--- a/drivers/iio/adc/cpcap-adc.c
+++ b/drivers/iio/adc/cpcap-adc.c
@@ -385,9 +385,8 @@ static irqreturn_t cpcap_adc_irq_thread(int irq, void *data)
struct cpcap_adc *ddata = iio_priv(indio_dev);
int error;
- error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2,
- CPCAP_BIT_ADTRIG_DIS,
- CPCAP_BIT_ADTRIG_DIS);
+ error = regmap_set_bits(ddata->reg, CPCAP_REG_ADCC2,
+ CPCAP_BIT_ADTRIG_DIS);
if (error)
return IRQ_NONE;
@@ -424,23 +423,19 @@ static void cpcap_adc_setup_calibrate(struct cpcap_adc *ddata,
if (error)
return;
- error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2,
- CPCAP_BIT_ATOX_PS_FACTOR |
- CPCAP_BIT_ADC_PS_FACTOR1 |
- CPCAP_BIT_ADC_PS_FACTOR0,
- 0);
+ error = regmap_clear_bits(ddata->reg, CPCAP_REG_ADCC2,
+ CPCAP_BIT_ATOX_PS_FACTOR |
+ CPCAP_BIT_ADC_PS_FACTOR1 |
+ CPCAP_BIT_ADC_PS_FACTOR0);
if (error)
return;
- error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2,
- CPCAP_BIT_ADTRIG_DIS,
- CPCAP_BIT_ADTRIG_DIS);
+ error = regmap_set_bits(ddata->reg, CPCAP_REG_ADCC2,
+ CPCAP_BIT_ADTRIG_DIS);
if (error)
return;
- error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2,
- CPCAP_BIT_ASC,
- CPCAP_BIT_ASC);
+ error = regmap_set_bits(ddata->reg, CPCAP_REG_ADCC2, CPCAP_BIT_ASC);
if (error)
return;
@@ -455,8 +450,8 @@ static void cpcap_adc_setup_calibrate(struct cpcap_adc *ddata,
dev_err(ddata->dev,
"Timeout waiting for calibration to complete\n");
- error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC1,
- CPCAP_BIT_CAL_MODE, 0);
+ error = regmap_clear_bits(ddata->reg, CPCAP_REG_ADCC1,
+ CPCAP_BIT_CAL_MODE);
if (error)
return;
}
@@ -602,26 +597,23 @@ static void cpcap_adc_setup_bank(struct cpcap_adc *ddata,
return;
if (req->timing == CPCAP_ADC_TIMING_IMM) {
- error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2,
- CPCAP_BIT_ADTRIG_DIS,
- CPCAP_BIT_ADTRIG_DIS);
+ error = regmap_set_bits(ddata->reg, CPCAP_REG_ADCC2,
+ CPCAP_BIT_ADTRIG_DIS);
if (error)
return;
- error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2,
- CPCAP_BIT_ASC,
- CPCAP_BIT_ASC);
+ error = regmap_set_bits(ddata->reg, CPCAP_REG_ADCC2,
+ CPCAP_BIT_ASC);
if (error)
return;
} else {
- error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2,
- CPCAP_BIT_ADTRIG_ONESHOT,
- CPCAP_BIT_ADTRIG_ONESHOT);
+ error = regmap_set_bits(ddata->reg, CPCAP_REG_ADCC2,
+ CPCAP_BIT_ADTRIG_ONESHOT);
if (error)
return;
- error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2,
- CPCAP_BIT_ADTRIG_DIS, 0);
+ error = regmap_clear_bits(ddata->reg, CPCAP_REG_ADCC2,
+ CPCAP_BIT_ADTRIG_DIS);
if (error)
return;
}
diff --git a/drivers/iio/adc/fsl-imx25-gcq.c b/drivers/iio/adc/fsl-imx25-gcq.c
index b680690631db..b3f037510e35 100644
--- a/drivers/iio/adc/fsl-imx25-gcq.c
+++ b/drivers/iio/adc/fsl-imx25-gcq.c
@@ -87,13 +87,13 @@ static irqreturn_t mx25_gcq_irq(int irq, void *data)
regmap_read(priv->regs, MX25_ADCQ_SR, &stats);
if (stats & MX25_ADCQ_SR_EOQ) {
- regmap_update_bits(priv->regs, MX25_ADCQ_MR,
- MX25_ADCQ_MR_EOQ_IRQ, MX25_ADCQ_MR_EOQ_IRQ);
+ regmap_set_bits(priv->regs, MX25_ADCQ_MR,
+ MX25_ADCQ_MR_EOQ_IRQ);
complete(&priv->completed);
}
/* Disable conversion queue run */
- regmap_update_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_FQS, 0);
+ regmap_clear_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_FQS);
/* Acknowledge all possible irqs */
regmap_write(priv->regs, MX25_ADCQ_SR, MX25_ADCQ_SR_FRR |
@@ -115,11 +115,10 @@ static int mx25_gcq_get_raw_value(struct device *dev,
regmap_write(priv->regs, MX25_ADCQ_ITEM_7_0,
MX25_ADCQ_ITEM(0, chan->channel));
- regmap_update_bits(priv->regs, MX25_ADCQ_MR, MX25_ADCQ_MR_EOQ_IRQ, 0);
+ regmap_clear_bits(priv->regs, MX25_ADCQ_MR, MX25_ADCQ_MR_EOQ_IRQ);
/* Trigger queue for one run */
- regmap_update_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_FQS,
- MX25_ADCQ_CR_FQS);
+ regmap_set_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_FQS);
time_left = wait_for_completion_interruptible_timeout(
&priv->completed, MX25_GCQ_TIMEOUT);
@@ -272,9 +271,8 @@ static int mx25_gcq_setup_cfgs(struct platform_device *pdev,
MX25_ADCQ_CFG_REFN_MASK,
refp | refn);
}
- regmap_update_bits(priv->regs, MX25_ADCQ_CR,
- MX25_ADCQ_CR_FRST | MX25_ADCQ_CR_QRST,
- MX25_ADCQ_CR_FRST | MX25_ADCQ_CR_QRST);
+ regmap_set_bits(priv->regs, MX25_ADCQ_CR,
+ MX25_ADCQ_CR_FRST | MX25_ADCQ_CR_QRST);
regmap_write(priv->regs, MX25_ADCQ_CR,
MX25_ADCQ_CR_PDMSK | MX25_ADCQ_CR_QSM_FQS);
diff --git a/drivers/iio/adc/hx711.c b/drivers/iio/adc/hx711.c
index fef97c1d226a..b3372ccff7d5 100644
--- a/drivers/iio/adc/hx711.c
+++ b/drivers/iio/adc/hx711.c
@@ -80,7 +80,6 @@ struct hx711_data {
struct device *dev;
struct gpio_desc *gpiod_pd_sck;
struct gpio_desc *gpiod_dout;
- struct regulator *reg_avdd;
int gain_set; /* gain set on device */
int gain_chan_a; /* gain for channel A */
struct mutex lock;
@@ -465,10 +464,8 @@ static int hx711_probe(struct platform_device *pdev)
int i;
indio_dev = devm_iio_device_alloc(dev, sizeof(struct hx711_data));
- if (!indio_dev) {
- dev_err(dev, "failed to allocate IIO device\n");
- return -ENOMEM;
- }
+ if (!indio_dev)
+ return dev_err_probe(dev, -ENOMEM, "failed to allocate IIO device\n");
hx711_data = iio_priv(indio_dev);
hx711_data->dev = dev;
@@ -480,28 +477,20 @@ static int hx711_probe(struct platform_device *pdev)
* in the driver it is an output
*/
hx711_data->gpiod_pd_sck = devm_gpiod_get(dev, "sck", GPIOD_OUT_LOW);
- if (IS_ERR(hx711_data->gpiod_pd_sck)) {
- dev_err(dev, "failed to get sck-gpiod: err=%ld\n",
- PTR_ERR(hx711_data->gpiod_pd_sck));
- return PTR_ERR(hx711_data->gpiod_pd_sck);
- }
+ if (IS_ERR(hx711_data->gpiod_pd_sck))
+ return dev_err_probe(dev, PTR_ERR(hx711_data->gpiod_pd_sck),
+ "failed to get sck-gpiod\n");
/*
* DOUT stands for serial data output of HX711
* for the driver it is an input
*/
hx711_data->gpiod_dout = devm_gpiod_get(dev, "dout", GPIOD_IN);
- if (IS_ERR(hx711_data->gpiod_dout)) {
- dev_err(dev, "failed to get dout-gpiod: err=%ld\n",
- PTR_ERR(hx711_data->gpiod_dout));
- return PTR_ERR(hx711_data->gpiod_dout);
- }
+ if (IS_ERR(hx711_data->gpiod_dout))
+ return dev_err_probe(dev, PTR_ERR(hx711_data->gpiod_dout),
+ "failed to get dout-gpiod\n");
- hx711_data->reg_avdd = devm_regulator_get(dev, "avdd");
- if (IS_ERR(hx711_data->reg_avdd))
- return PTR_ERR(hx711_data->reg_avdd);
-
- ret = regulator_enable(hx711_data->reg_avdd);
+ ret = devm_regulator_get_enable_read_voltage(dev, "avdd");
if (ret < 0)
return ret;
@@ -517,9 +506,6 @@ static int hx711_probe(struct platform_device *pdev)
* approximately to fit into a 32 bit number:
* 1 LSB = (AVDD * 100) / GAIN / 1678 [10^-9 mV]
*/
- ret = regulator_get_voltage(hx711_data->reg_avdd);
- if (ret < 0)
- goto error_regulator;
/* we need 10^-9 mV */
ret *= 100;
@@ -547,51 +533,24 @@ static int hx711_probe(struct platform_device *pdev)
hx711_data->data_ready_delay_ns =
1000000000 / hx711_data->clock_frequency;
- platform_set_drvdata(pdev, indio_dev);
-
indio_dev->name = "hx711";
indio_dev->info = &hx711_iio_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = hx711_chan_spec;
indio_dev->num_channels = ARRAY_SIZE(hx711_chan_spec);
- ret = iio_triggered_buffer_setup(indio_dev, iio_pollfunc_store_time,
- hx711_trigger, NULL);
- if (ret < 0) {
- dev_err(dev, "setup of iio triggered buffer failed\n");
- goto error_regulator;
- }
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
+ iio_pollfunc_store_time,
+ hx711_trigger, NULL);
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "setup of iio triggered buffer failed\n");
- ret = iio_device_register(indio_dev);
- if (ret < 0) {
- dev_err(dev, "Couldn't register the device\n");
- goto error_buffer;
- }
+ ret = devm_iio_device_register(dev, indio_dev);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Couldn't register the device\n");
return 0;
-
-error_buffer:
- iio_triggered_buffer_cleanup(indio_dev);
-
-error_regulator:
- regulator_disable(hx711_data->reg_avdd);
-
- return ret;
-}
-
-static void hx711_remove(struct platform_device *pdev)
-{
- struct hx711_data *hx711_data;
- struct iio_dev *indio_dev;
-
- indio_dev = platform_get_drvdata(pdev);
- hx711_data = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
-
- iio_triggered_buffer_cleanup(indio_dev);
-
- regulator_disable(hx711_data->reg_avdd);
}
static const struct of_device_id of_hx711_match[] = {
@@ -603,7 +562,6 @@ MODULE_DEVICE_TABLE(of, of_hx711_match);
static struct platform_driver hx711_driver = {
.probe = hx711_probe,
- .remove_new = hx711_remove,
.driver = {
.name = "hx711-gpio",
.of_match_table = of_hx711_match,
diff --git a/drivers/iio/adc/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c
index 9e52207352fb..727e390bd979 100644
--- a/drivers/iio/adc/ina2xx-adc.c
+++ b/drivers/iio/adc/ina2xx-adc.c
@@ -1046,8 +1046,7 @@ static void ina2xx_remove(struct i2c_client *client)
iio_device_unregister(indio_dev);
/* Powerdown */
- ret = regmap_update_bits(chip->regmap, INA2XX_CONFIG,
- INA2XX_MODE_MASK, 0);
+ ret = regmap_clear_bits(chip->regmap, INA2XX_CONFIG, INA2XX_MODE_MASK);
if (ret)
dev_warn(&client->dev, "Failed to power down device (%pe)\n",
ERR_PTR(ret));
diff --git a/drivers/iio/adc/intel_mrfld_adc.c b/drivers/iio/adc/intel_mrfld_adc.c
index c7f40ae6e608..0590a126f321 100644
--- a/drivers/iio/adc/intel_mrfld_adc.c
+++ b/drivers/iio/adc/intel_mrfld_adc.c
@@ -81,8 +81,8 @@ static int mrfld_adc_single_conv(struct iio_dev *indio_dev,
reinit_completion(&adc->completion);
- regmap_update_bits(regmap, BCOVE_MADCIRQ, BCOVE_ADCIRQ_ALL, 0);
- regmap_update_bits(regmap, BCOVE_MIRQLVL1, BCOVE_LVL1_ADC, 0);
+ regmap_clear_bits(regmap, BCOVE_MADCIRQ, BCOVE_ADCIRQ_ALL);
+ regmap_clear_bits(regmap, BCOVE_MIRQLVL1, BCOVE_LVL1_ADC);
ret = regmap_read_poll_timeout(regmap, BCOVE_GPADCREQ, req,
!(req & BCOVE_GPADCREQ_BUSY),
diff --git a/drivers/iio/adc/ltc2309.c b/drivers/iio/adc/ltc2309.c
index 8b3a89c1b840..5f0d947d0615 100644
--- a/drivers/iio/adc/ltc2309.c
+++ b/drivers/iio/adc/ltc2309.c
@@ -16,6 +16,7 @@
#include <linux/regulator/consumer.h>
#define LTC2309_ADC_RESOLUTION 12
+#define LTC2309_INTERNAL_REF_MV 4096
#define LTC2309_DIN_CH_MASK GENMASK(7, 4)
#define LTC2309_DIN_SDN BIT(7)
@@ -29,14 +30,12 @@
* struct ltc2309 - internal device data structure
* @dev: Device reference
* @client: I2C reference
- * @vref: External reference source
* @lock: Lock to serialize data access
* @vref_mv: Internal voltage reference
*/
struct ltc2309 {
struct device *dev;
struct i2c_client *client;
- struct regulator *vref;
struct mutex lock; /* serialize data access */
int vref_mv;
};
@@ -104,7 +103,7 @@ static int ltc2309_read_raw_channel(struct ltc2309 *ltc2309,
unsigned long address, int *val)
{
int ret;
- u16 buf;
+ __be16 buf;
u8 din;
din = FIELD_PREP(LTC2309_DIN_CH_MASK, address & 0x0f) |
@@ -157,11 +156,6 @@ static const struct iio_info ltc2309_info = {
.read_raw = ltc2309_read_raw,
};
-static void ltc2309_regulator_disable(void *regulator)
-{
- regulator_disable(regulator);
-}
-
static int ltc2309_probe(struct i2c_client *client)
{
struct iio_dev *indio_dev;
@@ -175,7 +169,6 @@ static int ltc2309_probe(struct i2c_client *client)
ltc2309 = iio_priv(indio_dev);
ltc2309->dev = &indio_dev->dev;
ltc2309->client = client;
- ltc2309->vref_mv = 4096; /* Default to the internal ref */
indio_dev->name = "ltc2309";
indio_dev->modes = INDIO_DIRECT_MODE;
@@ -183,36 +176,12 @@ static int ltc2309_probe(struct i2c_client *client)
indio_dev->num_channels = ARRAY_SIZE(ltc2309_channels);
indio_dev->info = &ltc2309_info;
- ltc2309->vref = devm_regulator_get_optional(&client->dev, "vref");
- if (IS_ERR(ltc2309->vref)) {
- ret = PTR_ERR(ltc2309->vref);
- if (ret == -ENODEV)
- ltc2309->vref = NULL;
- else
- return ret;
- }
+ ret = devm_regulator_get_enable_read_voltage(&client->dev, "vref");
+ if (ret < 0 && ret != -ENODEV)
+ return dev_err_probe(ltc2309->dev, ret,
+ "failed to get vref voltage\n");
- if (ltc2309->vref) {
- ret = regulator_enable(ltc2309->vref);
- if (ret)
- return dev_err_probe(ltc2309->dev, ret,
- "failed to enable vref\n");
-
- ret = devm_add_action_or_reset(ltc2309->dev,
- ltc2309_regulator_disable,
- ltc2309->vref);
- if (ret) {
- return dev_err_probe(ltc2309->dev, ret,
- "failed to add regulator_disable action: %d\n",
- ret);
- }
-
- ret = regulator_get_voltage(ltc2309->vref);
- if (ret < 0)
- return ret;
-
- ltc2309->vref_mv = ret / 1000;
- }
+ ltc2309->vref_mv = ret == -ENODEV ? LTC2309_INTERNAL_REF_MV : ret / 1000;
mutex_init(&ltc2309->lock);
diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c
index 8b5bc96cb9fb..bf4b6dc53fd2 100644
--- a/drivers/iio/adc/max1363.c
+++ b/drivers/iio/adc/max1363.c
@@ -1561,18 +1561,12 @@ static const struct of_device_id max1363_of_match[] = {
};
MODULE_DEVICE_TABLE(of, max1363_of_match);
-static void max1363_reg_disable(void *reg)
-{
- regulator_disable(reg);
-}
-
static int max1363_probe(struct i2c_client *client)
{
const struct i2c_device_id *id = i2c_client_get_device_id(client);
int ret;
struct max1363_state *st;
struct iio_dev *indio_dev;
- struct regulator *vref;
indio_dev = devm_iio_device_alloc(&client->dev,
sizeof(struct max1363_state));
@@ -1589,26 +1583,12 @@ static int max1363_probe(struct i2c_client *client)
st->chip_info = i2c_get_match_data(client);
st->client = client;
- st->vref_uv = st->chip_info->int_vref_mv * 1000;
- vref = devm_regulator_get_optional(&client->dev, "vref");
- if (!IS_ERR(vref)) {
- int vref_uv;
-
- ret = regulator_enable(vref);
- if (ret)
- return ret;
-
- ret = devm_add_action_or_reset(&client->dev, max1363_reg_disable, vref);
- if (ret)
- return ret;
+ ret = devm_regulator_get_enable_read_voltage(&client->dev, "vref");
+ if (ret < 0 && ret != -ENODEV)
+ return ret;
- st->vref = vref;
- vref_uv = regulator_get_voltage(vref);
- if (vref_uv <= 0)
- return -EINVAL;
- st->vref_uv = vref_uv;
- }
+ st->vref_uv = ret == -ENODEV ? st->chip_info->int_vref_mv * 1000 : ret;
if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
st->send = i2c_master_send;
diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c
index 13b473d8c6c7..e16b0e28974e 100644
--- a/drivers/iio/adc/meson_saradc.c
+++ b/drivers/iio/adc/meson_saradc.c
@@ -546,35 +546,31 @@ static void meson_sar_adc_start_sample_engine(struct iio_dev *indio_dev)
reinit_completion(&priv->done);
- regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0,
- MESON_SAR_ADC_REG0_FIFO_IRQ_EN,
- MESON_SAR_ADC_REG0_FIFO_IRQ_EN);
+ regmap_set_bits(priv->regmap, MESON_SAR_ADC_REG0,
+ MESON_SAR_ADC_REG0_FIFO_IRQ_EN);
- regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0,
- MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE,
- MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE);
+ regmap_set_bits(priv->regmap, MESON_SAR_ADC_REG0,
+ MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE);
- regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0,
- MESON_SAR_ADC_REG0_SAMPLING_START,
- MESON_SAR_ADC_REG0_SAMPLING_START);
+ regmap_set_bits(priv->regmap, MESON_SAR_ADC_REG0,
+ MESON_SAR_ADC_REG0_SAMPLING_START);
}
static void meson_sar_adc_stop_sample_engine(struct iio_dev *indio_dev)
{
struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
- regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0,
- MESON_SAR_ADC_REG0_FIFO_IRQ_EN, 0);
+ regmap_clear_bits(priv->regmap, MESON_SAR_ADC_REG0,
+ MESON_SAR_ADC_REG0_FIFO_IRQ_EN);
- regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0,
- MESON_SAR_ADC_REG0_SAMPLING_STOP,
- MESON_SAR_ADC_REG0_SAMPLING_STOP);
+ regmap_set_bits(priv->regmap, MESON_SAR_ADC_REG0,
+ MESON_SAR_ADC_REG0_SAMPLING_STOP);
/* wait until all modules are stopped */
meson_sar_adc_wait_busy_clear(indio_dev);
- regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0,
- MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE, 0);
+ regmap_clear_bits(priv->regmap, MESON_SAR_ADC_REG0,
+ MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE);
}
static int meson_sar_adc_lock(struct iio_dev *indio_dev)
@@ -586,9 +582,8 @@ static int meson_sar_adc_lock(struct iio_dev *indio_dev)
if (priv->param->has_bl30_integration) {
/* prevent BL30 from using the SAR ADC while we are using it */
- regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY,
- MESON_SAR_ADC_DELAY_KERNEL_BUSY,
- MESON_SAR_ADC_DELAY_KERNEL_BUSY);
+ regmap_set_bits(priv->regmap, MESON_SAR_ADC_DELAY,
+ MESON_SAR_ADC_DELAY_KERNEL_BUSY);
udelay(1);
@@ -614,8 +609,8 @@ static void meson_sar_adc_unlock(struct iio_dev *indio_dev)
if (priv->param->has_bl30_integration)
/* allow BL30 to use the SAR ADC again */
- regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY,
- MESON_SAR_ADC_DELAY_KERNEL_BUSY, 0);
+ regmap_clear_bits(priv->regmap, MESON_SAR_ADC_DELAY,
+ MESON_SAR_ADC_DELAY_KERNEL_BUSY);
mutex_unlock(&priv->lock);
}
@@ -869,17 +864,16 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev)
* disable this bit as seems to be only relevant for Meson6 (based
* on the vendor driver), which we don't support at the moment.
*/
- regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0,
- MESON_SAR_ADC_REG0_ADC_TEMP_SEN_SEL, 0);
+ regmap_clear_bits(priv->regmap, MESON_SAR_ADC_REG0,
+ MESON_SAR_ADC_REG0_ADC_TEMP_SEN_SEL);
/* disable all channels by default */
regmap_write(priv->regmap, MESON_SAR_ADC_CHAN_LIST, 0x0);
- regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3,
- MESON_SAR_ADC_REG3_CTRL_SAMPLING_CLOCK_PHASE, 0);
- regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3,
- MESON_SAR_ADC_REG3_CNTL_USE_SC_DLY,
- MESON_SAR_ADC_REG3_CNTL_USE_SC_DLY);
+ regmap_clear_bits(priv->regmap, MESON_SAR_ADC_REG3,
+ MESON_SAR_ADC_REG3_CTRL_SAMPLING_CLOCK_PHASE);
+ regmap_set_bits(priv->regmap, MESON_SAR_ADC_REG3,
+ MESON_SAR_ADC_REG3_CNTL_USE_SC_DLY);
/* delay between two samples = (10+1) * 1uS */
regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY,
@@ -914,21 +908,17 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev)
MESON_SAR_ADC_CHAN_10_SW_CHAN1_MUX_SEL_MASK,
regval);
- regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW,
- MESON_SAR_ADC_CHAN_10_SW_CHAN0_XP_DRIVE_SW,
- MESON_SAR_ADC_CHAN_10_SW_CHAN0_XP_DRIVE_SW);
+ regmap_set_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW,
+ MESON_SAR_ADC_CHAN_10_SW_CHAN0_XP_DRIVE_SW);
- regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW,
- MESON_SAR_ADC_CHAN_10_SW_CHAN0_YP_DRIVE_SW,
- MESON_SAR_ADC_CHAN_10_SW_CHAN0_YP_DRIVE_SW);
+ regmap_set_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW,
+ MESON_SAR_ADC_CHAN_10_SW_CHAN0_YP_DRIVE_SW);
- regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW,
- MESON_SAR_ADC_CHAN_10_SW_CHAN1_XP_DRIVE_SW,
- MESON_SAR_ADC_CHAN_10_SW_CHAN1_XP_DRIVE_SW);
+ regmap_set_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW,
+ MESON_SAR_ADC_CHAN_10_SW_CHAN1_XP_DRIVE_SW);
- regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW,
- MESON_SAR_ADC_CHAN_10_SW_CHAN1_YP_DRIVE_SW,
- MESON_SAR_ADC_CHAN_10_SW_CHAN1_YP_DRIVE_SW);
+ regmap_set_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW,
+ MESON_SAR_ADC_CHAN_10_SW_CHAN1_YP_DRIVE_SW);
/*
* set up the input channel muxes in MESON_SAR_ADC_AUX_SW
@@ -944,12 +934,10 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev)
regmap_write(priv->regmap, MESON_SAR_ADC_AUX_SW, regval);
if (priv->temperature_sensor_calibrated) {
- regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10,
- MESON_SAR_ADC_DELTA_10_TS_REVE1,
- MESON_SAR_ADC_DELTA_10_TS_REVE1);
- regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10,
- MESON_SAR_ADC_DELTA_10_TS_REVE0,
- MESON_SAR_ADC_DELTA_10_TS_REVE0);
+ regmap_set_bits(priv->regmap, MESON_SAR_ADC_DELTA_10,
+ MESON_SAR_ADC_DELTA_10_TS_REVE1);
+ regmap_set_bits(priv->regmap, MESON_SAR_ADC_DELTA_10,
+ MESON_SAR_ADC_DELTA_10_TS_REVE0);
/*
* set bits [3:0] of the TSC (temperature sensor coefficient)
@@ -976,10 +964,10 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev)
regval);
}
} else {
- regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10,
- MESON_SAR_ADC_DELTA_10_TS_REVE1, 0);
- regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10,
- MESON_SAR_ADC_DELTA_10_TS_REVE0, 0);
+ regmap_clear_bits(priv->regmap, MESON_SAR_ADC_DELTA_10,
+ MESON_SAR_ADC_DELTA_10_TS_REVE1);
+ regmap_clear_bits(priv->regmap, MESON_SAR_ADC_DELTA_10,
+ MESON_SAR_ADC_DELTA_10_TS_REVE0);
}
regval = FIELD_PREP(MESON_SAR_ADC_REG3_CTRL_CONT_RING_COUNTER_EN,
@@ -1062,9 +1050,8 @@ static int meson_sar_adc_hw_enable(struct iio_dev *indio_dev)
meson_sar_adc_set_bandgap(indio_dev, true);
- regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3,
- MESON_SAR_ADC_REG3_ADC_EN,
- MESON_SAR_ADC_REG3_ADC_EN);
+ regmap_set_bits(priv->regmap, MESON_SAR_ADC_REG3,
+ MESON_SAR_ADC_REG3_ADC_EN);
udelay(5);
@@ -1079,8 +1066,8 @@ static int meson_sar_adc_hw_enable(struct iio_dev *indio_dev)
return 0;
err_adc_clk:
- regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3,
- MESON_SAR_ADC_REG3_ADC_EN, 0);
+ regmap_clear_bits(priv->regmap, MESON_SAR_ADC_REG3,
+ MESON_SAR_ADC_REG3_ADC_EN);
meson_sar_adc_set_bandgap(indio_dev, false);
regulator_disable(priv->vref);
err_vref:
@@ -1104,8 +1091,8 @@ static void meson_sar_adc_hw_disable(struct iio_dev *indio_dev)
clk_disable_unprepare(priv->adc_clk);
- regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3,
- MESON_SAR_ADC_REG3_ADC_EN, 0);
+ regmap_clear_bits(priv->regmap, MESON_SAR_ADC_REG3,
+ MESON_SAR_ADC_REG3_ADC_EN);
meson_sar_adc_set_bandgap(indio_dev, false);
diff --git a/drivers/iio/adc/mp2629_adc.c b/drivers/iio/adc/mp2629_adc.c
index 7c66c2cd5be2..5f672765d4a2 100644
--- a/drivers/iio/adc/mp2629_adc.c
+++ b/drivers/iio/adc/mp2629_adc.c
@@ -131,9 +131,8 @@ static int mp2629_adc_probe(struct platform_device *pdev)
info->dev = dev;
platform_set_drvdata(pdev, indio_dev);
- ret = regmap_update_bits(info->regmap, MP2629_REG_ADC_CTRL,
- MP2629_ADC_START | MP2629_ADC_CONTINUOUS,
- MP2629_ADC_START | MP2629_ADC_CONTINUOUS);
+ ret = regmap_set_bits(info->regmap, MP2629_REG_ADC_CTRL,
+ MP2629_ADC_START | MP2629_ADC_CONTINUOUS);
if (ret) {
dev_err(dev, "adc enable fail: %d\n", ret);
return ret;
@@ -163,10 +162,9 @@ fail_map_unregister:
iio_map_array_unregister(indio_dev);
fail_disable:
- regmap_update_bits(info->regmap, MP2629_REG_ADC_CTRL,
- MP2629_ADC_CONTINUOUS, 0);
- regmap_update_bits(info->regmap, MP2629_REG_ADC_CTRL,
- MP2629_ADC_START, 0);
+ regmap_clear_bits(info->regmap, MP2629_REG_ADC_CTRL,
+ MP2629_ADC_CONTINUOUS);
+ regmap_clear_bits(info->regmap, MP2629_REG_ADC_CTRL, MP2629_ADC_START);
return ret;
}
@@ -180,10 +178,9 @@ static void mp2629_adc_remove(struct platform_device *pdev)
iio_map_array_unregister(indio_dev);
- regmap_update_bits(info->regmap, MP2629_REG_ADC_CTRL,
- MP2629_ADC_CONTINUOUS, 0);
- regmap_update_bits(info->regmap, MP2629_REG_ADC_CTRL,
- MP2629_ADC_START, 0);
+ regmap_clear_bits(info->regmap, MP2629_REG_ADC_CTRL,
+ MP2629_ADC_CONTINUOUS);
+ regmap_clear_bits(info->regmap, MP2629_REG_ADC_CTRL, MP2629_ADC_START);
}
static const struct of_device_id mp2629_adc_of_match[] = {
diff --git a/drivers/iio/adc/mt6359-auxadc.c b/drivers/iio/adc/mt6359-auxadc.c
new file mode 100644
index 000000000000..a4970cfb49a5
--- /dev/null
+++ b/drivers/iio/adc/mt6359-auxadc.c
@@ -0,0 +1,606 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * MediaTek MT6359 PMIC AUXADC IIO driver
+ *
+ * Copyright (c) 2021 MediaTek Inc.
+ * Copyright (c) 2024 Collabora Ltd
+ * Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+ */
+
+#include <linux/bits.h>
+#include <linux/cleanup.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+
+#include <linux/iio/iio.h>
+
+#include <linux/mfd/mt6397/core.h>
+
+#include <dt-bindings/iio/adc/mediatek,mt6357-auxadc.h>
+#include <dt-bindings/iio/adc/mediatek,mt6358-auxadc.h>
+#include <dt-bindings/iio/adc/mediatek,mt6359-auxadc.h>
+
+#define AUXADC_AVG_TIME_US 10
+#define AUXADC_POLL_DELAY_US 100
+#define AUXADC_TIMEOUT_US 32000
+#define AUXADC_VOLT_FULL 1800
+#define IMP_STOP_DELAY_US 150
+#define IMP_POLL_DELAY_US 1000
+
+/* For PMIC_RG_RESET_VAL and MT6358_IMP0_CLEAR, the bits specific purpose is unknown. */
+#define PMIC_RG_RESET_VAL (BIT(0) | BIT(3))
+#define PMIC_AUXADC_RDY_BIT BIT(15)
+#define MT6357_IMP_ADC_NUM 30
+#define MT6358_IMP_ADC_NUM 28
+
+#define MT6358_DCM_CK_SW_EN GENMASK(1, 0)
+#define MT6358_IMP0_CLEAR (BIT(14) | BIT(7))
+#define MT6358_IMP0_IRQ_RDY BIT(8)
+#define MT6358_IMP1_AUTOREPEAT_EN BIT(15)
+
+#define MT6359_IMP0_CONV_EN BIT(0)
+#define MT6359_IMP1_IRQ_RDY BIT(15)
+
+enum mtk_pmic_auxadc_regs {
+ PMIC_AUXADC_ADC0,
+ PMIC_AUXADC_DCM_CON,
+ PMIC_AUXADC_IMP0,
+ PMIC_AUXADC_IMP1,
+ PMIC_AUXADC_IMP3,
+ PMIC_AUXADC_RQST0,
+ PMIC_AUXADC_RQST1,
+ PMIC_HK_TOP_WKEY,
+ PMIC_HK_TOP_RST_CON0,
+ PMIC_FGADC_R_CON0,
+ PMIC_AUXADC_REGS_MAX
+};
+
+enum mtk_pmic_auxadc_channels {
+ PMIC_AUXADC_CHAN_BATADC,
+ PMIC_AUXADC_CHAN_ISENSE,
+ PMIC_AUXADC_CHAN_VCDT,
+ PMIC_AUXADC_CHAN_BAT_TEMP,
+ PMIC_AUXADC_CHAN_BATID,
+ PMIC_AUXADC_CHAN_CHIP_TEMP,
+ PMIC_AUXADC_CHAN_VCORE_TEMP,
+ PMIC_AUXADC_CHAN_VPROC_TEMP,
+ PMIC_AUXADC_CHAN_VGPU_TEMP,
+ PMIC_AUXADC_CHAN_ACCDET,
+ PMIC_AUXADC_CHAN_VDCXO,
+ PMIC_AUXADC_CHAN_TSX_TEMP,
+ PMIC_AUXADC_CHAN_HPOFS_CAL,
+ PMIC_AUXADC_CHAN_DCXO_TEMP,
+ PMIC_AUXADC_CHAN_VBIF,
+ PMIC_AUXADC_CHAN_IBAT,
+ PMIC_AUXADC_CHAN_VBAT,
+ PMIC_AUXADC_CHAN_MAX
+};
+
+/**
+ * struct mt6359_auxadc - Main driver structure
+ * @dev: Device pointer
+ * @regmap: Regmap from SoC PMIC Wrapper
+ * @chip_info: PMIC specific chip info
+ * @lock: Mutex to serialize AUXADC reading vs configuration
+ * @timed_out: Signals whether the last read timed out
+ */
+struct mt6359_auxadc {
+ struct device *dev;
+ struct regmap *regmap;
+ const struct mtk_pmic_auxadc_info *chip_info;
+ struct mutex lock;
+ bool timed_out;
+};
+
+/**
+ * struct mtk_pmic_auxadc_chan - PMIC AUXADC channel data
+ * @req_idx: Request register number
+ * @req_mask: Bitmask to activate a channel
+ * @num_samples: Number of AUXADC samples for averaging
+ * @r_ratio: Resistance ratio fractional
+ */
+struct mtk_pmic_auxadc_chan {
+ u8 req_idx;
+ u16 req_mask;
+ u16 num_samples;
+ struct u8_fract r_ratio;
+};
+
+/**
+ * struct mtk_pmic_auxadc_info - PMIC specific chip info
+ * @model_name: PMIC model name
+ * @channels: IIO specification of ADC channels
+ * @num_channels: Number of ADC channels
+ * @desc: PMIC AUXADC channel data
+ * @regs: List of PMIC specific registers
+ * @sec_unlock_key: Security unlock key for HK_TOP writes
+ * @imp_adc_num: ADC channel for battery impedance readings
+ * @read_imp: Callback to read impedance channels
+ */
+struct mtk_pmic_auxadc_info {
+ const char *model_name;
+ const struct iio_chan_spec *channels;
+ u8 num_channels;
+ const struct mtk_pmic_auxadc_chan *desc;
+ const u16 *regs;
+ u16 sec_unlock_key;
+ u8 imp_adc_num;
+ int (*read_imp)(struct mt6359_auxadc *adc_dev, int *vbat, int *ibat);
+};
+
+#define MTK_PMIC_ADC_CHAN(_ch_idx, _req_idx, _req_bit, _samples, _rnum, _rdiv) \
+ [PMIC_AUXADC_CHAN_##_ch_idx] = { \
+ .req_idx = _req_idx, \
+ .req_mask = BIT(_req_bit), \
+ .num_samples = _samples, \
+ .r_ratio = { _rnum, _rdiv } \
+ }
+
+#define MTK_PMIC_IIO_CHAN(_model, _name, _ch_idx, _adc_idx, _nbits, _ch_type) \
+{ \
+ .type = _ch_type, \
+ .channel = _model##_AUXADC_##_ch_idx, \
+ .address = _adc_idx, \
+ .scan_index = PMIC_AUXADC_CHAN_##_ch_idx, \
+ .datasheet_name = __stringify(_name), \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = _nbits, \
+ .storagebits = 16, \
+ .endianness = IIO_CPU \
+ }, \
+ .indexed = 1, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE) \
+}
+
+static const struct iio_chan_spec mt6357_auxadc_channels[] = {
+ MTK_PMIC_IIO_CHAN(MT6357, bat_adc, BATADC, 0, 15, IIO_RESISTANCE),
+ MTK_PMIC_IIO_CHAN(MT6357, isense, ISENSE, 1, 12, IIO_CURRENT),
+ MTK_PMIC_IIO_CHAN(MT6357, cdt_v, VCDT, 2, 12, IIO_TEMP),
+ MTK_PMIC_IIO_CHAN(MT6357, batt_temp, BAT_TEMP, 3, 12, IIO_TEMP),
+ MTK_PMIC_IIO_CHAN(MT6357, chip_temp, CHIP_TEMP, 4, 12, IIO_TEMP),
+ MTK_PMIC_IIO_CHAN(MT6357, acc_det, ACCDET, 5, 12, IIO_RESISTANCE),
+ MTK_PMIC_IIO_CHAN(MT6357, dcxo_v, VDCXO, 6, 12, IIO_VOLTAGE),
+ MTK_PMIC_IIO_CHAN(MT6357, tsx_temp, TSX_TEMP, 7, 15, IIO_TEMP),
+ MTK_PMIC_IIO_CHAN(MT6357, hp_ofs_cal, HPOFS_CAL, 9, 15, IIO_RESISTANCE),
+ MTK_PMIC_IIO_CHAN(MT6357, dcxo_temp, DCXO_TEMP, 36, 15, IIO_TEMP),
+ MTK_PMIC_IIO_CHAN(MT6357, vcore_temp, VCORE_TEMP, 40, 12, IIO_TEMP),
+ MTK_PMIC_IIO_CHAN(MT6357, vproc_temp, VPROC_TEMP, 41, 12, IIO_TEMP),
+
+ /* Battery impedance channels */
+ MTK_PMIC_IIO_CHAN(MT6357, batt_v, VBAT, 0, 15, IIO_VOLTAGE),
+};
+
+static const struct mtk_pmic_auxadc_chan mt6357_auxadc_ch_desc[] = {
+ MTK_PMIC_ADC_CHAN(BATADC, PMIC_AUXADC_RQST0, 0, 128, 3, 1),
+ MTK_PMIC_ADC_CHAN(ISENSE, PMIC_AUXADC_RQST0, 0, 128, 3, 1),
+ MTK_PMIC_ADC_CHAN(VCDT, PMIC_AUXADC_RQST0, 0, 8, 1, 1),
+ MTK_PMIC_ADC_CHAN(BAT_TEMP, PMIC_AUXADC_RQST0, 3, 8, 1, 1),
+ MTK_PMIC_ADC_CHAN(CHIP_TEMP, PMIC_AUXADC_RQST0, 4, 8, 1, 1),
+ MTK_PMIC_ADC_CHAN(ACCDET, PMIC_AUXADC_RQST0, 5, 8, 1, 1),
+ MTK_PMIC_ADC_CHAN(TSX_TEMP, PMIC_AUXADC_RQST0, 7, 128, 1, 1),
+ MTK_PMIC_ADC_CHAN(HPOFS_CAL, PMIC_AUXADC_RQST0, 9, 256, 1, 1),
+ MTK_PMIC_ADC_CHAN(DCXO_TEMP, PMIC_AUXADC_RQST0, 10, 16, 1, 1),
+ MTK_PMIC_ADC_CHAN(VBIF, PMIC_AUXADC_RQST0, 11, 8, 1, 1),
+ MTK_PMIC_ADC_CHAN(VCORE_TEMP, PMIC_AUXADC_RQST1, 5, 8, 1, 1),
+ MTK_PMIC_ADC_CHAN(VPROC_TEMP, PMIC_AUXADC_RQST1, 6, 8, 1, 1),
+
+ /* Battery impedance channels */
+ MTK_PMIC_ADC_CHAN(VBAT, 0, 0, 128, 3, 1),
+};
+
+static const u16 mt6357_auxadc_regs[] = {
+ [PMIC_HK_TOP_RST_CON0] = 0x0f90,
+ [PMIC_AUXADC_DCM_CON] = 0x122e,
+ [PMIC_AUXADC_ADC0] = 0x1088,
+ [PMIC_AUXADC_IMP0] = 0x119c,
+ [PMIC_AUXADC_IMP1] = 0x119e,
+ [PMIC_AUXADC_RQST0] = 0x110e,
+ [PMIC_AUXADC_RQST1] = 0x1114,
+};
+
+static const struct iio_chan_spec mt6358_auxadc_channels[] = {
+ MTK_PMIC_IIO_CHAN(MT6358, bat_adc, BATADC, 0, 15, IIO_RESISTANCE),
+ MTK_PMIC_IIO_CHAN(MT6358, cdt_v, VCDT, 2, 12, IIO_TEMP),
+ MTK_PMIC_IIO_CHAN(MT6358, batt_temp, BAT_TEMP, 3, 12, IIO_TEMP),
+ MTK_PMIC_IIO_CHAN(MT6358, chip_temp, CHIP_TEMP, 4, 12, IIO_TEMP),
+ MTK_PMIC_IIO_CHAN(MT6358, acc_det, ACCDET, 5, 12, IIO_RESISTANCE),
+ MTK_PMIC_IIO_CHAN(MT6358, dcxo_v, VDCXO, 6, 12, IIO_VOLTAGE),
+ MTK_PMIC_IIO_CHAN(MT6358, tsx_temp, TSX_TEMP, 7, 15, IIO_TEMP),
+ MTK_PMIC_IIO_CHAN(MT6358, hp_ofs_cal, HPOFS_CAL, 9, 15, IIO_RESISTANCE),
+ MTK_PMIC_IIO_CHAN(MT6358, dcxo_temp, DCXO_TEMP, 10, 15, IIO_TEMP),
+ MTK_PMIC_IIO_CHAN(MT6358, bif_v, VBIF, 11, 12, IIO_VOLTAGE),
+ MTK_PMIC_IIO_CHAN(MT6358, vcore_temp, VCORE_TEMP, 38, 12, IIO_TEMP),
+ MTK_PMIC_IIO_CHAN(MT6358, vproc_temp, VPROC_TEMP, 39, 12, IIO_TEMP),
+ MTK_PMIC_IIO_CHAN(MT6358, vgpu_temp, VGPU_TEMP, 40, 12, IIO_TEMP),
+
+ /* Battery impedance channels */
+ MTK_PMIC_IIO_CHAN(MT6358, batt_v, VBAT, 0, 15, IIO_VOLTAGE),
+};
+
+static const struct mtk_pmic_auxadc_chan mt6358_auxadc_ch_desc[] = {
+ MTK_PMIC_ADC_CHAN(BATADC, PMIC_AUXADC_RQST0, 0, 128, 3, 1),
+ MTK_PMIC_ADC_CHAN(VCDT, PMIC_AUXADC_RQST0, 0, 8, 1, 1),
+ MTK_PMIC_ADC_CHAN(BAT_TEMP, PMIC_AUXADC_RQST0, 3, 8, 2, 1),
+ MTK_PMIC_ADC_CHAN(CHIP_TEMP, PMIC_AUXADC_RQST0, 4, 8, 1, 1),
+ MTK_PMIC_ADC_CHAN(ACCDET, PMIC_AUXADC_RQST0, 5, 8, 1, 1),
+ MTK_PMIC_ADC_CHAN(VDCXO, PMIC_AUXADC_RQST0, 6, 8, 3, 2),
+ MTK_PMIC_ADC_CHAN(TSX_TEMP, PMIC_AUXADC_RQST0, 7, 128, 1, 1),
+ MTK_PMIC_ADC_CHAN(HPOFS_CAL, PMIC_AUXADC_RQST0, 9, 256, 1, 1),
+ MTK_PMIC_ADC_CHAN(DCXO_TEMP, PMIC_AUXADC_RQST0, 10, 16, 1, 1),
+ MTK_PMIC_ADC_CHAN(VBIF, PMIC_AUXADC_RQST0, 11, 8, 2, 1),
+ MTK_PMIC_ADC_CHAN(VCORE_TEMP, PMIC_AUXADC_RQST1, 8, 8, 1, 1),
+ MTK_PMIC_ADC_CHAN(VPROC_TEMP, PMIC_AUXADC_RQST1, 9, 8, 1, 1),
+ MTK_PMIC_ADC_CHAN(VGPU_TEMP, PMIC_AUXADC_RQST1, 10, 8, 1, 1),
+
+ /* Battery impedance channels */
+ MTK_PMIC_ADC_CHAN(VBAT, 0, 0, 128, 7, 2),
+};
+
+static const u16 mt6358_auxadc_regs[] = {
+ [PMIC_HK_TOP_RST_CON0] = 0x0f90,
+ [PMIC_AUXADC_DCM_CON] = 0x1260,
+ [PMIC_AUXADC_ADC0] = 0x1088,
+ [PMIC_AUXADC_IMP0] = 0x1208,
+ [PMIC_AUXADC_IMP1] = 0x120a,
+ [PMIC_AUXADC_RQST0] = 0x1108,
+ [PMIC_AUXADC_RQST1] = 0x110a,
+};
+
+static const struct iio_chan_spec mt6359_auxadc_channels[] = {
+ MTK_PMIC_IIO_CHAN(MT6359, bat_adc, BATADC, 0, 15, IIO_RESISTANCE),
+ MTK_PMIC_IIO_CHAN(MT6359, batt_temp, BAT_TEMP, 3, 12, IIO_TEMP),
+ MTK_PMIC_IIO_CHAN(MT6359, chip_temp, CHIP_TEMP, 4, 12, IIO_TEMP),
+ MTK_PMIC_IIO_CHAN(MT6359, acc_det, ACCDET, 5, 12, IIO_RESISTANCE),
+ MTK_PMIC_IIO_CHAN(MT6359, dcxo_v, VDCXO, 6, 12, IIO_VOLTAGE),
+ MTK_PMIC_IIO_CHAN(MT6359, tsx_temp, TSX_TEMP, 7, 15, IIO_TEMP),
+ MTK_PMIC_IIO_CHAN(MT6359, hp_ofs_cal, HPOFS_CAL, 9, 15, IIO_RESISTANCE),
+ MTK_PMIC_IIO_CHAN(MT6359, dcxo_temp, DCXO_TEMP, 10, 15, IIO_TEMP),
+ MTK_PMIC_IIO_CHAN(MT6359, bif_v, VBIF, 11, 12, IIO_VOLTAGE),
+ MTK_PMIC_IIO_CHAN(MT6359, vcore_temp, VCORE_TEMP, 30, 12, IIO_TEMP),
+ MTK_PMIC_IIO_CHAN(MT6359, vproc_temp, VPROC_TEMP, 31, 12, IIO_TEMP),
+ MTK_PMIC_IIO_CHAN(MT6359, vgpu_temp, VGPU_TEMP, 32, 12, IIO_TEMP),
+
+ /* Battery impedance channels */
+ MTK_PMIC_IIO_CHAN(MT6359, batt_v, VBAT, 0, 15, IIO_VOLTAGE),
+ MTK_PMIC_IIO_CHAN(MT6359, batt_i, IBAT, 0, 15, IIO_CURRENT),
+};
+
+static const struct mtk_pmic_auxadc_chan mt6359_auxadc_ch_desc[] = {
+ MTK_PMIC_ADC_CHAN(BATADC, PMIC_AUXADC_RQST0, 0, 128, 7, 2),
+ MTK_PMIC_ADC_CHAN(BAT_TEMP, PMIC_AUXADC_RQST0, 3, 8, 5, 2),
+ MTK_PMIC_ADC_CHAN(CHIP_TEMP, PMIC_AUXADC_RQST0, 4, 8, 1, 1),
+ MTK_PMIC_ADC_CHAN(ACCDET, PMIC_AUXADC_RQST0, 5, 8, 1, 1),
+ MTK_PMIC_ADC_CHAN(VDCXO, PMIC_AUXADC_RQST0, 6, 8, 3, 2),
+ MTK_PMIC_ADC_CHAN(TSX_TEMP, PMIC_AUXADC_RQST0, 7, 128, 1, 1),
+ MTK_PMIC_ADC_CHAN(HPOFS_CAL, PMIC_AUXADC_RQST0, 9, 256, 1, 1),
+ MTK_PMIC_ADC_CHAN(DCXO_TEMP, PMIC_AUXADC_RQST0, 10, 16, 1, 1),
+ MTK_PMIC_ADC_CHAN(VBIF, PMIC_AUXADC_RQST0, 11, 8, 5, 2),
+ MTK_PMIC_ADC_CHAN(VCORE_TEMP, PMIC_AUXADC_RQST1, 8, 8, 1, 1),
+ MTK_PMIC_ADC_CHAN(VPROC_TEMP, PMIC_AUXADC_RQST1, 9, 8, 1, 1),
+ MTK_PMIC_ADC_CHAN(VGPU_TEMP, PMIC_AUXADC_RQST1, 10, 8, 1, 1),
+
+ /* Battery impedance channels */
+ MTK_PMIC_ADC_CHAN(VBAT, 0, 0, 128, 7, 2),
+ MTK_PMIC_ADC_CHAN(IBAT, 0, 0, 128, 7, 2),
+};
+
+static const u16 mt6359_auxadc_regs[] = {
+ [PMIC_FGADC_R_CON0] = 0x0d88,
+ [PMIC_HK_TOP_WKEY] = 0x0fb4,
+ [PMIC_HK_TOP_RST_CON0] = 0x0f90,
+ [PMIC_AUXADC_RQST0] = 0x1108,
+ [PMIC_AUXADC_RQST1] = 0x110a,
+ [PMIC_AUXADC_ADC0] = 0x1088,
+ [PMIC_AUXADC_IMP0] = 0x1208,
+ [PMIC_AUXADC_IMP1] = 0x120a,
+ [PMIC_AUXADC_IMP3] = 0x120e,
+};
+
+static void mt6358_stop_imp_conv(struct mt6359_auxadc *adc_dev)
+{
+ const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info;
+ struct regmap *regmap = adc_dev->regmap;
+
+ regmap_set_bits(regmap, cinfo->regs[PMIC_AUXADC_IMP0], MT6358_IMP0_CLEAR);
+ regmap_clear_bits(regmap, cinfo->regs[PMIC_AUXADC_IMP0], MT6358_IMP0_CLEAR);
+ regmap_clear_bits(regmap, cinfo->regs[PMIC_AUXADC_IMP1], MT6358_IMP1_AUTOREPEAT_EN);
+ regmap_clear_bits(regmap, cinfo->regs[PMIC_AUXADC_DCM_CON], MT6358_DCM_CK_SW_EN);
+}
+
+static int mt6358_start_imp_conv(struct mt6359_auxadc *adc_dev)
+{
+ const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info;
+ struct regmap *regmap = adc_dev->regmap;
+ u32 val;
+ int ret;
+
+ regmap_set_bits(regmap, cinfo->regs[PMIC_AUXADC_DCM_CON], MT6358_DCM_CK_SW_EN);
+ regmap_set_bits(regmap, cinfo->regs[PMIC_AUXADC_IMP1], MT6358_IMP1_AUTOREPEAT_EN);
+
+ ret = regmap_read_poll_timeout(adc_dev->regmap, cinfo->regs[PMIC_AUXADC_IMP0],
+ val, val & MT6358_IMP0_IRQ_RDY,
+ IMP_POLL_DELAY_US, AUXADC_TIMEOUT_US);
+ if (ret) {
+ mt6358_stop_imp_conv(adc_dev);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mt6358_read_imp(struct mt6359_auxadc *adc_dev, int *vbat, int *ibat)
+{
+ const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info;
+ struct regmap *regmap = adc_dev->regmap;
+ u16 reg_adc0 = cinfo->regs[PMIC_AUXADC_ADC0];
+ u32 val_v;
+ int ret;
+
+ ret = mt6358_start_imp_conv(adc_dev);
+ if (ret)
+ return ret;
+
+ /* Read the params before stopping */
+ regmap_read(regmap, reg_adc0 + (cinfo->imp_adc_num << 1), &val_v);
+
+ mt6358_stop_imp_conv(adc_dev);
+
+ if (vbat)
+ *vbat = val_v;
+ if (ibat)
+ *ibat = 0;
+
+ return 0;
+}
+
+static int mt6359_read_imp(struct mt6359_auxadc *adc_dev, int *vbat, int *ibat)
+{
+ const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info;
+ struct regmap *regmap = adc_dev->regmap;
+ u32 val, val_v, val_i;
+ int ret;
+
+ /* Start conversion */
+ regmap_write(regmap, cinfo->regs[PMIC_AUXADC_IMP0], MT6359_IMP0_CONV_EN);
+ ret = regmap_read_poll_timeout(regmap, cinfo->regs[PMIC_AUXADC_IMP1],
+ val, val & MT6359_IMP1_IRQ_RDY,
+ IMP_POLL_DELAY_US, AUXADC_TIMEOUT_US);
+
+ /* Stop conversion regardless of the result */
+ regmap_write(regmap, cinfo->regs[PMIC_AUXADC_IMP0], 0);
+ if (ret)
+ return ret;
+
+ /* If it succeeded, wait for the registers to be populated */
+ fsleep(IMP_STOP_DELAY_US);
+
+ ret = regmap_read(regmap, cinfo->regs[PMIC_AUXADC_IMP3], &val_v);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(regmap, cinfo->regs[PMIC_FGADC_R_CON0], &val_i);
+ if (ret)
+ return ret;
+
+ if (vbat)
+ *vbat = val_v;
+ if (ibat)
+ *ibat = val_i;
+
+ return 0;
+}
+
+static const struct mtk_pmic_auxadc_info mt6357_chip_info = {
+ .model_name = "MT6357",
+ .channels = mt6357_auxadc_channels,
+ .num_channels = ARRAY_SIZE(mt6357_auxadc_channels),
+ .desc = mt6357_auxadc_ch_desc,
+ .regs = mt6357_auxadc_regs,
+ .imp_adc_num = MT6357_IMP_ADC_NUM,
+ .read_imp = mt6358_read_imp,
+};
+
+static const struct mtk_pmic_auxadc_info mt6358_chip_info = {
+ .model_name = "MT6358",
+ .channels = mt6358_auxadc_channels,
+ .num_channels = ARRAY_SIZE(mt6358_auxadc_channels),
+ .desc = mt6358_auxadc_ch_desc,
+ .regs = mt6358_auxadc_regs,
+ .imp_adc_num = MT6358_IMP_ADC_NUM,
+ .read_imp = mt6358_read_imp,
+};
+
+static const struct mtk_pmic_auxadc_info mt6359_chip_info = {
+ .model_name = "MT6359",
+ .channels = mt6359_auxadc_channels,
+ .num_channels = ARRAY_SIZE(mt6359_auxadc_channels),
+ .desc = mt6359_auxadc_ch_desc,
+ .regs = mt6359_auxadc_regs,
+ .sec_unlock_key = 0x6359,
+ .read_imp = mt6359_read_imp,
+};
+
+static void mt6359_auxadc_reset(struct mt6359_auxadc *adc_dev)
+{
+ const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info;
+ struct regmap *regmap = adc_dev->regmap;
+
+ /* Unlock HK_TOP writes */
+ if (cinfo->sec_unlock_key)
+ regmap_write(regmap, cinfo->regs[PMIC_HK_TOP_WKEY], cinfo->sec_unlock_key);
+
+ /* Assert ADC reset */
+ regmap_set_bits(regmap, cinfo->regs[PMIC_HK_TOP_RST_CON0], PMIC_RG_RESET_VAL);
+
+ /* De-assert ADC reset. No wait required, as pwrap takes care of that for us. */
+ regmap_clear_bits(regmap, cinfo->regs[PMIC_HK_TOP_RST_CON0], PMIC_RG_RESET_VAL);
+
+ /* Lock HK_TOP writes again */
+ if (cinfo->sec_unlock_key)
+ regmap_write(regmap, cinfo->regs[PMIC_HK_TOP_WKEY], 0);
+}
+
+static int mt6359_auxadc_read_adc(struct mt6359_auxadc *adc_dev,
+ const struct iio_chan_spec *chan, int *out)
+{
+ const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info;
+ const struct mtk_pmic_auxadc_chan *desc = &cinfo->desc[chan->scan_index];
+ struct regmap *regmap = adc_dev->regmap;
+ u32 val;
+ int ret;
+
+ /* Request to start sampling for ADC channel */
+ ret = regmap_write(regmap, cinfo->regs[desc->req_idx], desc->req_mask);
+ if (ret)
+ return ret;
+
+ /* Wait until all samples are averaged */
+ fsleep(desc->num_samples * AUXADC_AVG_TIME_US);
+
+ ret = regmap_read_poll_timeout(regmap,
+ cinfo->regs[PMIC_AUXADC_ADC0] + (chan->address << 1),
+ val, val & PMIC_AUXADC_RDY_BIT,
+ AUXADC_POLL_DELAY_US, AUXADC_TIMEOUT_US);
+ if (ret)
+ return ret;
+
+ /* Stop sampling */
+ regmap_write(regmap, cinfo->regs[desc->req_idx], 0);
+
+ *out = val & GENMASK(chan->scan_type.realbits - 1, 0);
+ return 0;
+}
+
+static int mt6359_auxadc_read_label(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, char *label)
+{
+ return sysfs_emit(label, "%s\n", chan->datasheet_name);
+}
+
+static int mt6359_auxadc_read_raw(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ int *val, int *val2, long mask)
+{
+ struct mt6359_auxadc *adc_dev = iio_priv(indio_dev);
+ const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info;
+ const struct mtk_pmic_auxadc_chan *desc = &cinfo->desc[chan->scan_index];
+ int ret;
+
+ if (mask == IIO_CHAN_INFO_SCALE) {
+ *val = desc->r_ratio.numerator * AUXADC_VOLT_FULL;
+
+ if (desc->r_ratio.denominator > 1) {
+ *val2 = desc->r_ratio.denominator;
+ return IIO_VAL_FRACTIONAL;
+ }
+
+ return IIO_VAL_INT;
+ }
+
+ scoped_guard(mutex, &adc_dev->lock) {
+ switch (chan->scan_index) {
+ case PMIC_AUXADC_CHAN_IBAT:
+ ret = adc_dev->chip_info->read_imp(adc_dev, NULL, val);
+ break;
+ case PMIC_AUXADC_CHAN_VBAT:
+ ret = adc_dev->chip_info->read_imp(adc_dev, val, NULL);
+ break;
+ default:
+ ret = mt6359_auxadc_read_adc(adc_dev, chan, val);
+ break;
+ }
+ }
+
+ if (ret) {
+ /*
+ * If we get more than one timeout, it's possible that the
+ * AUXADC is stuck: perform a full reset to recover it.
+ */
+ if (ret == -ETIMEDOUT) {
+ if (adc_dev->timed_out) {
+ dev_warn(adc_dev->dev, "Resetting stuck ADC!\r\n");
+ mt6359_auxadc_reset(adc_dev);
+ }
+ adc_dev->timed_out = true;
+ }
+ return ret;
+ }
+ adc_dev->timed_out = false;
+
+ return IIO_VAL_INT;
+}
+
+static const struct iio_info mt6359_auxadc_iio_info = {
+ .read_label = mt6359_auxadc_read_label,
+ .read_raw = mt6359_auxadc_read_raw,
+};
+
+static int mt6359_auxadc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device *mt6397_mfd_dev = dev->parent;
+ struct mt6359_auxadc *adc_dev;
+ struct iio_dev *indio_dev;
+ struct regmap *regmap;
+ int ret;
+
+ /* Regmap is from SoC PMIC Wrapper, parent of the mt6397 MFD */
+ regmap = dev_get_regmap(mt6397_mfd_dev->parent, NULL);
+ if (!regmap)
+ return dev_err_probe(dev, -ENODEV, "Failed to get regmap\n");
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*adc_dev));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ adc_dev = iio_priv(indio_dev);
+ adc_dev->regmap = regmap;
+ adc_dev->dev = dev;
+
+ adc_dev->chip_info = device_get_match_data(dev);
+ if (!adc_dev->chip_info)
+ return -EINVAL;
+
+ mutex_init(&adc_dev->lock);
+
+ mt6359_auxadc_reset(adc_dev);
+
+ indio_dev->name = adc_dev->chip_info->model_name;
+ indio_dev->info = &mt6359_auxadc_iio_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = adc_dev->chip_info->channels;
+ indio_dev->num_channels = adc_dev->chip_info->num_channels;
+
+ ret = devm_iio_device_register(dev, indio_dev);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to register iio device\n");
+
+ return 0;
+}
+
+static const struct of_device_id mt6359_auxadc_of_match[] = {
+ { .compatible = "mediatek,mt6357-auxadc", .data = &mt6357_chip_info },
+ { .compatible = "mediatek,mt6358-auxadc", .data = &mt6358_chip_info },
+ { .compatible = "mediatek,mt6359-auxadc", .data = &mt6359_chip_info },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mt6359_auxadc_of_match);
+
+static struct platform_driver mt6359_auxadc_driver = {
+ .driver = {
+ .name = "mt6359-auxadc",
+ .of_match_table = mt6359_auxadc_of_match,
+ },
+ .probe = mt6359_auxadc_probe,
+};
+module_platform_driver(mt6359_auxadc_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>");
+MODULE_DESCRIPTION("MediaTek MT6359 PMIC AUXADC Driver");
diff --git a/drivers/iio/adc/qcom-spmi-rradc.c b/drivers/iio/adc/qcom-spmi-rradc.c
index 56a713766954..1402df68dd52 100644
--- a/drivers/iio/adc/qcom-spmi-rradc.c
+++ b/drivers/iio/adc/qcom-spmi-rradc.c
@@ -358,15 +358,15 @@ static int rradc_enable_continuous_mode(struct rradc_chip *chip)
int ret;
/* Clear channel log */
- ret = regmap_update_bits(chip->regmap, chip->base + RR_ADC_LOG,
- RR_ADC_LOG_CLR_CTRL, RR_ADC_LOG_CLR_CTRL);
+ ret = regmap_set_bits(chip->regmap, chip->base + RR_ADC_LOG,
+ RR_ADC_LOG_CLR_CTRL);
if (ret < 0) {
dev_err(chip->dev, "log ctrl update to clear failed:%d\n", ret);
return ret;
}
- ret = regmap_update_bits(chip->regmap, chip->base + RR_ADC_LOG,
- RR_ADC_LOG_CLR_CTRL, 0);
+ ret = regmap_clear_bits(chip->regmap, chip->base + RR_ADC_LOG,
+ RR_ADC_LOG_CLR_CTRL);
if (ret < 0) {
dev_err(chip->dev, "log ctrl update to not clear failed:%d\n",
ret);
@@ -374,9 +374,8 @@ static int rradc_enable_continuous_mode(struct rradc_chip *chip)
}
/* Switch to continuous mode */
- ret = regmap_update_bits(chip->regmap, chip->base + RR_ADC_CTL,
- RR_ADC_CTL_CONTINUOUS_SEL,
- RR_ADC_CTL_CONTINUOUS_SEL);
+ ret = regmap_set_bits(chip->regmap, chip->base + RR_ADC_CTL,
+ RR_ADC_CTL_CONTINUOUS_SEL);
if (ret < 0)
dev_err(chip->dev, "Update to continuous mode failed:%d\n",
ret);
@@ -389,8 +388,8 @@ static int rradc_disable_continuous_mode(struct rradc_chip *chip)
int ret;
/* Switch to non continuous mode */
- ret = regmap_update_bits(chip->regmap, chip->base + RR_ADC_CTL,
- RR_ADC_CTL_CONTINUOUS_SEL, 0);
+ ret = regmap_clear_bits(chip->regmap, chip->base + RR_ADC_CTL,
+ RR_ADC_CTL_CONTINUOUS_SEL);
if (ret < 0)
dev_err(chip->dev, "Update to non-continuous mode failed:%d\n",
ret);
@@ -434,8 +433,8 @@ static int rradc_read_status_in_cont_mode(struct rradc_chip *chip,
return -EINVAL;
}
- ret = regmap_update_bits(chip->regmap, chip->base + chan->trigger_addr,
- chan->trigger_mask, chan->trigger_mask);
+ ret = regmap_set_bits(chip->regmap, chip->base + chan->trigger_addr,
+ chan->trigger_mask);
if (ret < 0) {
dev_err(chip->dev,
"Failed to apply trigger for channel '%s' ret=%d\n",
@@ -469,8 +468,8 @@ static int rradc_read_status_in_cont_mode(struct rradc_chip *chip,
rradc_disable_continuous_mode(chip);
disable_trigger:
- regmap_update_bits(chip->regmap, chip->base + chan->trigger_addr,
- chan->trigger_mask, 0);
+ regmap_clear_bits(chip->regmap, chip->base + chan->trigger_addr,
+ chan->trigger_mask);
return ret;
}
@@ -481,17 +480,16 @@ static int rradc_prepare_batt_id_conversion(struct rradc_chip *chip,
{
int ret;
- ret = regmap_update_bits(chip->regmap, chip->base + RR_ADC_BATT_ID_CTRL,
- RR_ADC_BATT_ID_CTRL_CHANNEL_CONV,
- RR_ADC_BATT_ID_CTRL_CHANNEL_CONV);
+ ret = regmap_set_bits(chip->regmap, chip->base + RR_ADC_BATT_ID_CTRL,
+ RR_ADC_BATT_ID_CTRL_CHANNEL_CONV);
if (ret < 0) {
dev_err(chip->dev, "Enabling BATT ID channel failed:%d\n", ret);
return ret;
}
- ret = regmap_update_bits(chip->regmap,
- chip->base + RR_ADC_BATT_ID_TRIGGER,
- RR_ADC_TRIGGER_CTL, RR_ADC_TRIGGER_CTL);
+ ret = regmap_set_bits(chip->regmap,
+ chip->base + RR_ADC_BATT_ID_TRIGGER,
+ RR_ADC_TRIGGER_CTL);
if (ret < 0) {
dev_err(chip->dev, "BATT_ID trigger set failed:%d\n", ret);
goto out_disable_batt_id;
@@ -500,12 +498,12 @@ static int rradc_prepare_batt_id_conversion(struct rradc_chip *chip,
ret = rradc_read_status_in_cont_mode(chip, chan_address);
/* Reset registers back to default values */
- regmap_update_bits(chip->regmap, chip->base + RR_ADC_BATT_ID_TRIGGER,
- RR_ADC_TRIGGER_CTL, 0);
+ regmap_clear_bits(chip->regmap, chip->base + RR_ADC_BATT_ID_TRIGGER,
+ RR_ADC_TRIGGER_CTL);
out_disable_batt_id:
- regmap_update_bits(chip->regmap, chip->base + RR_ADC_BATT_ID_CTRL,
- RR_ADC_BATT_ID_CTRL_CHANNEL_CONV, 0);
+ regmap_clear_bits(chip->regmap, chip->base + RR_ADC_BATT_ID_CTRL,
+ RR_ADC_BATT_ID_CTRL_CHANNEL_CONV);
return ret;
}
@@ -965,9 +963,9 @@ static int rradc_probe(struct platform_device *pdev)
if (batt_id_delay >= 0) {
batt_id_delay = FIELD_PREP(BATT_ID_SETTLE_MASK, batt_id_delay);
- ret = regmap_update_bits(chip->regmap,
- chip->base + RR_ADC_BATT_ID_CFG,
- batt_id_delay, batt_id_delay);
+ ret = regmap_set_bits(chip->regmap,
+ chip->base + RR_ADC_BATT_ID_CFG,
+ batt_id_delay);
if (ret < 0) {
dev_err(chip->dev,
"BATT_ID settling time config failed:%d\n",
diff --git a/drivers/iio/adc/rn5t618-adc.c b/drivers/iio/adc/rn5t618-adc.c
index 6bf32907f01d..ce5f3011fe00 100644
--- a/drivers/iio/adc/rn5t618-adc.c
+++ b/drivers/iio/adc/rn5t618-adc.c
@@ -137,9 +137,8 @@ static int rn5t618_adc_read(struct iio_dev *iio_dev,
init_completion(&adc->conv_completion);
/* single conversion */
- ret = regmap_update_bits(adc->rn5t618->regmap, RN5T618_ADCCNT3,
- RN5T618_ADCCNT3_GODONE,
- RN5T618_ADCCNT3_GODONE);
+ ret = regmap_set_bits(adc->rn5t618->regmap, RN5T618_ADCCNT3,
+ RN5T618_ADCCNT3_GODONE);
if (ret < 0)
return ret;
diff --git a/drivers/iio/adc/sc27xx_adc.c b/drivers/iio/adc/sc27xx_adc.c
index b4a2e057d80f..2535c2c3e60b 100644
--- a/drivers/iio/adc/sc27xx_adc.c
+++ b/drivers/iio/adc/sc27xx_adc.c
@@ -508,13 +508,13 @@ static int sc27xx_adc_read(struct sc27xx_adc_data *data, int channel,
}
}
- ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_CTL,
- SC27XX_ADC_EN, SC27XX_ADC_EN);
+ ret = regmap_set_bits(data->regmap, data->base + SC27XX_ADC_CTL,
+ SC27XX_ADC_EN);
if (ret)
goto regulator_restore;
- ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_INT_CLR,
- SC27XX_ADC_IRQ_CLR, SC27XX_ADC_IRQ_CLR);
+ ret = regmap_set_bits(data->regmap, data->base + SC27XX_ADC_INT_CLR,
+ SC27XX_ADC_IRQ_CLR);
if (ret)
goto disable_adc;
@@ -537,8 +537,8 @@ static int sc27xx_adc_read(struct sc27xx_adc_data *data, int channel,
if (ret)
goto disable_adc;
- ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_CTL,
- SC27XX_ADC_CHN_RUN, SC27XX_ADC_CHN_RUN);
+ ret = regmap_set_bits(data->regmap, data->base + SC27XX_ADC_CTL,
+ SC27XX_ADC_CHN_RUN);
if (ret)
goto disable_adc;
@@ -559,8 +559,8 @@ static int sc27xx_adc_read(struct sc27xx_adc_data *data, int channel,
value &= SC27XX_ADC_DATA_MASK;
disable_adc:
- regmap_update_bits(data->regmap, data->base + SC27XX_ADC_CTL,
- SC27XX_ADC_EN, 0);
+ regmap_clear_bits(data->regmap, data->base + SC27XX_ADC_CTL,
+ SC27XX_ADC_EN);
regulator_restore:
if ((data->var_data->set_volref) && (channel == 30 || channel == 31)) {
ret_volref = regulator_set_voltage(data->volref,
@@ -765,15 +765,14 @@ static int sc27xx_adc_enable(struct sc27xx_adc_data *data)
{
int ret;
- ret = regmap_update_bits(data->regmap, data->var_data->module_en,
- SC27XX_MODULE_ADC_EN, SC27XX_MODULE_ADC_EN);
+ ret = regmap_set_bits(data->regmap, data->var_data->module_en,
+ SC27XX_MODULE_ADC_EN);
if (ret)
return ret;
/* Enable ADC work clock and controller clock */
- ret = regmap_update_bits(data->regmap, data->var_data->clk_en,
- SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN,
- SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN);
+ ret = regmap_set_bits(data->regmap, data->var_data->clk_en,
+ SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN);
if (ret)
goto disable_adc;
@@ -789,11 +788,11 @@ static int sc27xx_adc_enable(struct sc27xx_adc_data *data)
return 0;
disable_clk:
- regmap_update_bits(data->regmap, data->var_data->clk_en,
- SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN, 0);
+ regmap_clear_bits(data->regmap, data->var_data->clk_en,
+ SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN);
disable_adc:
- regmap_update_bits(data->regmap, data->var_data->module_en,
- SC27XX_MODULE_ADC_EN, 0);
+ regmap_clear_bits(data->regmap, data->var_data->module_en,
+ SC27XX_MODULE_ADC_EN);
return ret;
}
@@ -803,11 +802,11 @@ static void sc27xx_adc_disable(void *_data)
struct sc27xx_adc_data *data = _data;
/* Disable ADC work clock and controller clock */
- regmap_update_bits(data->regmap, data->var_data->clk_en,
- SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN, 0);
+ regmap_clear_bits(data->regmap, data->var_data->clk_en,
+ SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN);
- regmap_update_bits(data->regmap, data->var_data->module_en,
- SC27XX_MODULE_ADC_EN, 0);
+ regmap_clear_bits(data->regmap, data->var_data->module_en,
+ SC27XX_MODULE_ADC_EN);
}
static const struct sc27xx_adc_variant_data sc2731_data = {
diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c
index 9a47d2c87f05..fabd654245f5 100644
--- a/drivers/iio/adc/stm32-dfsdm-adc.c
+++ b/drivers/iio/adc/stm32-dfsdm-adc.c
@@ -759,8 +759,7 @@ static int stm32_dfsdm_start_conv(struct iio_dev *indio_dev,
return 0;
filter_unconfigure:
- regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id),
- DFSDM_CR1_CFG_MASK, 0);
+ regmap_clear_bits(regmap, DFSDM_CR1(adc->fl_id), DFSDM_CR1_CFG_MASK);
stop_channels:
stm32_dfsdm_stop_channel(indio_dev);
@@ -774,8 +773,7 @@ static void stm32_dfsdm_stop_conv(struct iio_dev *indio_dev)
stm32_dfsdm_stop_filter(adc->dfsdm, adc->fl_id);
- regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id),
- DFSDM_CR1_CFG_MASK, 0);
+ regmap_clear_bits(regmap, DFSDM_CR1(adc->fl_id), DFSDM_CR1_CFG_MASK);
stm32_dfsdm_stop_channel(indio_dev);
}
@@ -951,16 +949,14 @@ static int stm32_dfsdm_adc_dma_start(struct iio_dev *indio_dev)
if (adc->nconv == 1 && !indio_dev->trig) {
/* Enable regular DMA transfer*/
- ret = regmap_update_bits(adc->dfsdm->regmap,
- DFSDM_CR1(adc->fl_id),
- DFSDM_CR1_RDMAEN_MASK,
- DFSDM_CR1_RDMAEN_MASK);
+ ret = regmap_set_bits(adc->dfsdm->regmap,
+ DFSDM_CR1(adc->fl_id),
+ DFSDM_CR1_RDMAEN_MASK);
} else {
/* Enable injected DMA transfer*/
- ret = regmap_update_bits(adc->dfsdm->regmap,
- DFSDM_CR1(adc->fl_id),
- DFSDM_CR1_JDMAEN_MASK,
- DFSDM_CR1_JDMAEN_MASK);
+ ret = regmap_set_bits(adc->dfsdm->regmap,
+ DFSDM_CR1(adc->fl_id),
+ DFSDM_CR1_JDMAEN_MASK);
}
if (ret < 0)
@@ -981,8 +977,8 @@ static void stm32_dfsdm_adc_dma_stop(struct iio_dev *indio_dev)
if (!adc->dma_chan)
return;
- regmap_update_bits(adc->dfsdm->regmap, DFSDM_CR1(adc->fl_id),
- DFSDM_CR1_RDMAEN_MASK | DFSDM_CR1_JDMAEN_MASK, 0);
+ regmap_clear_bits(adc->dfsdm->regmap, DFSDM_CR1(adc->fl_id),
+ DFSDM_CR1_RDMAEN_MASK | DFSDM_CR1_JDMAEN_MASK);
dmaengine_terminate_all(adc->dma_chan);
}
@@ -1305,9 +1301,8 @@ static irqreturn_t stm32_dfsdm_irq(int irq, void *arg)
if (status & DFSDM_ISR_ROVRF_MASK) {
if (int_en & DFSDM_CR2_ROVRIE_MASK)
dev_warn(&indio_dev->dev, "Overrun detected\n");
- regmap_update_bits(regmap, DFSDM_ICR(adc->fl_id),
- DFSDM_ICR_CLRROVRF_MASK,
- DFSDM_ICR_CLRROVRF_MASK);
+ regmap_set_bits(regmap, DFSDM_ICR(adc->fl_id),
+ DFSDM_ICR_CLRROVRF_MASK);
}
return IRQ_HANDLED;
diff --git a/drivers/iio/adc/ti-adc108s102.c b/drivers/iio/adc/ti-adc108s102.c
index 69fcbbc7e418..9758ac801310 100644
--- a/drivers/iio/adc/ti-adc108s102.c
+++ b/drivers/iio/adc/ti-adc108s102.c
@@ -58,7 +58,6 @@
struct adc108s102_state {
struct spi_device *spi;
- struct regulator *reg;
u32 va_millivolt;
/* SPI transfer used by triggered buffer handler*/
struct spi_transfer ring_xfer;
@@ -216,11 +215,6 @@ static const struct iio_info adc108s102_info = {
.update_scan_mode = &adc108s102_update_scan_mode,
};
-static void adc108s102_reg_disable(void *reg)
-{
- regulator_disable(reg);
-}
-
static int adc108s102_probe(struct spi_device *spi)
{
struct adc108s102_state *st;
@@ -236,25 +230,9 @@ static int adc108s102_probe(struct spi_device *spi)
if (ACPI_COMPANION(&spi->dev)) {
st->va_millivolt = ADC108S102_VA_MV_ACPI_DEFAULT;
} else {
- st->reg = devm_regulator_get(&spi->dev, "vref");
- if (IS_ERR(st->reg))
- return PTR_ERR(st->reg);
-
- ret = regulator_enable(st->reg);
- if (ret < 0) {
- dev_err(&spi->dev, "Cannot enable vref regulator\n");
- return ret;
- }
- ret = devm_add_action_or_reset(&spi->dev, adc108s102_reg_disable,
- st->reg);
- if (ret)
- return ret;
-
- ret = regulator_get_voltage(st->reg);
- if (ret < 0) {
- dev_err(&spi->dev, "vref get voltage failed\n");
- return ret;
- }
+ ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref");
+ if (ret < 0)
+ return dev_err_probe(&spi->dev, ret, "failed get vref voltage\n");
st->va_millivolt = ret / 1000;
}
diff --git a/drivers/iio/adc/ti-ads1119.c b/drivers/iio/adc/ti-ads1119.c
new file mode 100644
index 000000000000..630f5d5f9a60
--- /dev/null
+++ b/drivers/iio/adc/ti-ads1119.c
@@ -0,0 +1,825 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Texas Instruments ADS1119 ADC driver.
+ *
+ * Copyright 2024 Toradex
+ */
+
+#include <linux/bits.h>
+#include <linux/bitfield.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/dev_printk.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/iopoll.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/math.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/units.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
+
+#define ADS1119_CMD_RESET 0x06
+#define ADS1119_CMD_POWERDOWN 0x02
+#define ADS1119_CMD_START_SYNC 0x08
+#define ADS1119_CMD_RDATA 0x10
+#define ADS1119_CMD_RREG_CONFIG 0x20
+#define ADS1119_CMD_RREG_STATUS 0x24
+#define ADS1119_CMD_WREG 0x40
+
+#define ADS1119_CMD_RREG(reg) (0x20 | (reg) << 2)
+
+/* Config register */
+#define ADS1119_REG_CONFIG 0x00
+#define ADS1119_CONFIG_VREF_FIELD BIT(0)
+#define ADS1119_CONFIG_CM_FIELD BIT(1)
+#define ADS1119_CONFIG_DR_FIELD GENMASK(3, 2)
+#define ADS1119_CONFIG_GAIN_FIELD BIT(4)
+#define ADS1119_CONFIG_MUX_FIELD GENMASK(7, 5)
+
+#define ADS1119_VREF_INTERNAL 0
+#define ADS1119_VREF_EXTERNAL 1
+#define ADS1119_VREF_INTERNAL_VAL 2048000
+
+#define ADS1119_CM_SINGLE 0
+#define ADS1119_CM_CONTINUOUS 1
+
+#define ADS1119_DR_20_SPS 0
+#define ADS1119_DR_90_SPS 1
+#define ADS1119_DR_330_SPS 2
+#define ADS1119_DR_1000_SPS 3
+
+#define ADS1119_GAIN_1 0
+#define ADS1119_GAIN_4 1
+
+#define ADS1119_MUX_AIN0_AIN1 0
+#define ADS1119_MUX_AIN2_AIN3 1
+#define ADS1119_MUX_AIN1_AIN2 2
+#define ADS1119_MUX_AIN0 3
+#define ADS1119_MUX_AIN1 4
+#define ADS1119_MUX_AIN2 5
+#define ADS1119_MUX_AIN3 6
+#define ADS1119_MUX_SHORTED 7
+
+/* Status register */
+#define ADS1119_REG_STATUS 0x01
+#define ADS1119_STATUS_DRDY_FIELD BIT(7)
+
+#define ADS1119_DEFAULT_GAIN 1
+#define ADS1119_DEFAULT_DATARATE 20
+
+#define ADS1119_SUSPEND_DELAY 2000
+
+/* Timeout based on the minimum sample rate of 20 SPS (50000us) */
+#define ADS1119_MAX_DRDY_TIMEOUT 85000
+
+#define ADS1119_MAX_CHANNELS 7
+#define ADS1119_MAX_SINGLE_CHANNELS 4
+
+struct ads1119_channel_config {
+ int gain;
+ int datarate;
+ int mux;
+};
+
+struct ads1119_state {
+ struct completion completion;
+ struct i2c_client *client;
+ struct gpio_desc *reset_gpio;
+ struct iio_trigger *trig;
+ struct ads1119_channel_config *channels_cfg;
+ unsigned int num_channels_cfg;
+ unsigned int cached_config;
+ int vref_uV;
+};
+
+static const char * const ads1119_power_supplies[] = {
+ "avdd", "dvdd"
+};
+
+static const int ads1119_available_datarates[] = {
+ 20, 90, 330, 1000,
+};
+
+static const int ads1119_available_gains[] = {
+ 1, 1,
+ 1, 4,
+};
+
+static int ads1119_upd_cfg_reg(struct ads1119_state *st, unsigned int fields,
+ unsigned int val)
+{
+ unsigned int config = st->cached_config;
+ int ret;
+
+ config &= ~fields;
+ config |= val;
+
+ ret = i2c_smbus_write_byte_data(st->client, ADS1119_CMD_WREG, config);
+ if (ret)
+ return ret;
+
+ st->cached_config = config;
+
+ return 0;
+}
+
+static bool ads1119_data_ready(struct ads1119_state *st)
+{
+ int status;
+
+ status = i2c_smbus_read_byte_data(st->client, ADS1119_CMD_RREG_STATUS);
+ if (status < 0)
+ return false;
+
+ return FIELD_GET(ADS1119_STATUS_DRDY_FIELD, status);
+}
+
+static int ads1119_reset(struct ads1119_state *st)
+{
+ st->cached_config = 0;
+
+ if (!st->reset_gpio)
+ return i2c_smbus_write_byte(st->client, ADS1119_CMD_RESET);
+
+ gpiod_set_value_cansleep(st->reset_gpio, 1);
+ udelay(1);
+ gpiod_set_value_cansleep(st->reset_gpio, 0);
+ udelay(1);
+
+ return 0;
+}
+
+static int ads1119_set_conv_mode(struct ads1119_state *st, bool continuous)
+{
+ unsigned int mode;
+
+ if (continuous)
+ mode = ADS1119_CM_CONTINUOUS;
+ else
+ mode = ADS1119_CM_SINGLE;
+
+ return ads1119_upd_cfg_reg(st, ADS1119_CONFIG_CM_FIELD,
+ FIELD_PREP(ADS1119_CONFIG_CM_FIELD, mode));
+}
+
+static int ads1119_get_hw_gain(int gain)
+{
+ if (gain == 4)
+ return ADS1119_GAIN_4;
+ else
+ return ADS1119_GAIN_1;
+}
+
+static int ads1119_get_hw_datarate(int datarate)
+{
+ switch (datarate) {
+ case 90:
+ return ADS1119_DR_90_SPS;
+ case 330:
+ return ADS1119_DR_330_SPS;
+ case 1000:
+ return ADS1119_DR_1000_SPS;
+ case 20:
+ default:
+ return ADS1119_DR_20_SPS;
+ }
+}
+
+static int ads1119_configure_channel(struct ads1119_state *st, int mux,
+ int gain, int datarate)
+{
+ int ret;
+
+ ret = ads1119_upd_cfg_reg(st, ADS1119_CONFIG_MUX_FIELD,
+ FIELD_PREP(ADS1119_CONFIG_MUX_FIELD, mux));
+ if (ret)
+ return ret;
+
+ ret = ads1119_upd_cfg_reg(st, ADS1119_CONFIG_GAIN_FIELD,
+ FIELD_PREP(ADS1119_CONFIG_GAIN_FIELD,
+ ads1119_get_hw_gain(gain)));
+ if (ret)
+ return ret;
+
+ return ads1119_upd_cfg_reg(st, ADS1119_CONFIG_DR_FIELD,
+ FIELD_PREP(ADS1119_CONFIG_DR_FIELD,
+ ads1119_get_hw_datarate(datarate)));
+}
+
+static int ads1119_poll_data_ready(struct ads1119_state *st,
+ struct iio_chan_spec const *chan)
+{
+ unsigned int datarate = st->channels_cfg[chan->address].datarate;
+ unsigned long wait_time;
+ bool data_ready;
+
+ /* Poll 5 times more than the data rate */
+ wait_time = DIV_ROUND_CLOSEST(MICRO, 5 * datarate);
+
+ return read_poll_timeout(ads1119_data_ready, data_ready,
+ data_ready, wait_time,
+ ADS1119_MAX_DRDY_TIMEOUT, false, st);
+}
+
+static int ads1119_read_data(struct ads1119_state *st,
+ struct iio_chan_spec const *chan,
+ unsigned int *val)
+{
+ unsigned int timeout;
+ int ret = 0;
+
+ timeout = msecs_to_jiffies(ADS1119_MAX_DRDY_TIMEOUT);
+
+ if (!st->client->irq) {
+ ret = ads1119_poll_data_ready(st, chan);
+ if (ret)
+ return ret;
+ } else if (!wait_for_completion_timeout(&st->completion, timeout)) {
+ return -ETIMEDOUT;
+ }
+
+ ret = i2c_smbus_read_word_swapped(st->client, ADS1119_CMD_RDATA);
+ if (ret < 0)
+ return ret;
+
+ *val = ret;
+
+ return 0;
+}
+
+static int ads1119_single_conversion(struct ads1119_state *st,
+ struct iio_chan_spec const *chan,
+ int *val,
+ bool calib_offset)
+{
+ struct device *dev = &st->client->dev;
+ int mux = st->channels_cfg[chan->address].mux;
+ int gain = st->channels_cfg[chan->address].gain;
+ int datarate = st->channels_cfg[chan->address].datarate;
+ unsigned int sample;
+ int ret;
+
+ if (calib_offset)
+ mux = ADS1119_MUX_SHORTED;
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret)
+ goto pdown;
+
+ ret = ads1119_configure_channel(st, mux, gain, datarate);
+ if (ret)
+ goto pdown;
+
+ ret = i2c_smbus_write_byte(st->client, ADS1119_CMD_START_SYNC);
+ if (ret)
+ goto pdown;
+
+ ret = ads1119_read_data(st, chan, &sample);
+ if (ret)
+ goto pdown;
+
+ *val = sign_extend32(sample, chan->scan_type.realbits - 1);
+ ret = IIO_VAL_INT;
+pdown:
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+ return ret;
+}
+
+static int ads1119_validate_datarate(struct ads1119_state *st, int datarate)
+{
+ switch (datarate) {
+ case 20:
+ case 90:
+ case 330:
+ case 1000:
+ return datarate;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ads1119_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long mask)
+{
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ *type = IIO_VAL_FRACTIONAL;
+ *vals = ads1119_available_gains;
+ *length = ARRAY_SIZE(ads1119_available_gains);
+ return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *type = IIO_VAL_INT;
+ *vals = ads1119_available_datarates;
+ *length = ARRAY_SIZE(ads1119_available_datarates);
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ads1119_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ struct ads1119_state *st = iio_priv(indio_dev);
+ unsigned int index = chan->address;
+
+ if (index >= st->num_channels_cfg)
+ return -EINVAL;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ iio_device_claim_direct_scoped(return -EBUSY, indio_dev)
+ return ads1119_single_conversion(st, chan, val, false);
+ unreachable();
+ case IIO_CHAN_INFO_OFFSET:
+ iio_device_claim_direct_scoped(return -EBUSY, indio_dev)
+ return ads1119_single_conversion(st, chan, val, true);
+ unreachable();
+ case IIO_CHAN_INFO_SCALE:
+ *val = st->vref_uV / 1000;
+ *val /= st->channels_cfg[index].gain;
+ *val2 = chan->scan_type.realbits - 1;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *val = st->channels_cfg[index].datarate;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ads1119_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val,
+ int val2, long mask)
+{
+ struct ads1119_state *st = iio_priv(indio_dev);
+ unsigned int index = chan->address;
+ int ret;
+
+ if (index >= st->num_channels_cfg)
+ return -EINVAL;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ ret = MICRO / ((val * MICRO) + val2);
+ if (ret != 1 && ret != 4)
+ return -EINVAL;
+
+ st->channels_cfg[index].gain = ret;
+ return 0;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ ret = ads1119_validate_datarate(st, val);
+ if (ret < 0)
+ return ret;
+
+ st->channels_cfg[index].datarate = ret;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ads1119_debugfs_reg_access(struct iio_dev *indio_dev,
+ unsigned int reg, unsigned int writeval,
+ unsigned int *readval)
+{
+ struct ads1119_state *st = iio_priv(indio_dev);
+ int ret;
+
+ if (reg > ADS1119_REG_STATUS)
+ return -EINVAL;
+
+ if (readval) {
+ ret = i2c_smbus_read_byte_data(st->client,
+ ADS1119_CMD_RREG(reg));
+ if (ret < 0)
+ return ret;
+
+ *readval = ret;
+ return 0;
+ }
+
+ if (reg > ADS1119_REG_CONFIG)
+ return -EINVAL;
+
+ return i2c_smbus_write_byte_data(st->client, ADS1119_CMD_WREG,
+ writeval);
+}
+
+static const struct iio_info ads1119_info = {
+ .read_avail = ads1119_read_avail,
+ .read_raw = ads1119_read_raw,
+ .write_raw = ads1119_write_raw,
+ .debugfs_reg_access = ads1119_debugfs_reg_access,
+};
+
+static int ads1119_triggered_buffer_preenable(struct iio_dev *indio_dev)
+{
+ struct ads1119_state *st = iio_priv(indio_dev);
+ struct device *dev = &st->client->dev;
+ unsigned int index;
+ int ret;
+
+ index = find_first_bit(indio_dev->active_scan_mask,
+ indio_dev->masklength);
+
+ ret = ads1119_set_conv_mode(st, true);
+ if (ret)
+ return ret;
+
+ ret = ads1119_configure_channel(st,
+ st->channels_cfg[index].mux,
+ st->channels_cfg[index].gain,
+ st->channels_cfg[index].datarate);
+ if (ret)
+ return ret;
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret)
+ return ret;
+
+ return i2c_smbus_write_byte(st->client, ADS1119_CMD_START_SYNC);
+}
+
+static int ads1119_triggered_buffer_postdisable(struct iio_dev *indio_dev)
+{
+ struct ads1119_state *st = iio_priv(indio_dev);
+ struct device *dev = &st->client->dev;
+ int ret;
+
+ ret = ads1119_set_conv_mode(st, false);
+ if (ret)
+ return ret;
+
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+
+ return 0;
+}
+
+static const struct iio_buffer_setup_ops ads1119_buffer_setup_ops = {
+ .preenable = ads1119_triggered_buffer_preenable,
+ .postdisable = ads1119_triggered_buffer_postdisable,
+ .validate_scan_mask = &iio_validate_scan_mask_onehot,
+};
+
+static const struct iio_trigger_ops ads1119_trigger_ops = {
+ .validate_device = &iio_trigger_validate_own_device,
+};
+
+static irqreturn_t ads1119_irq_handler(int irq, void *dev_id)
+{
+ struct iio_dev *indio_dev = dev_id;
+ struct ads1119_state *st = iio_priv(indio_dev);
+
+ if (iio_buffer_enabled(indio_dev) && iio_trigger_using_own(indio_dev))
+ iio_trigger_poll(indio_dev->trig);
+ else
+ complete(&st->completion);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t ads1119_trigger_handler(int irq, void *private)
+{
+ struct iio_poll_func *pf = private;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct ads1119_state *st = iio_priv(indio_dev);
+ struct {
+ unsigned int sample;
+ s64 timestamp __aligned(8);
+ } scan;
+ unsigned int index;
+ int ret;
+
+ if (!iio_trigger_using_own(indio_dev)) {
+ index = find_first_bit(indio_dev->active_scan_mask,
+ indio_dev->masklength);
+
+ ret = ads1119_poll_data_ready(st, &indio_dev->channels[index]);
+ if (ret) {
+ dev_err(&st->client->dev,
+ "Failed to poll data on trigger (%d)\n", ret);
+ goto done;
+ }
+ }
+
+ ret = i2c_smbus_read_word_swapped(st->client, ADS1119_CMD_RDATA);
+ if (ret < 0) {
+ dev_err(&st->client->dev,
+ "Failed to read data on trigger (%d)\n", ret);
+ goto done;
+ }
+
+ scan.sample = ret;
+
+ iio_push_to_buffers_with_timestamp(indio_dev, &scan,
+ iio_get_time_ns(indio_dev));
+done:
+ iio_trigger_notify_done(indio_dev->trig);
+ return IRQ_HANDLED;
+}
+
+static int ads1119_init(struct ads1119_state *st, bool vref_external)
+{
+ int ret;
+
+ ret = ads1119_reset(st);
+ if (ret)
+ return ret;
+
+ if (vref_external)
+ return ads1119_upd_cfg_reg(st,
+ ADS1119_CONFIG_VREF_FIELD,
+ FIELD_PREP(ADS1119_CONFIG_VREF_FIELD,
+ ADS1119_VREF_EXTERNAL));
+ return 0;
+}
+
+static int ads1119_map_analog_inputs_mux(int ain_pos, int ain_neg,
+ bool differential)
+{
+ if (ain_pos >= ADS1119_MAX_SINGLE_CHANNELS)
+ return -EINVAL;
+
+ if (!differential)
+ return ADS1119_MUX_AIN0 + ain_pos;
+
+ if (ain_pos == 0 && ain_neg == 1)
+ return ADS1119_MUX_AIN0_AIN1;
+ else if (ain_pos == 1 && ain_neg == 2)
+ return ADS1119_MUX_AIN1_AIN2;
+ else if (ain_pos == 2 && ain_neg == 3)
+ return ADS1119_MUX_AIN2_AIN3;
+
+ return -EINVAL;
+}
+
+static int ads1119_alloc_and_config_channels(struct iio_dev *indio_dev)
+{
+ const struct iio_chan_spec ads1119_channel =
+ (const struct iio_chan_spec) {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_OFFSET) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ .info_mask_shared_by_all_available =
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ .scan_type = {
+ .sign = 's',
+ .realbits = 16,
+ .storagebits = 16,
+ .endianness = IIO_CPU,
+ },
+ };
+ const struct iio_chan_spec ads1119_ts = IIO_CHAN_SOFT_TIMESTAMP(0);
+ struct ads1119_state *st = iio_priv(indio_dev);
+ struct iio_chan_spec *iio_channels, *chan;
+ struct device *dev = &st->client->dev;
+ unsigned int num_channels, i;
+ bool differential;
+ u32 ain[2];
+ int ret;
+
+ st->num_channels_cfg = device_get_child_node_count(dev);
+ if (st->num_channels_cfg > ADS1119_MAX_CHANNELS)
+ return dev_err_probe(dev, -EINVAL,
+ "Too many channels %d, max is %d\n",
+ st->num_channels_cfg,
+ ADS1119_MAX_CHANNELS);
+
+ st->channels_cfg = devm_kcalloc(dev, st->num_channels_cfg,
+ sizeof(*st->channels_cfg), GFP_KERNEL);
+ if (!st->channels_cfg)
+ return -ENOMEM;
+
+ /* Allocate one more iio channel for the timestamp */
+ num_channels = st->num_channels_cfg + 1;
+ iio_channels = devm_kcalloc(dev, num_channels, sizeof(*iio_channels),
+ GFP_KERNEL);
+ if (!iio_channels)
+ return -ENOMEM;
+
+ i = 0;
+
+ device_for_each_child_node_scoped(dev, child) {
+ chan = &iio_channels[i];
+
+ differential = fwnode_property_present(child, "diff-channels");
+ if (differential)
+ ret = fwnode_property_read_u32_array(child,
+ "diff-channels",
+ ain, 2);
+ else
+ ret = fwnode_property_read_u32(child, "single-channel",
+ &ain[0]);
+
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to get channel property\n");
+
+ ret = ads1119_map_analog_inputs_mux(ain[0], ain[1],
+ differential);
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "Invalid channel value\n");
+
+ st->channels_cfg[i].mux = ret;
+ st->channels_cfg[i].gain = ADS1119_DEFAULT_GAIN;
+ st->channels_cfg[i].datarate = ADS1119_DEFAULT_DATARATE;
+
+ *chan = ads1119_channel;
+ chan->channel = ain[0];
+ chan->address = i;
+ chan->scan_index = i;
+
+ if (differential) {
+ chan->channel2 = ain[1];
+ chan->differential = 1;
+ }
+
+ dev_dbg(dev, "channel: index %d, mux %d\n", i,
+ st->channels_cfg[i].mux);
+
+ i++;
+ }
+
+ iio_channels[i] = ads1119_ts;
+ iio_channels[i].address = i;
+ iio_channels[i].scan_index = i;
+
+ indio_dev->channels = iio_channels;
+ indio_dev->num_channels = num_channels;
+
+ return 0;
+}
+
+static void ads1119_powerdown(void *data)
+{
+ struct ads1119_state *st = data;
+
+ i2c_smbus_write_byte(st->client, ADS1119_CMD_POWERDOWN);
+}
+
+static int ads1119_probe(struct i2c_client *client)
+{
+ struct iio_dev *indio_dev;
+ struct ads1119_state *st;
+ struct device *dev = &client->dev;
+ bool vref_external = true;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
+ if (!indio_dev)
+ return dev_err_probe(dev, -ENOMEM,
+ "Failed to allocate IIO device\n");
+
+ st = iio_priv(indio_dev);
+ st->client = client;
+
+ indio_dev->name = "ads1119";
+ indio_dev->info = &ads1119_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ i2c_set_clientdata(client, indio_dev);
+
+ ret = devm_regulator_bulk_get_enable(dev,
+ ARRAY_SIZE(ads1119_power_supplies),
+ ads1119_power_supplies);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to get and enable supplies\n");
+
+ st->vref_uV = devm_regulator_get_enable_read_voltage(dev, "vref");
+ if (st->vref_uV == -ENODEV) {
+ vref_external = false;
+ st->vref_uV = ADS1119_VREF_INTERNAL_VAL;
+ } else if (st->vref_uV < 0) {
+ return dev_err_probe(dev, st->vref_uV, "Failed to get vref\n");
+ }
+
+ st->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(st->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(st->reset_gpio),
+ "Failed to get reset gpio\n");
+
+ ret = ads1119_alloc_and_config_channels(indio_dev);
+ if (ret)
+ return ret;
+
+ init_completion(&st->completion);
+
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
+ ads1119_trigger_handler,
+ &ads1119_buffer_setup_ops);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to setup IIO buffer\n");
+
+ if (client->irq > 0) {
+ ret = devm_request_threaded_irq(dev, client->irq,
+ ads1119_irq_handler,
+ NULL, IRQF_TRIGGER_FALLING,
+ "ads1119", indio_dev);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to allocate irq\n");
+
+ st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
+ indio_dev->name,
+ iio_device_id(indio_dev));
+ if (!st->trig)
+ return dev_err_probe(dev, -ENOMEM,
+ "Failed to allocate IIO trigger\n");
+
+ st->trig->ops = &ads1119_trigger_ops;
+ iio_trigger_set_drvdata(st->trig, indio_dev);
+
+ ret = devm_iio_trigger_register(dev, st->trig);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to register IIO trigger\n");
+ }
+
+ ret = ads1119_init(st, vref_external);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to initialize device\n");
+
+ pm_runtime_set_autosuspend_delay(dev, ADS1119_SUSPEND_DELAY);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_set_active(dev);
+
+ ret = devm_pm_runtime_enable(dev);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to enable pm runtime\n");
+
+ ret = devm_add_action_or_reset(dev, ads1119_powerdown, st);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to add powerdown action\n");
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static int ads1119_runtime_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct ads1119_state *st = iio_priv(indio_dev);
+
+ return i2c_smbus_write_byte(st->client, ADS1119_CMD_POWERDOWN);
+}
+
+/*
+ * The ADS1119 does not require a resume function because it automatically
+ * powers on after a reset.
+ * After a power down command, the ADS1119 can still communicate but turns off
+ * its analog parts. To resume from power down, the device will power up again
+ * upon receiving a start/sync command.
+ */
+static DEFINE_RUNTIME_DEV_PM_OPS(ads1119_pm_ops, ads1119_runtime_suspend,
+ NULL, NULL);
+
+static const struct of_device_id __maybe_unused ads1119_of_match[] = {
+ { .compatible = "ti,ads1119" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ads1119_of_match);
+
+static const struct i2c_device_id ads1119_id[] = {
+ { "ads1119", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ads1119_id);
+
+static struct i2c_driver ads1119_driver = {
+ .driver = {
+ .name = "ads1119",
+ .of_match_table = ads1119_of_match,
+ .pm = pm_ptr(&ads1119_pm_ops),
+ },
+ .probe = ads1119_probe,
+ .id_table = ads1119_id,
+};
+module_i2c_driver(ads1119_driver);
+
+MODULE_AUTHOR("João Paulo Gonçalves <joao.goncalves@toradex.com>");
+MODULE_DESCRIPTION("Texas Instruments ADS1119 ADC Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/adc/ti-ads8688.c b/drivers/iio/adc/ti-ads8688.c
index 9440a268a78c..7a79f0cebfbf 100644
--- a/drivers/iio/adc/ti-ads8688.c
+++ b/drivers/iio/adc/ti-ads8688.c
@@ -65,7 +65,6 @@ struct ads8688_state {
struct mutex lock;
const struct ads8688_chip_info *chip_info;
struct spi_device *spi;
- struct regulator *reg;
unsigned int vref_mv;
enum ads8688_range range[8];
union {
@@ -423,28 +422,16 @@ static int ads8688_probe(struct spi_device *spi)
st = iio_priv(indio_dev);
- st->reg = devm_regulator_get_optional(&spi->dev, "vref");
- if (!IS_ERR(st->reg)) {
- ret = regulator_enable(st->reg);
- if (ret)
- return ret;
-
- ret = regulator_get_voltage(st->reg);
- if (ret < 0)
- goto err_regulator_disable;
+ ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref");
+ if (ret < 0 && ret != -ENODEV)
+ return ret;
- st->vref_mv = ret / 1000;
- } else {
- /* Use internal reference */
- st->vref_mv = ADS8688_VREF_MV;
- }
+ st->vref_mv = ret == -ENODEV ? ADS8688_VREF_MV : ret / 1000;
st->chip_info = &ads8688_chip_info_tbl[spi_get_device_id(spi)->driver_data];
spi->mode = SPI_MODE_1;
- spi_set_drvdata(spi, indio_dev);
-
st->spi = spi;
indio_dev->name = spi_get_device_id(spi)->name;
@@ -457,38 +444,13 @@ static int ads8688_probe(struct spi_device *spi)
mutex_init(&st->lock);
- ret = iio_triggered_buffer_setup(indio_dev, NULL, ads8688_trigger_handler, NULL);
- if (ret < 0) {
- dev_err(&spi->dev, "iio triggered buffer setup failed\n");
- goto err_regulator_disable;
- }
-
- ret = iio_device_register(indio_dev);
- if (ret)
- goto err_buffer_cleanup;
-
- return 0;
-
-err_buffer_cleanup:
- iio_triggered_buffer_cleanup(indio_dev);
-
-err_regulator_disable:
- if (!IS_ERR(st->reg))
- regulator_disable(st->reg);
-
- return ret;
-}
-
-static void ads8688_remove(struct spi_device *spi)
-{
- struct iio_dev *indio_dev = spi_get_drvdata(spi);
- struct ads8688_state *st = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
- iio_triggered_buffer_cleanup(indio_dev);
+ ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, NULL,
+ ads8688_trigger_handler, NULL);
+ if (ret < 0)
+ return dev_err_probe(&spi->dev, ret,
+ "iio triggered buffer setup failed\n");
- if (!IS_ERR(st->reg))
- regulator_disable(st->reg);
+ return devm_iio_device_register(&spi->dev, indio_dev);
}
static const struct spi_device_id ads8688_id[] = {
@@ -511,7 +473,6 @@ static struct spi_driver ads8688_driver = {
.of_match_table = ads8688_of_match,
},
.probe = ads8688_probe,
- .remove = ads8688_remove,
.id_table = ads8688_id,
};
module_spi_driver(ads8688_driver);
diff --git a/drivers/iio/adc/xilinx-ams.c b/drivers/iio/adc/xilinx-ams.c
index aa05f24931f9..f051358d6b50 100644
--- a/drivers/iio/adc/xilinx-ams.c
+++ b/drivers/iio/adc/xilinx-ams.c
@@ -222,7 +222,7 @@ enum ams_ps_pl_seq {
#define PL_SEQ(x) (AMS_PS_SEQ_MAX + (x))
#define AMS_CTRL_SEQ_BASE (AMS_PS_SEQ_MAX * 3)
-#define AMS_CHAN_TEMP(_scan_index, _addr) { \
+#define AMS_CHAN_TEMP(_scan_index, _addr, _name) { \
.type = IIO_TEMP, \
.indexed = 1, \
.address = (_addr), \
@@ -232,9 +232,10 @@ enum ams_ps_pl_seq {
.event_spec = ams_temp_events, \
.scan_index = _scan_index, \
.num_event_specs = ARRAY_SIZE(ams_temp_events), \
+ .datasheet_name = _name, \
}
-#define AMS_CHAN_VOLTAGE(_scan_index, _addr, _alarm) { \
+#define AMS_CHAN_VOLTAGE(_scan_index, _addr, _alarm, _name) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.address = (_addr), \
@@ -243,21 +244,24 @@ enum ams_ps_pl_seq {
.event_spec = (_alarm) ? ams_voltage_events : NULL, \
.scan_index = _scan_index, \
.num_event_specs = (_alarm) ? ARRAY_SIZE(ams_voltage_events) : 0, \
+ .datasheet_name = _name, \
}
-#define AMS_PS_CHAN_TEMP(_scan_index, _addr) \
- AMS_CHAN_TEMP(PS_SEQ(_scan_index), _addr)
-#define AMS_PS_CHAN_VOLTAGE(_scan_index, _addr) \
- AMS_CHAN_VOLTAGE(PS_SEQ(_scan_index), _addr, true)
+#define AMS_PS_CHAN_TEMP(_scan_index, _addr, _name) \
+ AMS_CHAN_TEMP(PS_SEQ(_scan_index), _addr, _name)
+#define AMS_PS_CHAN_VOLTAGE(_scan_index, _addr, _name) \
+ AMS_CHAN_VOLTAGE(PS_SEQ(_scan_index), _addr, true, _name)
-#define AMS_PL_CHAN_TEMP(_scan_index, _addr) \
- AMS_CHAN_TEMP(PL_SEQ(_scan_index), _addr)
-#define AMS_PL_CHAN_VOLTAGE(_scan_index, _addr, _alarm) \
- AMS_CHAN_VOLTAGE(PL_SEQ(_scan_index), _addr, _alarm)
+#define AMS_PL_CHAN_TEMP(_scan_index, _addr, _name) \
+ AMS_CHAN_TEMP(PL_SEQ(_scan_index), _addr, _name)
+#define AMS_PL_CHAN_VOLTAGE(_scan_index, _addr, _alarm, _name) \
+ AMS_CHAN_VOLTAGE(PL_SEQ(_scan_index), _addr, _alarm, _name)
#define AMS_PL_AUX_CHAN_VOLTAGE(_auxno) \
- AMS_CHAN_VOLTAGE(PL_SEQ(AMS_SEQ(_auxno)), AMS_REG_VAUX(_auxno), false)
-#define AMS_CTRL_CHAN_VOLTAGE(_scan_index, _addr) \
- AMS_CHAN_VOLTAGE(PL_SEQ(AMS_SEQ(AMS_SEQ(_scan_index))), _addr, false)
+ AMS_CHAN_VOLTAGE(PL_SEQ(AMS_SEQ(_auxno)), AMS_REG_VAUX(_auxno), false, \
+ "VAUX" #_auxno)
+#define AMS_CTRL_CHAN_VOLTAGE(_scan_index, _addr, _name) \
+ AMS_CHAN_VOLTAGE(PL_SEQ(AMS_SEQ(AMS_SEQ(_scan_index))), _addr, false, \
+ _name)
/**
* struct ams - This structure contains necessary state for xilinx-ams to operate
@@ -505,6 +509,12 @@ static int ams_init_device(struct ams *ams)
return 0;
}
+static int ams_read_label(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, char *label)
+{
+ return sysfs_emit(label, "%s\n", chan->datasheet_name);
+}
+
static int ams_enable_single_channel(struct ams *ams, unsigned int offset)
{
u8 channel_num;
@@ -1116,37 +1126,37 @@ static const struct iio_event_spec ams_voltage_events[] = {
};
static const struct iio_chan_spec ams_ps_channels[] = {
- AMS_PS_CHAN_TEMP(AMS_SEQ_TEMP, AMS_TEMP),
- AMS_PS_CHAN_TEMP(AMS_SEQ_TEMP_REMOTE, AMS_TEMP_REMOTE),
- AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY1, AMS_SUPPLY1),
- AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY2, AMS_SUPPLY2),
- AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY3, AMS_SUPPLY3),
- AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY4, AMS_SUPPLY4),
- AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY5, AMS_SUPPLY5),
- AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY6, AMS_SUPPLY6),
- AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY7, AMS_SUPPLY7),
- AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY8, AMS_SUPPLY8),
- AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY9, AMS_SUPPLY9),
- AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY10, AMS_SUPPLY10),
- AMS_PS_CHAN_VOLTAGE(AMS_SEQ_VCCAMS, AMS_VCCAMS),
+ AMS_PS_CHAN_TEMP(AMS_SEQ_TEMP, AMS_TEMP, "Temp_LPD"),
+ AMS_PS_CHAN_TEMP(AMS_SEQ_TEMP_REMOTE, AMS_TEMP_REMOTE, "Temp_FPD"),
+ AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY1, AMS_SUPPLY1, "VCC_PSINTLP"),
+ AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY2, AMS_SUPPLY2, "VCC_PSINTFP"),
+ AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY3, AMS_SUPPLY3, "VCC_PSAUX"),
+ AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY4, AMS_SUPPLY4, "VCC_PSDDR"),
+ AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY5, AMS_SUPPLY5, "VCC_PSIO3"),
+ AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY6, AMS_SUPPLY6, "VCC_PSIO0"),
+ AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY7, AMS_SUPPLY7, "VCC_PSIO1"),
+ AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY8, AMS_SUPPLY8, "VCC_PSIO2"),
+ AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY9, AMS_SUPPLY9, "PS_MGTRAVCC"),
+ AMS_PS_CHAN_VOLTAGE(AMS_SEQ_SUPPLY10, AMS_SUPPLY10, "PS_MGTRAVTT"),
+ AMS_PS_CHAN_VOLTAGE(AMS_SEQ_VCCAMS, AMS_VCCAMS, "VCC_PSADC"),
};
static const struct iio_chan_spec ams_pl_channels[] = {
- AMS_PL_CHAN_TEMP(AMS_SEQ_TEMP, AMS_TEMP),
- AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY1, AMS_SUPPLY1, true),
- AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY2, AMS_SUPPLY2, true),
- AMS_PL_CHAN_VOLTAGE(AMS_SEQ_VREFP, AMS_VREFP, false),
- AMS_PL_CHAN_VOLTAGE(AMS_SEQ_VREFN, AMS_VREFN, false),
- AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY3, AMS_SUPPLY3, true),
- AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY4, AMS_SUPPLY4, true),
- AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY5, AMS_SUPPLY5, true),
- AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY6, AMS_SUPPLY6, true),
- AMS_PL_CHAN_VOLTAGE(AMS_SEQ_VCCAMS, AMS_VCCAMS, true),
- AMS_PL_CHAN_VOLTAGE(AMS_SEQ_VP_VN, AMS_VP_VN, false),
- AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY7, AMS_SUPPLY7, true),
- AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY8, AMS_SUPPLY8, true),
- AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY9, AMS_SUPPLY9, true),
- AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY10, AMS_SUPPLY10, true),
+ AMS_PL_CHAN_TEMP(AMS_SEQ_TEMP, AMS_TEMP, "Temp_PL"),
+ AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY1, AMS_SUPPLY1, true, "VCCINT"),
+ AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY2, AMS_SUPPLY2, true, "VCCAUX"),
+ AMS_PL_CHAN_VOLTAGE(AMS_SEQ_VREFP, AMS_VREFP, false, "VREFP"),
+ AMS_PL_CHAN_VOLTAGE(AMS_SEQ_VREFN, AMS_VREFN, false, "VREFN"),
+ AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY3, AMS_SUPPLY3, true, "VCCBRAM"),
+ AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY4, AMS_SUPPLY4, true, "VCC_PSINTLP"),
+ AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY5, AMS_SUPPLY5, true, "VCC_PSINTFP"),
+ AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY6, AMS_SUPPLY6, true, "VCC_PSAUX"),
+ AMS_PL_CHAN_VOLTAGE(AMS_SEQ_VCCAMS, AMS_VCCAMS, true, "VCCAMS"),
+ AMS_PL_CHAN_VOLTAGE(AMS_SEQ_VP_VN, AMS_VP_VN, false, "VP_VN"),
+ AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY7, AMS_SUPPLY7, true, "VUser0"),
+ AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY8, AMS_SUPPLY8, true, "VUser1"),
+ AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY9, AMS_SUPPLY9, true, "VUser2"),
+ AMS_PL_CHAN_VOLTAGE(AMS_SEQ_SUPPLY10, AMS_SUPPLY10, true, "VUser3"),
AMS_PL_AUX_CHAN_VOLTAGE(0),
AMS_PL_AUX_CHAN_VOLTAGE(1),
AMS_PL_AUX_CHAN_VOLTAGE(2),
@@ -1166,13 +1176,13 @@ static const struct iio_chan_spec ams_pl_channels[] = {
};
static const struct iio_chan_spec ams_ctrl_channels[] = {
- AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_VCC_PSPLL, AMS_VCC_PSPLL0),
- AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_VCC_PSBATT, AMS_VCC_PSPLL3),
- AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_VCCINT, AMS_VCCINT),
- AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_VCCBRAM, AMS_VCCBRAM),
- AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_VCCAUX, AMS_VCCAUX),
- AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_PSDDRPLL, AMS_PSDDRPLL),
- AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_INTDDR, AMS_PSINTFPDDR),
+ AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_VCC_PSPLL, AMS_VCC_PSPLL0, "VCC_PSPLL"),
+ AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_VCC_PSBATT, AMS_VCC_PSPLL3, "VCC_PSBATT"),
+ AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_VCCINT, AMS_VCCINT, "VCCINT"),
+ AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_VCCBRAM, AMS_VCCBRAM, "VCCBRAM"),
+ AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_VCCAUX, AMS_VCCAUX, "VCCAUX"),
+ AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_PSDDRPLL, AMS_PSDDRPLL, "VCC_PSDDR_PLL"),
+ AMS_CTRL_CHAN_VOLTAGE(AMS_SEQ_INTDDR, AMS_PSINTFPDDR, "VCC_PSINTFP_DDR"),
};
static int ams_get_ext_chan(struct fwnode_handle *chan_node,
@@ -1336,6 +1346,7 @@ static int ams_parse_firmware(struct iio_dev *indio_dev)
}
static const struct iio_info iio_ams_info = {
+ .read_label = ams_read_label,
.read_raw = &ams_read_raw,
.read_event_config = &ams_read_event_config,
.write_event_config = &ams_write_event_config,
diff --git a/drivers/iio/buffer/industrialio-buffer-dma.c b/drivers/iio/buffer/industrialio-buffer-dma.c
index 13b1a858969e..647f417a045e 100644
--- a/drivers/iio/buffer/industrialio-buffer-dma.c
+++ b/drivers/iio/buffer/industrialio-buffer-dma.c
@@ -4,6 +4,8 @@
* Author: Lars-Peter Clausen <lars@metafoo.de>
*/
+#include <linux/atomic.h>
+#include <linux/cleanup.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -14,6 +16,8 @@
#include <linux/poll.h>
#include <linux/iio/buffer_impl.h>
#include <linux/iio/buffer-dma.h>
+#include <linux/dma-buf.h>
+#include <linux/dma-fence.h>
#include <linux/dma-mapping.h>
#include <linux/sizes.h>
@@ -94,13 +98,18 @@ static void iio_buffer_block_release(struct kref *kref)
{
struct iio_dma_buffer_block *block = container_of(kref,
struct iio_dma_buffer_block, kref);
+ struct iio_dma_buffer_queue *queue = block->queue;
- WARN_ON(block->state != IIO_BLOCK_STATE_DEAD);
+ WARN_ON(block->fileio && block->state != IIO_BLOCK_STATE_DEAD);
- dma_free_coherent(block->queue->dev, PAGE_ALIGN(block->size),
- block->vaddr, block->phys_addr);
+ if (block->fileio) {
+ dma_free_coherent(queue->dev, PAGE_ALIGN(block->size),
+ block->vaddr, block->phys_addr);
+ } else {
+ atomic_dec(&queue->num_dmabufs);
+ }
- iio_buffer_put(&block->queue->buffer);
+ iio_buffer_put(&queue->buffer);
kfree(block);
}
@@ -163,7 +172,7 @@ static struct iio_dma_buffer_queue *iio_buffer_to_queue(struct iio_buffer *buf)
}
static struct iio_dma_buffer_block *iio_dma_buffer_alloc_block(
- struct iio_dma_buffer_queue *queue, size_t size)
+ struct iio_dma_buffer_queue *queue, size_t size, bool fileio)
{
struct iio_dma_buffer_block *block;
@@ -171,13 +180,16 @@ static struct iio_dma_buffer_block *iio_dma_buffer_alloc_block(
if (!block)
return NULL;
- block->vaddr = dma_alloc_coherent(queue->dev, PAGE_ALIGN(size),
- &block->phys_addr, GFP_KERNEL);
- if (!block->vaddr) {
- kfree(block);
- return NULL;
+ if (fileio) {
+ block->vaddr = dma_alloc_coherent(queue->dev, PAGE_ALIGN(size),
+ &block->phys_addr, GFP_KERNEL);
+ if (!block->vaddr) {
+ kfree(block);
+ return NULL;
+ }
}
+ block->fileio = fileio;
block->size = size;
block->state = IIO_BLOCK_STATE_DONE;
block->queue = queue;
@@ -186,6 +198,9 @@ static struct iio_dma_buffer_block *iio_dma_buffer_alloc_block(
iio_buffer_get(&queue->buffer);
+ if (!fileio)
+ atomic_inc(&queue->num_dmabufs);
+
return block;
}
@@ -218,13 +233,20 @@ void iio_dma_buffer_block_done(struct iio_dma_buffer_block *block)
{
struct iio_dma_buffer_queue *queue = block->queue;
unsigned long flags;
+ bool cookie;
+
+ cookie = dma_fence_begin_signalling();
spin_lock_irqsave(&queue->list_lock, flags);
_iio_dma_buffer_block_done(block);
spin_unlock_irqrestore(&queue->list_lock, flags);
+ if (!block->fileio)
+ iio_buffer_signal_dmabuf_done(block->fence, 0);
+
iio_buffer_block_put_atomic(block);
iio_dma_buffer_queue_wake(queue);
+ dma_fence_end_signalling(cookie);
}
EXPORT_SYMBOL_GPL(iio_dma_buffer_block_done);
@@ -243,17 +265,27 @@ void iio_dma_buffer_block_list_abort(struct iio_dma_buffer_queue *queue,
{
struct iio_dma_buffer_block *block, *_block;
unsigned long flags;
+ bool cookie;
+
+ cookie = dma_fence_begin_signalling();
spin_lock_irqsave(&queue->list_lock, flags);
list_for_each_entry_safe(block, _block, list, head) {
list_del(&block->head);
block->bytes_used = 0;
_iio_dma_buffer_block_done(block);
+
+ if (!block->fileio)
+ iio_buffer_signal_dmabuf_done(block->fence, -EINTR);
iio_buffer_block_put_atomic(block);
}
spin_unlock_irqrestore(&queue->list_lock, flags);
+ if (queue->fileio.enabled)
+ queue->fileio.enabled = false;
+
iio_dma_buffer_queue_wake(queue);
+ dma_fence_end_signalling(cookie);
}
EXPORT_SYMBOL_GPL(iio_dma_buffer_block_list_abort);
@@ -273,6 +305,16 @@ static bool iio_dma_block_reusable(struct iio_dma_buffer_block *block)
}
}
+static bool iio_dma_buffer_can_use_fileio(struct iio_dma_buffer_queue *queue)
+{
+ /*
+ * Note that queue->num_dmabufs cannot increase while the queue is
+ * locked, it can only decrease, so it does not race against
+ * iio_dma_buffer_alloc_block().
+ */
+ return queue->fileio.enabled || !atomic_read(&queue->num_dmabufs);
+}
+
/**
* iio_dma_buffer_request_update() - DMA buffer request_update callback
* @buffer: The buffer which to request an update
@@ -299,6 +341,12 @@ int iio_dma_buffer_request_update(struct iio_buffer *buffer)
mutex_lock(&queue->lock);
+ queue->fileio.enabled = iio_dma_buffer_can_use_fileio(queue);
+
+ /* If DMABUFs were created, disable fileio interface */
+ if (!queue->fileio.enabled)
+ goto out_unlock;
+
/* Allocations are page aligned */
if (PAGE_ALIGN(queue->fileio.block_size) == PAGE_ALIGN(size))
try_reuse = true;
@@ -339,7 +387,7 @@ int iio_dma_buffer_request_update(struct iio_buffer *buffer)
}
if (!block) {
- block = iio_dma_buffer_alloc_block(queue, size);
+ block = iio_dma_buffer_alloc_block(queue, size, true);
if (!block) {
ret = -ENOMEM;
goto out_unlock;
@@ -412,8 +460,12 @@ static void iio_dma_buffer_submit_block(struct iio_dma_buffer_queue *queue,
block->state = IIO_BLOCK_STATE_ACTIVE;
iio_buffer_block_get(block);
+
ret = queue->ops->submit(queue, block);
if (ret) {
+ if (!block->fileio)
+ iio_buffer_signal_dmabuf_done(block->fence, ret);
+
/*
* This is a bit of a problem and there is not much we can do
* other then wait for the buffer to be disabled and re-enabled
@@ -646,6 +698,110 @@ size_t iio_dma_buffer_usage(struct iio_buffer *buf)
}
EXPORT_SYMBOL_GPL(iio_dma_buffer_usage);
+struct iio_dma_buffer_block *
+iio_dma_buffer_attach_dmabuf(struct iio_buffer *buffer,
+ struct dma_buf_attachment *attach)
+{
+ struct iio_dma_buffer_queue *queue = iio_buffer_to_queue(buffer);
+ struct iio_dma_buffer_block *block;
+
+ guard(mutex)(&queue->lock);
+
+ /*
+ * If the buffer is enabled and in fileio mode new blocks can't be
+ * allocated.
+ */
+ if (queue->fileio.enabled)
+ return ERR_PTR(-EBUSY);
+
+ block = iio_dma_buffer_alloc_block(queue, attach->dmabuf->size, false);
+ if (!block)
+ return ERR_PTR(-ENOMEM);
+
+ /* Free memory that might be in use for fileio mode */
+ iio_dma_buffer_fileio_free(queue);
+
+ return block;
+}
+EXPORT_SYMBOL_GPL(iio_dma_buffer_attach_dmabuf);
+
+void iio_dma_buffer_detach_dmabuf(struct iio_buffer *buffer,
+ struct iio_dma_buffer_block *block)
+{
+ block->state = IIO_BLOCK_STATE_DEAD;
+ iio_buffer_block_put_atomic(block);
+}
+EXPORT_SYMBOL_GPL(iio_dma_buffer_detach_dmabuf);
+
+static int iio_dma_can_enqueue_block(struct iio_dma_buffer_block *block)
+{
+ struct iio_dma_buffer_queue *queue = block->queue;
+
+ /* If in fileio mode buffers can't be enqueued. */
+ if (queue->fileio.enabled)
+ return -EBUSY;
+
+ switch (block->state) {
+ case IIO_BLOCK_STATE_QUEUED:
+ return -EPERM;
+ case IIO_BLOCK_STATE_ACTIVE:
+ case IIO_BLOCK_STATE_DEAD:
+ return -EBUSY;
+ case IIO_BLOCK_STATE_DONE:
+ break;
+ }
+
+ return 0;
+}
+
+int iio_dma_buffer_enqueue_dmabuf(struct iio_buffer *buffer,
+ struct iio_dma_buffer_block *block,
+ struct dma_fence *fence,
+ struct sg_table *sgt,
+ size_t size, bool cyclic)
+{
+ struct iio_dma_buffer_queue *queue = iio_buffer_to_queue(buffer);
+ bool cookie;
+ int ret;
+
+ WARN_ON(!mutex_is_locked(&queue->lock));
+
+ cookie = dma_fence_begin_signalling();
+
+ ret = iio_dma_can_enqueue_block(block);
+ if (ret < 0)
+ goto out_end_signalling;
+
+ block->bytes_used = size;
+ block->cyclic = cyclic;
+ block->sg_table = sgt;
+ block->fence = fence;
+
+ iio_dma_buffer_enqueue(queue, block);
+
+out_end_signalling:
+ dma_fence_end_signalling(cookie);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(iio_dma_buffer_enqueue_dmabuf);
+
+void iio_dma_buffer_lock_queue(struct iio_buffer *buffer)
+{
+ struct iio_dma_buffer_queue *queue = iio_buffer_to_queue(buffer);
+
+ mutex_lock(&queue->lock);
+}
+EXPORT_SYMBOL_GPL(iio_dma_buffer_lock_queue);
+
+void iio_dma_buffer_unlock_queue(struct iio_buffer *buffer)
+{
+ struct iio_dma_buffer_queue *queue = iio_buffer_to_queue(buffer);
+
+ mutex_unlock(&queue->lock);
+}
+EXPORT_SYMBOL_GPL(iio_dma_buffer_unlock_queue);
+
/**
* iio_dma_buffer_set_bytes_per_datum() - DMA buffer set_bytes_per_datum callback
* @buffer: Buffer to set the bytes-per-datum for
diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c
index 918f6f8d65b6..12aa1412dfa0 100644
--- a/drivers/iio/buffer/industrialio-buffer-dmaengine.c
+++ b/drivers/iio/buffer/industrialio-buffer-dmaengine.c
@@ -65,25 +65,62 @@ static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue,
iio_buffer_to_dmaengine_buffer(&queue->buffer);
struct dma_async_tx_descriptor *desc;
enum dma_transfer_direction dma_dir;
+ struct scatterlist *sgl;
+ struct dma_vec *vecs;
size_t max_size;
dma_cookie_t cookie;
+ size_t len_total;
+ unsigned int i;
+ int nents;
max_size = min(block->size, dmaengine_buffer->max_size);
max_size = round_down(max_size, dmaengine_buffer->align);
- if (queue->buffer.direction == IIO_BUFFER_DIRECTION_IN) {
- block->bytes_used = max_size;
+ if (queue->buffer.direction == IIO_BUFFER_DIRECTION_IN)
dma_dir = DMA_DEV_TO_MEM;
- } else {
+ else
dma_dir = DMA_MEM_TO_DEV;
- }
- if (!block->bytes_used || block->bytes_used > max_size)
- return -EINVAL;
+ if (block->sg_table) {
+ sgl = block->sg_table->sgl;
+ nents = sg_nents_for_len(sgl, block->bytes_used);
+ if (nents < 0)
+ return nents;
+
+ vecs = kmalloc_array(nents, sizeof(*vecs), GFP_ATOMIC);
+ if (!vecs)
+ return -ENOMEM;
+
+ len_total = block->bytes_used;
+
+ for (i = 0; i < nents; i++) {
+ vecs[i].addr = sg_dma_address(sgl);
+ vecs[i].len = min(sg_dma_len(sgl), len_total);
+ len_total -= vecs[i].len;
+
+ sgl = sg_next(sgl);
+ }
- desc = dmaengine_prep_slave_single(dmaengine_buffer->chan,
- block->phys_addr, block->bytes_used, dma_dir,
- DMA_PREP_INTERRUPT);
+ desc = dmaengine_prep_peripheral_dma_vec(dmaengine_buffer->chan,
+ vecs, nents, dma_dir,
+ DMA_PREP_INTERRUPT);
+ kfree(vecs);
+ } else {
+ max_size = min(block->size, dmaengine_buffer->max_size);
+ max_size = round_down(max_size, dmaengine_buffer->align);
+
+ if (queue->buffer.direction == IIO_BUFFER_DIRECTION_IN)
+ block->bytes_used = max_size;
+
+ if (!block->bytes_used || block->bytes_used > max_size)
+ return -EINVAL;
+
+ desc = dmaengine_prep_slave_single(dmaengine_buffer->chan,
+ block->phys_addr,
+ block->bytes_used,
+ dma_dir,
+ DMA_PREP_INTERRUPT);
+ }
if (!desc)
return -ENOMEM;
@@ -133,6 +170,13 @@ static const struct iio_buffer_access_funcs iio_dmaengine_buffer_ops = {
.space_available = iio_dma_buffer_usage,
.release = iio_dmaengine_buffer_release,
+ .enqueue_dmabuf = iio_dma_buffer_enqueue_dmabuf,
+ .attach_dmabuf = iio_dma_buffer_attach_dmabuf,
+ .detach_dmabuf = iio_dma_buffer_detach_dmabuf,
+
+ .lock_queue = iio_dma_buffer_lock_queue,
+ .unlock_queue = iio_dma_buffer_unlock_queue,
+
.modes = INDIO_BUFFER_HARDWARE,
.flags = INDIO_BUFFER_FLAG_FIXED_WATERMARK,
};
diff --git a/drivers/iio/common/scmi_sensors/scmi_iio.c b/drivers/iio/common/scmi_sensors/scmi_iio.c
index 0c2caf3570db..7190eaede7fb 100644
--- a/drivers/iio/common/scmi_sensors/scmi_iio.c
+++ b/drivers/iio/common/scmi_sensors/scmi_iio.c
@@ -626,12 +626,10 @@ scmi_alloc_iiodev(struct scmi_device *sdev,
SCMI_PROTOCOL_SENSOR, SCMI_EVENT_SENSOR_UPDATE,
&sensor->sensor_info->id,
&sensor->sensor_update_nb);
- if (ret) {
- dev_err(&iiodev->dev,
- "Error in registering sensor update notifier for sensor %s err %d",
- sensor->sensor_info->name, ret);
- return ERR_PTR(ret);
- }
+ if (ret)
+ return dev_err_ptr_probe(&iiodev->dev, ret,
+ "Error in registering sensor update notifier for sensor %s\n",
+ sensor->sensor_info->name);
scmi_iio_set_timestamp_channel(&iio_channels[i], i);
iiodev->channels = iio_channels;
@@ -653,10 +651,9 @@ static int scmi_iio_dev_probe(struct scmi_device *sdev)
return -ENODEV;
sensor_ops = handle->devm_protocol_get(sdev, SCMI_PROTOCOL_SENSOR, &ph);
- if (IS_ERR(sensor_ops)) {
- dev_err(dev, "SCMI device has no sensor interface\n");
- return PTR_ERR(sensor_ops);
- }
+ if (IS_ERR(sensor_ops))
+ return dev_err_probe(dev, PTR_ERR(sensor_ops),
+ "SCMI device has no sensor interface\n");
nr_sensors = sensor_ops->count_get(ph);
if (!nr_sensors) {
@@ -667,8 +664,8 @@ static int scmi_iio_dev_probe(struct scmi_device *sdev)
for (i = 0; i < nr_sensors; i++) {
sensor_info = sensor_ops->info_get(ph, i);
if (!sensor_info) {
- dev_err(dev, "SCMI sensor %d has missing info\n", i);
- return -EINVAL;
+ return dev_err_probe(dev, -EINVAL,
+ "SCMI sensor %d has missing info\n", i);
}
/* This driver only supports 3-axis accel and gyro, skipping other sensors */
@@ -683,29 +680,25 @@ static int scmi_iio_dev_probe(struct scmi_device *sdev)
scmi_iio_dev = scmi_alloc_iiodev(sdev, sensor_ops, ph,
sensor_info);
if (IS_ERR(scmi_iio_dev)) {
- dev_err(dev,
- "failed to allocate IIO device for sensor %s: %ld\n",
- sensor_info->name, PTR_ERR(scmi_iio_dev));
- return PTR_ERR(scmi_iio_dev);
+ return dev_err_probe(dev, PTR_ERR(scmi_iio_dev),
+ "failed to allocate IIO device for sensor %s\n",
+ sensor_info->name);
}
err = devm_iio_kfifo_buffer_setup(&scmi_iio_dev->dev,
scmi_iio_dev,
&scmi_iio_buffer_ops);
if (err < 0) {
- dev_err(dev,
- "IIO buffer setup error at sensor %s: %d\n",
- sensor_info->name, err);
- return err;
+ return dev_err_probe(dev, err,
+ "IIO buffer setup error at sensor %s\n",
+ sensor_info->name);
}
err = devm_iio_device_register(dev, scmi_iio_dev);
- if (err) {
- dev_err(dev,
- "IIO device registration failed at sensor %s: %d\n",
- sensor_info->name, err);
- return err;
- }
+ if (err)
+ return dev_err_probe(dev, err,
+ "IIO device registration failed at sensor %s\n",
+ sensor_info->name);
}
return err;
}
diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c
index c77d7bdcc121..c69399ac6657 100644
--- a/drivers/iio/common/st_sensors/st_sensors_core.c
+++ b/drivers/iio/common/st_sensors/st_sensors_core.c
@@ -606,10 +606,9 @@ int st_sensors_verify_id(struct iio_dev *indio_dev)
}
if (sdata->sensor_settings->wai != wai) {
- dev_err(&indio_dev->dev,
+ dev_warn(&indio_dev->dev,
"%s: WhoAmI mismatch (0x%x).\n",
indio_dev->name, wai);
- return -EINVAL;
}
}
diff --git a/drivers/iio/dac/ad3552r.c b/drivers/iio/dac/ad3552r.c
index ddc6c262f801..bd37d304ca70 100644
--- a/drivers/iio/dac/ad3552r.c
+++ b/drivers/iio/dac/ad3552r.c
@@ -857,15 +857,9 @@ static int ad3552r_configure_custom_gain(struct ad3552r_desc *dac,
return 0;
}
-static void ad3552r_reg_disable(void *reg)
-{
- regulator_disable(reg);
-}
-
static int ad3552r_configure_device(struct ad3552r_desc *dac)
{
struct device *dev = &dac->spi->dev;
- struct regulator *vref;
int err, cnt = 0, voltage, delta = 100000;
u32 vals[2], val, ch;
@@ -874,30 +868,16 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac)
return dev_err_probe(dev, PTR_ERR(dac->gpio_ldac),
"Error getting gpio ldac");
- vref = devm_regulator_get_optional(dev, "vref");
- if (IS_ERR(vref)) {
- if (PTR_ERR(vref) != -ENODEV)
- return dev_err_probe(dev, PTR_ERR(vref),
- "Error getting vref");
+ voltage = devm_regulator_get_enable_read_voltage(dev, "vref");
+ if (voltage < 0 && voltage != -ENODEV)
+ return dev_err_probe(dev, voltage, "Error getting vref voltage\n");
+ if (voltage == -ENODEV) {
if (device_property_read_bool(dev, "adi,vref-out-en"))
val = AD3552R_INTERNAL_VREF_PIN_2P5V;
else
val = AD3552R_INTERNAL_VREF_PIN_FLOATING;
} else {
- err = regulator_enable(vref);
- if (err) {
- dev_err(dev, "Failed to enable external vref supply\n");
- return err;
- }
-
- err = devm_add_action_or_reset(dev, ad3552r_reg_disable, vref);
- if (err) {
- regulator_disable(vref);
- return err;
- }
-
- voltage = regulator_get_voltage(vref);
if (voltage > 2500000 + delta || voltage < 2500000 - delta) {
dev_warn(dev, "vref-supply must be 2.5V");
return -EINVAL;
diff --git a/drivers/iio/dac/adi-axi-dac.c b/drivers/iio/dac/adi-axi-dac.c
index 880d83a014a1..6d56428e623d 100644
--- a/drivers/iio/dac/adi-axi-dac.c
+++ b/drivers/iio/dac/adi-axi-dac.c
@@ -545,7 +545,8 @@ static int axi_dac_probe(struct platform_device *pdev)
clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(clk))
- return PTR_ERR(clk);
+ return dev_err_probe(&pdev->dev, PTR_ERR(clk),
+ "failed to get clock\n");
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
@@ -555,7 +556,8 @@ static int axi_dac_probe(struct platform_device *pdev)
st->regmap = devm_regmap_init_mmio(&pdev->dev, base,
&axi_dac_regmap_config);
if (IS_ERR(st->regmap))
- return PTR_ERR(st->regmap);
+ return dev_err_probe(&pdev->dev, PTR_ERR(st->regmap),
+ "failed to init register map\n");
/*
* Force disable the core. Up to the frontend to enable us. And we can
@@ -601,7 +603,8 @@ static int axi_dac_probe(struct platform_device *pdev)
mutex_init(&st->lock);
ret = devm_iio_backend_register(&pdev->dev, &axi_dac_generic, st);
if (ret)
- return ret;
+ return dev_err_probe(&pdev->dev, ret,
+ "failed to register iio backend\n");
dev_info(&pdev->dev, "AXI DAC IP core (%d.%.2d.%c) probed\n",
ADI_AXI_PCORE_VER_MAJOR(ver),
diff --git a/drivers/iio/dac/ltc2688.c b/drivers/iio/dac/ltc2688.c
index c4b1ba30f935..af50d2a95898 100644
--- a/drivers/iio/dac/ltc2688.c
+++ b/drivers/iio/dac/ltc2688.c
@@ -860,9 +860,8 @@ static int ltc2688_setup(struct ltc2688_state *st, struct regulator *vref)
/* bring device out of reset */
gpiod_set_value_cansleep(gpio, 0);
} else {
- ret = regmap_update_bits(st->regmap, LTC2688_CMD_CONFIG,
- LTC2688_CONFIG_RST,
- LTC2688_CONFIG_RST);
+ ret = regmap_set_bits(st->regmap, LTC2688_CMD_CONFIG,
+ LTC2688_CONFIG_RST);
if (ret)
return ret;
}
diff --git a/drivers/iio/dac/stm32-dac-core.c b/drivers/iio/dac/stm32-dac-core.c
index e150ac729154..2d567073996b 100644
--- a/drivers/iio/dac/stm32-dac-core.c
+++ b/drivers/iio/dac/stm32-dac-core.c
@@ -200,9 +200,8 @@ static int stm32_dac_core_resume(struct device *dev)
if (priv->common.hfsel) {
/* restore hfsel (maybe lost under low power state) */
- ret = regmap_update_bits(priv->common.regmap, STM32_DAC_CR,
- STM32H7_DAC_CR_HFSEL,
- STM32H7_DAC_CR_HFSEL);
+ ret = regmap_set_bits(priv->common.regmap, STM32_DAC_CR,
+ STM32H7_DAC_CR_HFSEL);
if (ret)
return ret;
}
diff --git a/drivers/iio/frequency/adf4350.c b/drivers/iio/frequency/adf4350.c
index 4abf80f75ef5..e13e64a5164c 100644
--- a/drivers/iio/frequency/adf4350.c
+++ b/drivers/iio/frequency/adf4350.c
@@ -19,6 +19,7 @@
#include <linux/gpio/consumer.h>
#include <asm/div64.h>
#include <linux/clk.h>
+#include <linux/clk-provider.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@@ -36,6 +37,9 @@ struct adf4350_state {
struct gpio_desc *lock_detect_gpiod;
struct adf4350_platform_data *pdata;
struct clk *clk;
+ struct clk *clkout;
+ const char *clk_out_name;
+ struct clk_hw hw;
unsigned long clkin;
unsigned long chspc; /* Channel Spacing */
unsigned long fpfd; /* Phase Frequency Detector */
@@ -61,6 +65,8 @@ struct adf4350_state {
__be32 val __aligned(IIO_DMA_MINALIGN);
};
+#define to_adf4350_state(_hw) container_of(_hw, struct adf4350_state, hw)
+
static struct adf4350_platform_data default_pdata = {
.channel_spacing = 10000,
.r2_user_settings = ADF4350_REG2_PD_POLARITY_POS |
@@ -381,6 +387,113 @@ static const struct iio_info adf4350_info = {
.debugfs_reg_access = &adf4350_reg_access,
};
+static void adf4350_clk_del_provider(void *data)
+{
+ struct adf4350_state *st = data;
+
+ of_clk_del_provider(st->spi->dev.of_node);
+}
+
+static unsigned long adf4350_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct adf4350_state *st = to_adf4350_state(hw);
+ unsigned long long tmp;
+
+ tmp = (u64)(st->r0_int * st->r1_mod + st->r0_fract) * st->fpfd;
+ do_div(tmp, st->r1_mod * (1 << st->r4_rf_div_sel));
+
+ return tmp;
+}
+
+static int adf4350_clk_set_rate(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct adf4350_state *st = to_adf4350_state(hw);
+
+ if (parent_rate == 0 || parent_rate > ADF4350_MAX_FREQ_REFIN)
+ return -EINVAL;
+
+ st->clkin = parent_rate;
+
+ return adf4350_set_freq(st, rate);
+}
+
+static int adf4350_clk_prepare(struct clk_hw *hw)
+{
+ struct adf4350_state *st = to_adf4350_state(hw);
+
+ st->regs[ADF4350_REG2] &= ~ADF4350_REG2_POWER_DOWN_EN;
+
+ return adf4350_sync_config(st);
+}
+
+static void adf4350_clk_unprepare(struct clk_hw *hw)
+{
+ struct adf4350_state *st = to_adf4350_state(hw);
+
+ st->regs[ADF4350_REG2] |= ADF4350_REG2_POWER_DOWN_EN;
+
+ adf4350_sync_config(st);
+}
+
+static int adf4350_clk_is_enabled(struct clk_hw *hw)
+{
+ struct adf4350_state *st = to_adf4350_state(hw);
+
+ return (st->regs[ADF4350_REG2] & ADF4350_REG2_POWER_DOWN_EN);
+}
+
+static const struct clk_ops adf4350_clk_ops = {
+ .recalc_rate = adf4350_clk_recalc_rate,
+ .set_rate = adf4350_clk_set_rate,
+ .prepare = adf4350_clk_prepare,
+ .unprepare = adf4350_clk_unprepare,
+ .is_enabled = adf4350_clk_is_enabled,
+};
+
+static int adf4350_clk_register(struct adf4350_state *st)
+{
+ struct spi_device *spi = st->spi;
+ struct clk_init_data init;
+ struct clk *clk;
+ const char *parent_name;
+ int ret;
+
+ if (!device_property_present(&spi->dev, "#clock-cells"))
+ return 0;
+
+ if (device_property_read_string(&spi->dev, "clock-output-names", &init.name)) {
+ init.name = devm_kasprintf(&spi->dev, GFP_KERNEL, "%s-clk",
+ fwnode_get_name(dev_fwnode(&spi->dev)));
+ if (!init.name)
+ return -ENOMEM;
+ }
+
+ parent_name = of_clk_get_parent_name(spi->dev.of_node, 0);
+ if (!parent_name)
+ return -EINVAL;
+
+ init.ops = &adf4350_clk_ops;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+ init.flags = CLK_SET_RATE_PARENT;
+
+ st->hw.init = &init;
+ clk = devm_clk_register(&spi->dev, &st->hw);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ ret = of_clk_add_provider(spi->dev.of_node, of_clk_src_simple_get, clk);
+ if (ret)
+ return ret;
+
+ st->clkout = clk;
+
+ return devm_add_action_or_reset(&spi->dev, adf4350_clk_del_provider, st);
+}
+
static struct adf4350_platform_data *adf4350_parse_dt(struct device *dev)
{
struct adf4350_platform_data *pdata;
@@ -522,8 +635,6 @@ static int adf4350_probe(struct spi_device *spi)
indio_dev->info = &adf4350_info;
indio_dev->modes = INDIO_DIRECT_MODE;
- indio_dev->channels = &adf4350_chan;
- indio_dev->num_channels = 1;
mutex_init(&st->lock);
@@ -551,6 +662,15 @@ static int adf4350_probe(struct spi_device *spi)
return ret;
}
+ ret = adf4350_clk_register(st);
+ if (ret)
+ return ret;
+
+ if (!st->clkout) {
+ indio_dev->channels = &adf4350_chan;
+ indio_dev->num_channels = 1;
+ }
+
ret = devm_add_action_or_reset(&spi->dev, adf4350_power_down, indio_dev);
if (ret)
return dev_err_probe(&spi->dev, ret,
diff --git a/drivers/iio/gyro/adis16136.c b/drivers/iio/gyro/adis16136.c
index c95cf41be34b..da83adc684d0 100644
--- a/drivers/iio/gyro/adis16136.c
+++ b/drivers/iio/gyro/adis16136.c
@@ -221,13 +221,12 @@ static ssize_t adis16136_read_frequency(struct device *dev,
unsigned int freq;
int ret;
- adis_dev_lock(&adis16136->adis);
+ adis_dev_auto_lock(&adis16136->adis);
ret = __adis16136_get_freq(adis16136, &freq);
- adis_dev_unlock(&adis16136->adis);
if (ret)
return ret;
- return sprintf(buf, "%d\n", freq);
+ return sysfs_emit(buf, "%d\n", freq);
}
static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
@@ -251,21 +250,17 @@ static int adis16136_set_filter(struct iio_dev *indio_dev, int val)
unsigned int freq;
int i, ret;
- adis_dev_lock(&adis16136->adis);
+ adis_dev_auto_lock(&adis16136->adis);
ret = __adis16136_get_freq(adis16136, &freq);
if (ret)
- goto out_unlock;
+ return ret;
for (i = ARRAY_SIZE(adis16136_3db_divisors) - 1; i >= 1; i--) {
if (freq / adis16136_3db_divisors[i] >= val)
break;
}
- ret = __adis_write_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, i);
-out_unlock:
- adis_dev_unlock(&adis16136->adis);
-
- return ret;
+ return __adis_write_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, i);
}
static int adis16136_get_filter(struct iio_dev *indio_dev, int *val)
@@ -275,23 +270,20 @@ static int adis16136_get_filter(struct iio_dev *indio_dev, int *val)
uint16_t val16;
int ret;
- adis_dev_lock(&adis16136->adis);
+ adis_dev_auto_lock(&adis16136->adis);
ret = __adis_read_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT,
&val16);
if (ret)
- goto err_unlock;
+ return ret;
ret = __adis16136_get_freq(adis16136, &freq);
if (ret)
- goto err_unlock;
+ return ret;
*val = freq / adis16136_3db_divisors[val16 & 0x07];
-err_unlock:
- adis_dev_unlock(&adis16136->adis);
-
- return ret ? ret : IIO_VAL_INT;
+ return IIO_VAL_INT;
}
static int adis16136_read_raw(struct iio_dev *indio_dev,
diff --git a/drivers/iio/gyro/adis16260.c b/drivers/iio/gyro/adis16260.c
index 112d635b7dfd..495b64a27061 100644
--- a/drivers/iio/gyro/adis16260.c
+++ b/drivers/iio/gyro/adis16260.c
@@ -270,7 +270,6 @@ static int adis16260_write_raw(struct iio_dev *indio_dev,
{
struct adis16260 *adis16260 = iio_priv(indio_dev);
struct adis *adis = &adis16260->adis;
- int ret;
u8 addr;
u8 t;
@@ -288,7 +287,6 @@ static int adis16260_write_raw(struct iio_dev *indio_dev,
addr = adis16260_addresses[chan->scan_index][1];
return adis_write_reg_16(adis, addr, val);
case IIO_CHAN_INFO_SAMP_FREQ:
- adis_dev_lock(adis);
if (spi_get_device_id(adis->spi)->driver_data)
t = 256 / val;
else
@@ -298,15 +296,14 @@ static int adis16260_write_raw(struct iio_dev *indio_dev,
t = ADIS16260_SMPL_PRD_DIV_MASK;
else if (t > 0)
t--;
-
- if (t >= 0x0A)
- adis->spi->max_speed_hz = ADIS16260_SPI_SLOW;
- else
- adis->spi->max_speed_hz = ADIS16260_SPI_FAST;
- ret = __adis_write_reg_8(adis, ADIS16260_SMPL_PRD, t);
-
- adis_dev_unlock(adis);
- return ret;
+ adis_dev_auto_scoped_lock(adis) {
+ if (t >= 0x0A)
+ adis->spi->max_speed_hz = ADIS16260_SPI_SLOW;
+ else
+ adis->spi->max_speed_hz = ADIS16260_SPI_FAST;
+ return __adis_write_reg_8(adis, ADIS16260_SMPL_PRD, t);
+ }
+ unreachable();
}
return -EINVAL;
}
diff --git a/drivers/iio/gyro/bmg160_core.c b/drivers/iio/gyro/bmg160_core.c
index 0e2eb0e98235..10728d5ccae3 100644
--- a/drivers/iio/gyro/bmg160_core.c
+++ b/drivers/iio/gyro/bmg160_core.c
@@ -285,8 +285,8 @@ static int bmg160_chip_init(struct bmg160_data *data)
data->slope_thres = val;
/* Set default interrupt mode */
- ret = regmap_update_bits(data->regmap, BMG160_REG_INT_EN_1,
- BMG160_INT1_BIT_OD, 0);
+ ret = regmap_clear_bits(data->regmap, BMG160_REG_INT_EN_1,
+ BMG160_INT1_BIT_OD);
if (ret < 0) {
dev_err(dev, "Error updating bits in reg_int_en_1\n");
return ret;
diff --git a/drivers/iio/gyro/mpu3050-core.c b/drivers/iio/gyro/mpu3050-core.c
index a791ba3a693a..35af68b41408 100644
--- a/drivers/iio/gyro/mpu3050-core.c
+++ b/drivers/iio/gyro/mpu3050-core.c
@@ -197,8 +197,8 @@ static int mpu3050_start_sampling(struct mpu3050 *mpu3050)
int i;
/* Reset */
- ret = regmap_update_bits(mpu3050->map, MPU3050_PWR_MGM,
- MPU3050_PWR_MGM_RESET, MPU3050_PWR_MGM_RESET);
+ ret = regmap_set_bits(mpu3050->map, MPU3050_PWR_MGM,
+ MPU3050_PWR_MGM_RESET);
if (ret)
return ret;
@@ -513,12 +513,9 @@ static irqreturn_t mpu3050_trigger_handler(int irq, void *p)
"FIFO overflow! Emptying and resetting FIFO\n");
fifo_overflow = true;
/* Reset and enable the FIFO */
- ret = regmap_update_bits(mpu3050->map,
- MPU3050_USR_CTRL,
- MPU3050_USR_CTRL_FIFO_EN |
- MPU3050_USR_CTRL_FIFO_RST,
- MPU3050_USR_CTRL_FIFO_EN |
- MPU3050_USR_CTRL_FIFO_RST);
+ ret = regmap_set_bits(mpu3050->map, MPU3050_USR_CTRL,
+ MPU3050_USR_CTRL_FIFO_EN |
+ MPU3050_USR_CTRL_FIFO_RST);
if (ret) {
dev_info(mpu3050->dev, "error resetting FIFO\n");
goto out_trigger_unlock;
@@ -799,10 +796,8 @@ static int mpu3050_hw_init(struct mpu3050 *mpu3050)
u64 otp;
/* Reset */
- ret = regmap_update_bits(mpu3050->map,
- MPU3050_PWR_MGM,
- MPU3050_PWR_MGM_RESET,
- MPU3050_PWR_MGM_RESET);
+ ret = regmap_set_bits(mpu3050->map, MPU3050_PWR_MGM,
+ MPU3050_PWR_MGM_RESET);
if (ret)
return ret;
@@ -872,8 +867,8 @@ static int mpu3050_power_up(struct mpu3050 *mpu3050)
msleep(200);
/* Take device out of sleep mode */
- ret = regmap_update_bits(mpu3050->map, MPU3050_PWR_MGM,
- MPU3050_PWR_MGM_SLEEP, 0);
+ ret = regmap_clear_bits(mpu3050->map, MPU3050_PWR_MGM,
+ MPU3050_PWR_MGM_SLEEP);
if (ret) {
regulator_bulk_disable(ARRAY_SIZE(mpu3050->regs), mpu3050->regs);
dev_err(mpu3050->dev, "error setting power mode\n");
@@ -895,8 +890,8 @@ static int mpu3050_power_down(struct mpu3050 *mpu3050)
* then we would be wasting power unless we go to sleep mode
* first.
*/
- ret = regmap_update_bits(mpu3050->map, MPU3050_PWR_MGM,
- MPU3050_PWR_MGM_SLEEP, MPU3050_PWR_MGM_SLEEP);
+ ret = regmap_set_bits(mpu3050->map, MPU3050_PWR_MGM,
+ MPU3050_PWR_MGM_SLEEP);
if (ret)
dev_err(mpu3050->dev, "error putting to sleep\n");
@@ -997,11 +992,9 @@ static int mpu3050_drdy_trigger_set_state(struct iio_trigger *trig,
return ret;
/* Reset and enable the FIFO */
- ret = regmap_update_bits(mpu3050->map, MPU3050_USR_CTRL,
- MPU3050_USR_CTRL_FIFO_EN |
- MPU3050_USR_CTRL_FIFO_RST,
- MPU3050_USR_CTRL_FIFO_EN |
- MPU3050_USR_CTRL_FIFO_RST);
+ ret = regmap_set_bits(mpu3050->map, MPU3050_USR_CTRL,
+ MPU3050_USR_CTRL_FIFO_EN |
+ MPU3050_USR_CTRL_FIFO_RST);
if (ret)
return ret;
diff --git a/drivers/iio/health/afe4403.c b/drivers/iio/health/afe4403.c
index 1dbe48dae74e..52326dc521ac 100644
--- a/drivers/iio/health/afe4403.c
+++ b/drivers/iio/health/afe4403.c
@@ -422,9 +422,8 @@ static int afe4403_suspend(struct device *dev)
struct afe4403_data *afe = iio_priv(indio_dev);
int ret;
- ret = regmap_update_bits(afe->regmap, AFE440X_CONTROL2,
- AFE440X_CONTROL2_PDN_AFE,
- AFE440X_CONTROL2_PDN_AFE);
+ ret = regmap_set_bits(afe->regmap, AFE440X_CONTROL2,
+ AFE440X_CONTROL2_PDN_AFE);
if (ret)
return ret;
@@ -449,8 +448,8 @@ static int afe4403_resume(struct device *dev)
return ret;
}
- ret = regmap_update_bits(afe->regmap, AFE440X_CONTROL2,
- AFE440X_CONTROL2_PDN_AFE, 0);
+ ret = regmap_clear_bits(afe->regmap, AFE440X_CONTROL2,
+ AFE440X_CONTROL2_PDN_AFE);
if (ret)
return ret;
diff --git a/drivers/iio/health/afe4404.c b/drivers/iio/health/afe4404.c
index 390fbb6effaf..7f69baa1ed53 100644
--- a/drivers/iio/health/afe4404.c
+++ b/drivers/iio/health/afe4404.c
@@ -430,9 +430,8 @@ static int afe4404_suspend(struct device *dev)
struct afe4404_data *afe = iio_priv(indio_dev);
int ret;
- ret = regmap_update_bits(afe->regmap, AFE440X_CONTROL2,
- AFE440X_CONTROL2_PDN_AFE,
- AFE440X_CONTROL2_PDN_AFE);
+ ret = regmap_set_bits(afe->regmap, AFE440X_CONTROL2,
+ AFE440X_CONTROL2_PDN_AFE);
if (ret)
return ret;
@@ -457,8 +456,8 @@ static int afe4404_resume(struct device *dev)
return ret;
}
- ret = regmap_update_bits(afe->regmap, AFE440X_CONTROL2,
- AFE440X_CONTROL2_PDN_AFE, 0);
+ ret = regmap_clear_bits(afe->regmap, AFE440X_CONTROL2,
+ AFE440X_CONTROL2_PDN_AFE);
if (ret)
return ret;
diff --git a/drivers/iio/health/max30100.c b/drivers/iio/health/max30100.c
index 1dc0df21450d..e08d143a707c 100644
--- a/drivers/iio/health/max30100.c
+++ b/drivers/iio/health/max30100.c
@@ -363,9 +363,8 @@ static int max30100_get_temp(struct max30100_data *data, int *val)
int ret;
/* start acquisition */
- ret = regmap_update_bits(data->regmap, MAX30100_REG_MODE_CONFIG,
- MAX30100_REG_MODE_CONFIG_TEMP_EN,
- MAX30100_REG_MODE_CONFIG_TEMP_EN);
+ ret = regmap_set_bits(data->regmap, MAX30100_REG_MODE_CONFIG,
+ MAX30100_REG_MODE_CONFIG_TEMP_EN);
if (ret)
return ret;
diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
index 6616729af5b7..07a343e35a81 100644
--- a/drivers/iio/health/max30102.c
+++ b/drivers/iio/health/max30102.c
@@ -448,9 +448,8 @@ static int max30102_get_temp(struct max30102_data *data, int *val, bool en)
}
/* start acquisition */
- ret = regmap_update_bits(data->regmap, MAX30102_REG_TEMP_CONFIG,
- MAX30102_REG_TEMP_CONFIG_TEMP_EN,
- MAX30102_REG_TEMP_CONFIG_TEMP_EN);
+ ret = regmap_set_bits(data->regmap, MAX30102_REG_TEMP_CONFIG,
+ MAX30102_REG_TEMP_CONFIG_TEMP_EN);
if (ret)
goto out;
diff --git a/drivers/iio/iio_core.h b/drivers/iio/iio_core.h
index 1a38b1915e7a..b7d5f4f0fada 100644
--- a/drivers/iio/iio_core.h
+++ b/drivers/iio/iio_core.h
@@ -34,6 +34,10 @@ void iio_device_ioctl_handler_register(struct iio_dev *indio_dev,
struct iio_ioctl_handler *h);
void iio_device_ioctl_handler_unregister(struct iio_ioctl_handler *h);
+ssize_t do_iio_read_channel_label(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *c,
+ char *buf);
+
int __iio_add_chan_devattr(const char *postfix,
struct iio_chan_spec const *chan,
ssize_t (*func)(struct device *dev,
diff --git a/drivers/iio/imu/adis.c b/drivers/iio/imu/adis.c
index 495caf4ce87a..876848b42f69 100644
--- a/drivers/iio/imu/adis.c
+++ b/drivers/iio/imu/adis.c
@@ -466,17 +466,17 @@ int adis_single_conversion(struct iio_dev *indio_dev,
unsigned int uval;
int ret;
- mutex_lock(&adis->state_lock);
+ guard(mutex)(&adis->state_lock);
ret = __adis_read_reg(adis, chan->address, &uval,
chan->scan_type.storagebits / 8);
if (ret)
- goto err_unlock;
+ return ret;
if (uval & error_mask) {
ret = __adis_check_status(adis);
if (ret)
- goto err_unlock;
+ return ret;
}
if (chan->scan_type.sign == 's')
@@ -484,10 +484,7 @@ int adis_single_conversion(struct iio_dev *indio_dev,
else
*val = uval & ((1 << chan->scan_type.realbits) - 1);
- ret = IIO_VAL_INT;
-err_unlock:
- mutex_unlock(&adis->state_lock);
- return ret;
+ return IIO_VAL_INT;
}
EXPORT_SYMBOL_NS_GPL(adis_single_conversion, IIO_ADISLIB);
diff --git a/drivers/iio/imu/adis16400.c b/drivers/iio/imu/adis16400.c
index 3eda32e12a53..0bfd6205f5f6 100644
--- a/drivers/iio/imu/adis16400.c
+++ b/drivers/iio/imu/adis16400.c
@@ -497,41 +497,38 @@ static int adis16400_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val, int val2, long info)
{
struct adis16400_state *st = iio_priv(indio_dev);
- int ret, sps;
+ int sps;
switch (info) {
case IIO_CHAN_INFO_CALIBBIAS:
- ret = adis_write_reg_16(&st->adis,
- adis16400_addresses[chan->scan_index], val);
- return ret;
+ return adis_write_reg_16(&st->adis,
+ adis16400_addresses[chan->scan_index],
+ val);
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
/*
* Need to cache values so we can update if the frequency
* changes.
*/
- adis_dev_lock(&st->adis);
- st->filt_int = val;
- /* Work out update to current value */
- sps = st->variant->get_freq(st);
- if (sps < 0) {
- adis_dev_unlock(&st->adis);
- return sps;
+ adis_dev_auto_scoped_lock(&st->adis) {
+ st->filt_int = val;
+ /* Work out update to current value */
+ sps = st->variant->get_freq(st);
+ if (sps < 0)
+ return sps;
+
+ return __adis16400_set_filter(indio_dev, sps,
+ val * 1000 + val2 / 1000);
}
-
- ret = __adis16400_set_filter(indio_dev, sps,
- val * 1000 + val2 / 1000);
- adis_dev_unlock(&st->adis);
- return ret;
+ unreachable();
case IIO_CHAN_INFO_SAMP_FREQ:
sps = val * 1000 + val2 / 1000;
if (sps <= 0)
return -EINVAL;
- adis_dev_lock(&st->adis);
- ret = st->variant->set_freq(st, sps);
- adis_dev_unlock(&st->adis);
- return ret;
+ adis_dev_auto_scoped_lock(&st->adis)
+ return st->variant->set_freq(st, sps);
+ unreachable();
default:
return -EINVAL;
}
@@ -596,29 +593,30 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
*val = st->variant->temp_offset;
return IIO_VAL_INT;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
- adis_dev_lock(&st->adis);
- /* Need both the number of taps and the sampling frequency */
- ret = __adis_read_reg_16(&st->adis,
- ADIS16400_SENS_AVG,
- &val16);
- if (ret) {
- adis_dev_unlock(&st->adis);
- return ret;
+ adis_dev_auto_scoped_lock(&st->adis) {
+ /*
+ * Need both the number of taps and the sampling
+ * frequency
+ */
+ ret = __adis_read_reg_16(&st->adis, ADIS16400_SENS_AVG,
+ &val16);
+ if (ret)
+ return ret;
+
+ ret = st->variant->get_freq(st);
+ if (ret)
+ return ret;
}
- ret = st->variant->get_freq(st);
- adis_dev_unlock(&st->adis);
- if (ret)
- return ret;
ret /= adis16400_3db_divisors[val16 & 0x07];
*val = ret / 1000;
*val2 = (ret % 1000) * 1000;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_SAMP_FREQ:
- adis_dev_lock(&st->adis);
- ret = st->variant->get_freq(st);
- adis_dev_unlock(&st->adis);
- if (ret)
- return ret;
+ adis_dev_auto_scoped_lock(&st->adis) {
+ ret = st->variant->get_freq(st);
+ if (ret)
+ return ret;
+ }
*val = ret / 1000;
*val2 = (ret % 1000) * 1000;
return IIO_VAL_INT_PLUS_MICRO;
diff --git a/drivers/iio/imu/adis16475.c b/drivers/iio/imu/adis16475.c
index cf73c6f46c79..482258ed5a3c 100644
--- a/drivers/iio/imu/adis16475.c
+++ b/drivers/iio/imu/adis16475.c
@@ -302,30 +302,25 @@ static int adis16475_get_freq(struct adis16475 *st, u32 *freq)
u16 dec;
u32 sample_rate = st->clk_freq;
- adis_dev_lock(&st->adis);
+ adis_dev_auto_lock(&st->adis);
if (st->sync_mode == ADIS16475_SYNC_SCALED) {
u16 sync_scale;
ret = __adis_read_reg_16(&st->adis, ADIS16475_REG_UP_SCALE, &sync_scale);
if (ret)
- goto error;
+ return ret;
sample_rate = st->clk_freq * sync_scale;
}
ret = __adis_read_reg_16(&st->adis, ADIS16475_REG_DEC_RATE, &dec);
if (ret)
- goto error;
-
- adis_dev_unlock(&st->adis);
+ return ret;
*freq = DIV_ROUND_CLOSEST(sample_rate, dec + 1);
return 0;
-error:
- adis_dev_unlock(&st->adis);
- return ret;
}
static int adis16475_set_freq(struct adis16475 *st, const u32 freq)
@@ -340,7 +335,7 @@ static int adis16475_set_freq(struct adis16475 *st, const u32 freq)
if (!freq)
return -EINVAL;
- adis_dev_lock(&st->adis);
+ adis_dev_auto_lock(&st->adis);
/*
* When using sync scaled mode, the input clock needs to be scaled so that we have
* an IMU sample rate between (optimally) int_clk - 100 and int_clk + 100.
@@ -385,7 +380,7 @@ static int adis16475_set_freq(struct adis16475 *st, const u32 freq)
sync_scale = scaled_rate / st->clk_freq;
ret = __adis_write_reg_16(&st->adis, ADIS16475_REG_UP_SCALE, sync_scale);
if (ret)
- goto error;
+ return ret;
sample_rate = scaled_rate;
}
@@ -400,9 +395,8 @@ static int adis16475_set_freq(struct adis16475 *st, const u32 freq)
ret = __adis_write_reg_16(&st->adis, ADIS16475_REG_DEC_RATE, dec);
if (ret)
- goto error;
+ return ret;
- adis_dev_unlock(&st->adis);
/*
* If decimation is used, then gyro and accel data will have meaningful
* bits on the LSB registers. This info is used on the trigger handler.
@@ -410,9 +404,6 @@ static int adis16475_set_freq(struct adis16475 *st, const u32 freq)
assign_bit(ADIS16475_LSB_DEC_MASK, &st->lsb_flag, dec);
return 0;
-error:
- adis_dev_unlock(&st->adis);
- return ret;
}
/* The values are approximated. */
@@ -541,19 +532,15 @@ static int adis16475_buffer_postdisable(struct iio_dev *indio_dev)
struct adis *adis = &st->adis;
int ret;
- adis_dev_lock(&st->adis);
+ adis_dev_auto_lock(&st->adis);
ret = __adis_update_bits(adis, ADIS16475_REG_FIFO_CTRL,
ADIS16575_FIFO_EN_MASK, (u16)ADIS16575_FIFO_EN(0));
if (ret)
- goto unlock;
-
- ret = __adis_write_reg_16(adis, ADIS16475_REG_GLOB_CMD,
- ADIS16575_FIFO_FLUSH_CMD);
+ return ret;
-unlock:
- adis_dev_unlock(&st->adis);
- return ret;
+ return __adis_write_reg_16(adis, ADIS16475_REG_GLOB_CMD,
+ ADIS16575_FIFO_FLUSH_CMD);
}
static const struct iio_buffer_setup_ops adis16475_buffer_ops = {
@@ -567,20 +554,18 @@ static int adis16475_set_watermark(struct iio_dev *indio_dev, unsigned int val)
int ret;
u16 wm_lvl;
- adis_dev_lock(&st->adis);
+ adis_dev_auto_lock(&st->adis);
val = min_t(unsigned int, val, ADIS16575_MAX_FIFO_WM);
wm_lvl = ADIS16575_WM_LVL(val - 1);
ret = __adis_update_bits(&st->adis, ADIS16475_REG_FIFO_CTRL, ADIS16575_WM_LVL_MASK, wm_lvl);
if (ret)
- goto unlock;
+ return ret;
st->fifo_watermark = val;
-unlock:
- adis_dev_unlock(&st->adis);
- return ret;
+ return 0;
}
static const u32 adis16475_calib_regs[] = {
@@ -1745,7 +1730,7 @@ static irqreturn_t adis16475_trigger_handler_with_fifo(int irq, void *p)
int ret;
u16 fifo_cnt, i;
- adis_dev_lock(&st->adis);
+ adis_dev_auto_lock(&st->adis);
ret = __adis_read_reg_16(adis, ADIS16575_REG_FIFO_CNT, &fifo_cnt);
if (ret)
@@ -1781,7 +1766,6 @@ unlock:
* reading data from registers will impact the FIFO reading.
*/
adis16475_burst32_check(st);
- adis_dev_unlock(&st->adis);
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c
index 56ca5a09fbbf..c59ef6f7cfd4 100644
--- a/drivers/iio/imu/adis16480.c
+++ b/drivers/iio/imu/adis16480.c
@@ -345,7 +345,7 @@ static int adis16480_set_freq(struct iio_dev *indio_dev, int val, int val2)
if (t == 0)
return -EINVAL;
- adis_dev_lock(&st->adis);
+ adis_dev_auto_lock(&st->adis);
/*
* When using PPS mode, the input clock needs to be scaled so that we have an IMU
* sample rate between (optimally) 4000 and 4250. After this, we can use the
@@ -388,7 +388,7 @@ static int adis16480_set_freq(struct iio_dev *indio_dev, int val, int val2)
sync_scale = scaled_rate / st->clk_freq;
ret = __adis_write_reg_16(&st->adis, ADIS16495_REG_SYNC_SCALE, sync_scale);
if (ret)
- goto error;
+ return ret;
sample_rate = scaled_rate;
}
@@ -400,10 +400,7 @@ static int adis16480_set_freq(struct iio_dev *indio_dev, int val, int val2)
if (t > st->chip_info->max_dec_rate)
t = st->chip_info->max_dec_rate;
- ret = __adis_write_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, t);
-error:
- adis_dev_unlock(&st->adis);
- return ret;
+ return __adis_write_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, t);
}
static int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2)
@@ -413,23 +410,21 @@ static int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2)
int ret;
unsigned int freq, sample_rate = st->clk_freq;
- adis_dev_lock(&st->adis);
+ adis_dev_auto_lock(&st->adis);
if (st->clk_mode == ADIS16480_CLK_PPS) {
u16 sync_scale;
ret = __adis_read_reg_16(&st->adis, ADIS16495_REG_SYNC_SCALE, &sync_scale);
if (ret)
- goto error;
+ return ret;
sample_rate = st->clk_freq * sync_scale;
}
ret = __adis_read_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, &t);
if (ret)
- goto error;
-
- adis_dev_unlock(&st->adis);
+ return ret;
freq = DIV_ROUND_CLOSEST(sample_rate, (t + 1));
@@ -437,9 +432,6 @@ static int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2)
*val2 = (freq % 1000) * 1000;
return IIO_VAL_INT_PLUS_MICRO;
-error:
- adis_dev_unlock(&st->adis);
- return ret;
}
enum {
@@ -630,11 +622,11 @@ static int adis16480_set_filter_freq(struct iio_dev *indio_dev,
offset = ad16480_filter_data[chan->scan_index][1];
enable_mask = BIT(offset + 2);
- adis_dev_lock(&st->adis);
+ adis_dev_auto_lock(&st->adis);
ret = __adis_read_reg_16(&st->adis, reg, &val);
if (ret)
- goto out_unlock;
+ return ret;
if (freq == 0) {
val &= ~enable_mask;
@@ -656,11 +648,7 @@ static int adis16480_set_filter_freq(struct iio_dev *indio_dev,
val |= enable_mask;
}
- ret = __adis_write_reg_16(&st->adis, reg, val);
-out_unlock:
- adis_dev_unlock(&st->adis);
-
- return ret;
+ return __adis_write_reg_16(&st->adis, reg, val);
}
static int adis16480_read_raw(struct iio_dev *indio_dev,
@@ -1355,29 +1343,26 @@ static irqreturn_t adis16480_trigger_handler(int irq, void *p)
u32 crc;
bool valid;
- adis_dev_lock(adis);
- if (adis->current_page != 0) {
- adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID);
- adis->tx[1] = 0;
- ret = spi_write(adis->spi, adis->tx, 2);
+ adis_dev_auto_scoped_lock(adis) {
+ if (adis->current_page != 0) {
+ adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID);
+ adis->tx[1] = 0;
+ ret = spi_write(adis->spi, adis->tx, 2);
+ if (ret) {
+ dev_err(dev, "Failed to change device page: %d\n", ret);
+ goto irq_done;
+ }
+
+ adis->current_page = 0;
+ }
+
+ ret = spi_sync(adis->spi, &adis->msg);
if (ret) {
- dev_err(dev, "Failed to change device page: %d\n", ret);
- adis_dev_unlock(adis);
+ dev_err(dev, "Failed to read data: %d\n", ret);
goto irq_done;
}
-
- adis->current_page = 0;
}
- ret = spi_sync(adis->spi, &adis->msg);
- if (ret) {
- dev_err(dev, "Failed to read data: %d\n", ret);
- adis_dev_unlock(adis);
- goto irq_done;
- }
-
- adis_dev_unlock(adis);
-
/*
* After making the burst request, the response can have one or two
* 16-bit responses containing the BURST_ID depending on the sclk. If
diff --git a/drivers/iio/imu/adis_buffer.c b/drivers/iio/imu/adis_buffer.c
index 871b78b225e2..b7c1cc04492a 100644
--- a/drivers/iio/imu/adis_buffer.c
+++ b/drivers/iio/imu/adis_buffer.c
@@ -126,6 +126,26 @@ int adis_update_scan_mode(struct iio_dev *indio_dev,
}
EXPORT_SYMBOL_NS_GPL(adis_update_scan_mode, IIO_ADISLIB);
+static int adis_paging_trigger_handler(struct adis *adis)
+{
+ int ret;
+
+ guard(mutex)(&adis->state_lock);
+ if (adis->current_page != 0) {
+ adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID);
+ adis->tx[1] = 0;
+ ret = spi_write(adis->spi, adis->tx, 2);
+ if (ret) {
+ dev_err(&adis->spi->dev, "Failed to change device page: %d\n", ret);
+ return ret;
+ }
+
+ adis->current_page = 0;
+ }
+
+ return spi_sync(adis->spi, &adis->msg);
+}
+
static irqreturn_t adis_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
@@ -133,25 +153,10 @@ static irqreturn_t adis_trigger_handler(int irq, void *p)
struct adis *adis = iio_device_get_drvdata(indio_dev);
int ret;
- if (adis->data->has_paging) {
- mutex_lock(&adis->state_lock);
- if (adis->current_page != 0) {
- adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID);
- adis->tx[1] = 0;
- ret = spi_write(adis->spi, adis->tx, 2);
- if (ret) {
- dev_err(&adis->spi->dev, "Failed to change device page: %d\n", ret);
- mutex_unlock(&adis->state_lock);
- goto irq_done;
- }
-
- adis->current_page = 0;
- }
- }
-
- ret = spi_sync(adis->spi, &adis->msg);
if (adis->data->has_paging)
- mutex_unlock(&adis->state_lock);
+ ret = adis_paging_trigger_handler(adis);
+ else
+ ret = spi_sync(adis->spi, &adis->msg);
if (ret) {
dev_err(&adis->spi->dev, "Failed to read data: %d", ret);
goto irq_done;
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c
index a8cf74c84c3c..aae7c56481a3 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c
@@ -274,9 +274,8 @@ int inv_icm42600_buffer_update_watermark(struct inv_icm42600_state *st)
/* restore watermark interrupt */
if (restore) {
- ret = regmap_update_bits(st->map, INV_ICM42600_REG_INT_SOURCE0,
- INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN,
- INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN);
+ ret = regmap_set_bits(st->map, INV_ICM42600_REG_INT_SOURCE0,
+ INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN);
if (ret)
return ret;
}
@@ -318,9 +317,8 @@ static int inv_icm42600_buffer_postenable(struct iio_dev *indio_dev)
}
/* set FIFO threshold interrupt */
- ret = regmap_update_bits(st->map, INV_ICM42600_REG_INT_SOURCE0,
- INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN,
- INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN);
+ ret = regmap_set_bits(st->map, INV_ICM42600_REG_INT_SOURCE0,
+ INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN);
if (ret)
goto out_unlock;
@@ -375,8 +373,8 @@ static int inv_icm42600_buffer_predisable(struct iio_dev *indio_dev)
goto out_unlock;
/* disable FIFO threshold interrupt */
- ret = regmap_update_bits(st->map, INV_ICM42600_REG_INT_SOURCE0,
- INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN, 0);
+ ret = regmap_clear_bits(st->map, INV_ICM42600_REG_INT_SOURCE0,
+ INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN);
if (ret)
goto out_unlock;
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
index 61f1f6d4c421..c3924cc6190e 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
@@ -496,9 +496,8 @@ static int inv_icm42600_setup(struct inv_icm42600_state *st,
return ret;
/* sensor data in big-endian (default) */
- ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG0,
- INV_ICM42600_INTF_CONFIG0_SENSOR_DATA_ENDIAN,
- INV_ICM42600_INTF_CONFIG0_SENSOR_DATA_ENDIAN);
+ ret = regmap_set_bits(st->map, INV_ICM42600_REG_INTF_CONFIG0,
+ INV_ICM42600_INTF_CONFIG0_SENSOR_DATA_ENDIAN);
if (ret)
return ret;
@@ -603,8 +602,8 @@ static int inv_icm42600_irq_init(struct inv_icm42600_state *st, int irq,
return ret;
/* Deassert async reset for proper INT pin operation (cf datasheet) */
- ret = regmap_update_bits(st->map, INV_ICM42600_REG_INT_CONFIG1,
- INV_ICM42600_INT_CONFIG1_ASYNC_RESET, 0);
+ ret = regmap_clear_bits(st->map, INV_ICM42600_REG_INT_CONFIG1,
+ INV_ICM42600_INT_CONFIG1_ASYNC_RESET);
if (ret)
return ret;
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c
index 8d33504d770f..ebb31b385881 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c
@@ -28,8 +28,8 @@ static int inv_icm42600_i2c_bus_setup(struct inv_icm42600_state *st)
INV_ICM42600_INTF_CONFIG6_MASK,
INV_ICM42600_INTF_CONFIG6_I3C_EN);
- ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG4,
- INV_ICM42600_INTF_CONFIG4_I3C_BUS_ONLY, 0);
+ ret = regmap_clear_bits(st->map, INV_ICM42600_REG_INTF_CONFIG4,
+ INV_ICM42600_INTF_CONFIG4_I3C_BUS_ONLY);
if (ret)
return ret;
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c
index cc2bf1799a46..eae5ff7a3cc1 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c
@@ -27,8 +27,8 @@ static int inv_icm42600_spi_bus_setup(struct inv_icm42600_state *st)
if (ret)
return ret;
- ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG4,
- INV_ICM42600_INTF_CONFIG4_I3C_BUS_ONLY, 0);
+ ret = regmap_clear_bits(st->map, INV_ICM42600_REG_INTF_CONFIG4,
+ INV_ICM42600_INTF_CONFIG4_I3C_BUS_ONLY);
if (ret)
return ret;
diff --git a/drivers/iio/industrialio-backend.c b/drivers/iio/industrialio-backend.c
index 929aff4040ed..efe05be284b6 100644
--- a/drivers/iio/industrialio-backend.c
+++ b/drivers/iio/industrialio-backend.c
@@ -561,11 +561,9 @@ struct iio_backend *devm_iio_backend_get(struct device *dev, const char *name)
}
fwnode = fwnode_find_reference(dev_fwnode(dev), "io-backends", index);
- if (IS_ERR(fwnode)) {
- dev_err_probe(dev, PTR_ERR(fwnode),
- "Cannot get Firmware reference\n");
- return ERR_CAST(fwnode);
- }
+ if (IS_ERR(fwnode))
+ return dev_err_cast_probe(dev, fwnode,
+ "Cannot get Firmware reference\n");
guard(mutex)(&iio_back_lock);
list_for_each_entry(back, &iio_back_list, entry) {
diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
index 0138b21b244f..d6fe105d2f40 100644
--- a/drivers/iio/industrialio-buffer.c
+++ b/drivers/iio/industrialio-buffer.c
@@ -9,15 +9,20 @@
* - Better memory allocation techniques?
* - Alternative access techniques?
*/
+#include <linux/atomic.h>
#include <linux/anon_inodes.h>
#include <linux/cleanup.h>
#include <linux/kernel.h>
#include <linux/export.h>
#include <linux/device.h>
+#include <linux/dma-buf.h>
+#include <linux/dma-fence.h>
+#include <linux/dma-resv.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/slab.h>
+#include <linux/mm.h>
#include <linux/poll.h>
#include <linux/sched/signal.h>
@@ -29,6 +34,34 @@
#include <linux/iio/buffer.h>
#include <linux/iio/buffer_impl.h>
+#define DMABUF_ENQUEUE_TIMEOUT_MS 5000
+
+MODULE_IMPORT_NS(DMA_BUF);
+
+struct iio_dmabuf_priv {
+ struct list_head entry;
+ struct kref ref;
+
+ struct iio_buffer *buffer;
+ struct iio_dma_buffer_block *block;
+
+ u64 context;
+
+ /* Spinlock used for locking the dma_fence */
+ spinlock_t lock;
+
+ struct dma_buf_attachment *attach;
+ struct sg_table *sgt;
+ enum dma_data_direction dir;
+ atomic_t seqno;
+};
+
+struct iio_dma_fence {
+ struct dma_fence base;
+ struct iio_dmabuf_priv *priv;
+ struct work_struct work;
+};
+
static const char * const iio_endian_prefix[] = {
[IIO_BE] = "be",
[IIO_LE] = "le",
@@ -333,6 +366,8 @@ void iio_buffer_init(struct iio_buffer *buffer)
{
INIT_LIST_HEAD(&buffer->demux_list);
INIT_LIST_HEAD(&buffer->buffer_list);
+ INIT_LIST_HEAD(&buffer->dmabufs);
+ mutex_init(&buffer->dmabufs_mutex);
init_waitqueue_head(&buffer->pollq);
kref_init(&buffer->ref);
if (!buffer->watermark)
@@ -1526,14 +1561,55 @@ static void iio_buffer_unregister_legacy_sysfs_groups(struct iio_dev *indio_dev)
kfree(iio_dev_opaque->legacy_scan_el_group.attrs);
}
+static void iio_buffer_dmabuf_release(struct kref *ref)
+{
+ struct iio_dmabuf_priv *priv = container_of(ref, struct iio_dmabuf_priv, ref);
+ struct dma_buf_attachment *attach = priv->attach;
+ struct iio_buffer *buffer = priv->buffer;
+ struct dma_buf *dmabuf = attach->dmabuf;
+
+ dma_resv_lock(dmabuf->resv, NULL);
+ dma_buf_unmap_attachment(attach, priv->sgt, priv->dir);
+ dma_resv_unlock(dmabuf->resv);
+
+ buffer->access->detach_dmabuf(buffer, priv->block);
+
+ dma_buf_detach(attach->dmabuf, attach);
+ dma_buf_put(dmabuf);
+ kfree(priv);
+}
+
+static void iio_buffer_dmabuf_get(struct dma_buf_attachment *attach)
+{
+ struct iio_dmabuf_priv *priv = attach->importer_priv;
+
+ kref_get(&priv->ref);
+}
+
+static void iio_buffer_dmabuf_put(struct dma_buf_attachment *attach)
+{
+ struct iio_dmabuf_priv *priv = attach->importer_priv;
+
+ kref_put(&priv->ref, iio_buffer_dmabuf_release);
+}
+
static int iio_buffer_chrdev_release(struct inode *inode, struct file *filep)
{
struct iio_dev_buffer_pair *ib = filep->private_data;
struct iio_dev *indio_dev = ib->indio_dev;
struct iio_buffer *buffer = ib->buffer;
+ struct iio_dmabuf_priv *priv, *tmp;
wake_up(&buffer->pollq);
+ guard(mutex)(&buffer->dmabufs_mutex);
+
+ /* Close all attached DMABUFs */
+ list_for_each_entry_safe(priv, tmp, &buffer->dmabufs, entry) {
+ list_del_init(&priv->entry);
+ iio_buffer_dmabuf_put(priv->attach);
+ }
+
kfree(ib);
clear_bit(IIO_BUSY_BIT_POS, &buffer->flags);
iio_device_put(indio_dev);
@@ -1541,11 +1617,393 @@ static int iio_buffer_chrdev_release(struct inode *inode, struct file *filep)
return 0;
}
+static int iio_dma_resv_lock(struct dma_buf *dmabuf, bool nonblock)
+{
+ if (!nonblock)
+ return dma_resv_lock_interruptible(dmabuf->resv, NULL);
+
+ if (!dma_resv_trylock(dmabuf->resv))
+ return -EBUSY;
+
+ return 0;
+}
+
+static struct dma_buf_attachment *
+iio_buffer_find_attachment(struct iio_dev_buffer_pair *ib,
+ struct dma_buf *dmabuf, bool nonblock)
+{
+ struct device *dev = ib->indio_dev->dev.parent;
+ struct iio_buffer *buffer = ib->buffer;
+ struct dma_buf_attachment *attach = NULL;
+ struct iio_dmabuf_priv *priv;
+
+ guard(mutex)(&buffer->dmabufs_mutex);
+
+ list_for_each_entry(priv, &buffer->dmabufs, entry) {
+ if (priv->attach->dev == dev
+ && priv->attach->dmabuf == dmabuf) {
+ attach = priv->attach;
+ break;
+ }
+ }
+
+ if (attach)
+ iio_buffer_dmabuf_get(attach);
+
+ return attach ?: ERR_PTR(-EPERM);
+}
+
+static int iio_buffer_attach_dmabuf(struct iio_dev_buffer_pair *ib,
+ int __user *user_fd, bool nonblock)
+{
+ struct iio_dev *indio_dev = ib->indio_dev;
+ struct iio_buffer *buffer = ib->buffer;
+ struct dma_buf_attachment *attach;
+ struct iio_dmabuf_priv *priv, *each;
+ struct dma_buf *dmabuf;
+ int err, fd;
+
+ if (!buffer->access->attach_dmabuf
+ || !buffer->access->detach_dmabuf
+ || !buffer->access->enqueue_dmabuf)
+ return -EPERM;
+
+ if (copy_from_user(&fd, user_fd, sizeof(fd)))
+ return -EFAULT;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ spin_lock_init(&priv->lock);
+ priv->context = dma_fence_context_alloc(1);
+
+ dmabuf = dma_buf_get(fd);
+ if (IS_ERR(dmabuf)) {
+ err = PTR_ERR(dmabuf);
+ goto err_free_priv;
+ }
+
+ attach = dma_buf_attach(dmabuf, indio_dev->dev.parent);
+ if (IS_ERR(attach)) {
+ err = PTR_ERR(attach);
+ goto err_dmabuf_put;
+ }
+
+ err = iio_dma_resv_lock(dmabuf, nonblock);
+ if (err)
+ goto err_dmabuf_detach;
+
+ priv->dir = buffer->direction == IIO_BUFFER_DIRECTION_IN
+ ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+
+ priv->sgt = dma_buf_map_attachment(attach, priv->dir);
+ if (IS_ERR(priv->sgt)) {
+ err = PTR_ERR(priv->sgt);
+ dev_err(&indio_dev->dev, "Unable to map attachment: %d\n", err);
+ goto err_resv_unlock;
+ }
+
+ kref_init(&priv->ref);
+ priv->buffer = buffer;
+ priv->attach = attach;
+ attach->importer_priv = priv;
+
+ priv->block = buffer->access->attach_dmabuf(buffer, attach);
+ if (IS_ERR(priv->block)) {
+ err = PTR_ERR(priv->block);
+ goto err_dmabuf_unmap_attachment;
+ }
+
+ dma_resv_unlock(dmabuf->resv);
+
+ mutex_lock(&buffer->dmabufs_mutex);
+
+ /*
+ * Check whether we already have an attachment for this driver/DMABUF
+ * combo. If we do, refuse to attach.
+ */
+ list_for_each_entry(each, &buffer->dmabufs, entry) {
+ if (each->attach->dev == indio_dev->dev.parent
+ && each->attach->dmabuf == dmabuf) {
+ /*
+ * We unlocked the reservation object, so going through
+ * the cleanup code would mean re-locking it first.
+ * At this stage it is simpler to free the attachment
+ * using iio_buffer_dma_put().
+ */
+ mutex_unlock(&buffer->dmabufs_mutex);
+ iio_buffer_dmabuf_put(attach);
+ return -EBUSY;
+ }
+ }
+
+ /* Otherwise, add the new attachment to our dmabufs list. */
+ list_add(&priv->entry, &buffer->dmabufs);
+ mutex_unlock(&buffer->dmabufs_mutex);
+
+ return 0;
+
+err_dmabuf_unmap_attachment:
+ dma_buf_unmap_attachment(attach, priv->sgt, priv->dir);
+err_resv_unlock:
+ dma_resv_unlock(dmabuf->resv);
+err_dmabuf_detach:
+ dma_buf_detach(dmabuf, attach);
+err_dmabuf_put:
+ dma_buf_put(dmabuf);
+err_free_priv:
+ kfree(priv);
+
+ return err;
+}
+
+static int iio_buffer_detach_dmabuf(struct iio_dev_buffer_pair *ib,
+ int __user *user_req, bool nonblock)
+{
+ struct iio_buffer *buffer = ib->buffer;
+ struct iio_dev *indio_dev = ib->indio_dev;
+ struct iio_dmabuf_priv *priv;
+ struct dma_buf *dmabuf;
+ int dmabuf_fd, ret = -EPERM;
+
+ if (copy_from_user(&dmabuf_fd, user_req, sizeof(dmabuf_fd)))
+ return -EFAULT;
+
+ dmabuf = dma_buf_get(dmabuf_fd);
+ if (IS_ERR(dmabuf))
+ return PTR_ERR(dmabuf);
+
+ guard(mutex)(&buffer->dmabufs_mutex);
+
+ list_for_each_entry(priv, &buffer->dmabufs, entry) {
+ if (priv->attach->dev == indio_dev->dev.parent
+ && priv->attach->dmabuf == dmabuf) {
+ list_del(&priv->entry);
+
+ /* Unref the reference from iio_buffer_attach_dmabuf() */
+ iio_buffer_dmabuf_put(priv->attach);
+ ret = 0;
+ break;
+ }
+ }
+
+ dma_buf_put(dmabuf);
+
+ return ret;
+}
+
+static const char *
+iio_buffer_dma_fence_get_driver_name(struct dma_fence *fence)
+{
+ return "iio";
+}
+
+static void iio_buffer_dma_fence_release(struct dma_fence *fence)
+{
+ struct iio_dma_fence *iio_fence =
+ container_of(fence, struct iio_dma_fence, base);
+
+ kfree(iio_fence);
+}
+
+static const struct dma_fence_ops iio_buffer_dma_fence_ops = {
+ .get_driver_name = iio_buffer_dma_fence_get_driver_name,
+ .get_timeline_name = iio_buffer_dma_fence_get_driver_name,
+ .release = iio_buffer_dma_fence_release,
+};
+
+static int iio_buffer_enqueue_dmabuf(struct iio_dev_buffer_pair *ib,
+ struct iio_dmabuf __user *iio_dmabuf_req,
+ bool nonblock)
+{
+ struct iio_buffer *buffer = ib->buffer;
+ struct iio_dmabuf iio_dmabuf;
+ struct dma_buf_attachment *attach;
+ struct iio_dmabuf_priv *priv;
+ struct iio_dma_fence *fence;
+ struct dma_buf *dmabuf;
+ unsigned long timeout;
+ bool cookie, cyclic, dma_to_ram;
+ long retl;
+ u32 seqno;
+ int ret;
+
+ if (copy_from_user(&iio_dmabuf, iio_dmabuf_req, sizeof(iio_dmabuf)))
+ return -EFAULT;
+
+ if (iio_dmabuf.flags & ~IIO_BUFFER_DMABUF_SUPPORTED_FLAGS)
+ return -EINVAL;
+
+ cyclic = iio_dmabuf.flags & IIO_BUFFER_DMABUF_CYCLIC;
+
+ /* Cyclic flag is only supported on output buffers */
+ if (cyclic && buffer->direction != IIO_BUFFER_DIRECTION_OUT)
+ return -EINVAL;
+
+ dmabuf = dma_buf_get(iio_dmabuf.fd);
+ if (IS_ERR(dmabuf))
+ return PTR_ERR(dmabuf);
+
+ if (!iio_dmabuf.bytes_used || iio_dmabuf.bytes_used > dmabuf->size) {
+ ret = -EINVAL;
+ goto err_dmabuf_put;
+ }
+
+ attach = iio_buffer_find_attachment(ib, dmabuf, nonblock);
+ if (IS_ERR(attach)) {
+ ret = PTR_ERR(attach);
+ goto err_dmabuf_put;
+ }
+
+ priv = attach->importer_priv;
+
+ fence = kmalloc(sizeof(*fence), GFP_KERNEL);
+ if (!fence) {
+ ret = -ENOMEM;
+ goto err_attachment_put;
+ }
+
+ fence->priv = priv;
+
+ seqno = atomic_add_return(1, &priv->seqno);
+
+ /*
+ * The transfers are guaranteed to be processed in the order they are
+ * enqueued, so we can use a simple incrementing sequence number for
+ * the dma_fence.
+ */
+ dma_fence_init(&fence->base, &iio_buffer_dma_fence_ops,
+ &priv->lock, priv->context, seqno);
+
+ ret = iio_dma_resv_lock(dmabuf, nonblock);
+ if (ret)
+ goto err_fence_put;
+
+ timeout = nonblock ? 0 : msecs_to_jiffies(DMABUF_ENQUEUE_TIMEOUT_MS);
+ dma_to_ram = buffer->direction == IIO_BUFFER_DIRECTION_IN;
+
+ /* Make sure we don't have writers */
+ retl = dma_resv_wait_timeout(dmabuf->resv,
+ dma_resv_usage_rw(dma_to_ram),
+ true, timeout);
+ if (retl == 0)
+ retl = -EBUSY;
+ if (retl < 0) {
+ ret = (int)retl;
+ goto err_resv_unlock;
+ }
+
+ if (buffer->access->lock_queue)
+ buffer->access->lock_queue(buffer);
+
+ ret = dma_resv_reserve_fences(dmabuf->resv, 1);
+ if (ret)
+ goto err_queue_unlock;
+
+ dma_resv_add_fence(dmabuf->resv, &fence->base,
+ dma_to_ram ? DMA_RESV_USAGE_WRITE : DMA_RESV_USAGE_READ);
+ dma_resv_unlock(dmabuf->resv);
+
+ cookie = dma_fence_begin_signalling();
+
+ ret = buffer->access->enqueue_dmabuf(buffer, priv->block, &fence->base,
+ priv->sgt, iio_dmabuf.bytes_used,
+ cyclic);
+ if (ret) {
+ /*
+ * DMABUF enqueue failed, but we already added the fence.
+ * Signal the error through the fence completion mechanism.
+ */
+ iio_buffer_signal_dmabuf_done(&fence->base, ret);
+ }
+
+ if (buffer->access->unlock_queue)
+ buffer->access->unlock_queue(buffer);
+
+ dma_fence_end_signalling(cookie);
+ dma_buf_put(dmabuf);
+
+ return ret;
+
+err_queue_unlock:
+ if (buffer->access->unlock_queue)
+ buffer->access->unlock_queue(buffer);
+err_resv_unlock:
+ dma_resv_unlock(dmabuf->resv);
+err_fence_put:
+ dma_fence_put(&fence->base);
+err_attachment_put:
+ iio_buffer_dmabuf_put(attach);
+err_dmabuf_put:
+ dma_buf_put(dmabuf);
+
+ return ret;
+}
+
+static void iio_buffer_cleanup(struct work_struct *work)
+{
+ struct iio_dma_fence *fence =
+ container_of(work, struct iio_dma_fence, work);
+ struct iio_dmabuf_priv *priv = fence->priv;
+ struct dma_buf_attachment *attach = priv->attach;
+
+ dma_fence_put(&fence->base);
+ iio_buffer_dmabuf_put(attach);
+}
+
+void iio_buffer_signal_dmabuf_done(struct dma_fence *fence, int ret)
+{
+ struct iio_dma_fence *iio_fence =
+ container_of(fence, struct iio_dma_fence, base);
+ bool cookie = dma_fence_begin_signalling();
+
+ /*
+ * Get a reference to the fence, so that it's not freed as soon as
+ * it's signaled.
+ */
+ dma_fence_get(fence);
+
+ fence->error = ret;
+ dma_fence_signal(fence);
+ dma_fence_end_signalling(cookie);
+
+ /*
+ * The fence will be unref'd in iio_buffer_cleanup.
+ * It can't be done here, as the unref functions might try to lock the
+ * resv object, which can deadlock.
+ */
+ INIT_WORK(&iio_fence->work, iio_buffer_cleanup);
+ schedule_work(&iio_fence->work);
+}
+EXPORT_SYMBOL_GPL(iio_buffer_signal_dmabuf_done);
+
+static long iio_buffer_chrdev_ioctl(struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ struct iio_dev_buffer_pair *ib = filp->private_data;
+ void __user *_arg = (void __user *)arg;
+ bool nonblock = filp->f_flags & O_NONBLOCK;
+
+ switch (cmd) {
+ case IIO_BUFFER_DMABUF_ATTACH_IOCTL:
+ return iio_buffer_attach_dmabuf(ib, _arg, nonblock);
+ case IIO_BUFFER_DMABUF_DETACH_IOCTL:
+ return iio_buffer_detach_dmabuf(ib, _arg, nonblock);
+ case IIO_BUFFER_DMABUF_ENQUEUE_IOCTL:
+ return iio_buffer_enqueue_dmabuf(ib, _arg, nonblock);
+ default:
+ return -EINVAL;
+ }
+}
+
static const struct file_operations iio_buffer_chrdev_fileops = {
.owner = THIS_MODULE,
.llseek = noop_llseek,
.read = iio_buffer_read,
.write = iio_buffer_write,
+ .unlocked_ioctl = iio_buffer_chrdev_ioctl,
+ .compat_ioctl = compat_ptr_ioctl,
.poll = iio_buffer_poll,
.release = iio_buffer_chrdev_release,
};
@@ -1994,6 +2452,7 @@ static void iio_buffer_release(struct kref *ref)
{
struct iio_buffer *buffer = container_of(ref, struct iio_buffer, ref);
+ mutex_destroy(&buffer->dmabufs_mutex);
buffer->access->release(buffer);
}
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index 2f185b386949..0f6cda7ffe45 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -727,22 +727,27 @@ ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals)
}
EXPORT_SYMBOL_GPL(iio_format_value);
-static ssize_t iio_read_channel_label(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+ssize_t do_iio_read_channel_label(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *c,
+ char *buf)
{
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-
if (indio_dev->info->read_label)
- return indio_dev->info->read_label(indio_dev, this_attr->c, buf);
+ return indio_dev->info->read_label(indio_dev, c, buf);
- if (this_attr->c->extend_name)
- return sysfs_emit(buf, "%s\n", this_attr->c->extend_name);
+ if (c->extend_name)
+ return sysfs_emit(buf, "%s\n", c->extend_name);
return -EINVAL;
}
+static ssize_t iio_read_channel_label(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return do_iio_read_channel_label(dev_to_iio_dev(dev),
+ to_iio_dev_attr(attr)->c, buf);
+}
+
static ssize_t iio_read_channel_info(struct device *dev,
struct device_attribute *attr,
char *buf)
diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
index 39cf26d69d17..9f484c94bc6e 100644
--- a/drivers/iio/inkern.c
+++ b/drivers/iio/inkern.c
@@ -1010,3 +1010,9 @@ ssize_t iio_write_channel_ext_info(struct iio_channel *chan, const char *attr,
chan->channel, buf, len);
}
EXPORT_SYMBOL_GPL(iio_write_channel_ext_info);
+
+ssize_t iio_read_channel_label(struct iio_channel *chan, char *buf)
+{
+ return do_iio_read_channel_label(chan->indio_dev, chan->channel, buf);
+}
+EXPORT_SYMBOL_GPL(iio_read_channel_label);
diff --git a/drivers/iio/light/adux1020.c b/drivers/iio/light/adux1020.c
index d4eb938c3bf5..2e0170be077a 100644
--- a/drivers/iio/light/adux1020.c
+++ b/drivers/iio/light/adux1020.c
@@ -539,9 +539,8 @@ static int adux1020_write_event_config(struct iio_dev *indio_dev,
* Trigger proximity interrupt when the intensity is above
* or below threshold
*/
- ret = regmap_update_bits(data->regmap, ADUX1020_REG_PROX_TYPE,
- ADUX1020_PROX_TYPE,
- ADUX1020_PROX_TYPE);
+ ret = regmap_set_bits(data->regmap, ADUX1020_REG_PROX_TYPE,
+ ADUX1020_PROX_TYPE);
if (ret < 0)
goto fail;
@@ -748,8 +747,8 @@ static int adux1020_chip_init(struct adux1020_data *data)
dev_dbg(&client->dev, "Detected ADUX1020 with chip id: 0x%04x\n", val);
- ret = regmap_update_bits(data->regmap, ADUX1020_REG_SW_RESET,
- ADUX1020_SW_RESET, ADUX1020_SW_RESET);
+ ret = regmap_set_bits(data->regmap, ADUX1020_REG_SW_RESET,
+ ADUX1020_SW_RESET);
if (ret < 0)
return ret;
@@ -764,8 +763,8 @@ static int adux1020_chip_init(struct adux1020_data *data)
return ret;
/* Use LED_IREF for proximity mode */
- ret = regmap_update_bits(data->regmap, ADUX1020_REG_LED_CURRENT,
- ADUX1020_LED_PIREF_EN, 0);
+ ret = regmap_clear_bits(data->regmap, ADUX1020_REG_LED_CURRENT,
+ ADUX1020_LED_PIREF_EN);
if (ret < 0)
return ret;
diff --git a/drivers/iio/light/iqs621-als.c b/drivers/iio/light/iqs621-als.c
index 004ea890a4b2..6de33feada3a 100644
--- a/drivers/iio/light/iqs621-als.c
+++ b/drivers/iio/light/iqs621-als.c
@@ -86,8 +86,8 @@ static int iqs621_als_init(struct iqs621_als_private *iqs621_als)
if (iqs621_als->prox_en)
event_mask |= iqs62x->dev_desc->ir_mask;
- return regmap_update_bits(iqs62x->regmap, IQS620_GLBL_EVENT_MASK,
- event_mask, 0);
+ return regmap_clear_bits(iqs62x->regmap, IQS620_GLBL_EVENT_MASK,
+ event_mask);
}
static int iqs621_als_notifier(struct notifier_block *notifier,
diff --git a/drivers/iio/light/isl29018.c b/drivers/iio/light/isl29018.c
index 43484c18b101..8dfc750e68c0 100644
--- a/drivers/iio/light/isl29018.c
+++ b/drivers/iio/light/isl29018.c
@@ -550,9 +550,9 @@ static int isl29018_chip_init(struct isl29018_chip *chip)
return -ENODEV;
/* Clear brownout bit */
- status = regmap_update_bits(chip->regmap,
- ISL29035_REG_DEVICE_ID,
- ISL29035_BOUT_MASK, 0);
+ status = regmap_clear_bits(chip->regmap,
+ ISL29035_REG_DEVICE_ID,
+ ISL29035_BOUT_MASK);
if (status < 0)
return status;
}
diff --git a/drivers/iio/light/st_uvis25_core.c b/drivers/iio/light/st_uvis25_core.c
index d4e17079b2f4..fba3997574bb 100644
--- a/drivers/iio/light/st_uvis25_core.c
+++ b/drivers/iio/light/st_uvis25_core.c
@@ -330,8 +330,8 @@ static int st_uvis25_suspend(struct device *dev)
struct iio_dev *iio_dev = dev_get_drvdata(dev);
struct st_uvis25_hw *hw = iio_priv(iio_dev);
- return regmap_update_bits(hw->regmap, ST_UVIS25_REG_CTRL1_ADDR,
- ST_UVIS25_REG_ODR_MASK, 0);
+ return regmap_clear_bits(hw->regmap, ST_UVIS25_REG_CTRL1_ADDR,
+ ST_UVIS25_REG_ODR_MASK);
}
static int st_uvis25_resume(struct device *dev)
diff --git a/drivers/iio/light/veml6030.c b/drivers/iio/light/veml6030.c
index 4be151308574..2e86d310952e 100644
--- a/drivers/iio/light/veml6030.c
+++ b/drivers/iio/light/veml6030.c
@@ -144,8 +144,8 @@ static const struct attribute_group veml6030_event_attr_group = {
static int veml6030_als_pwr_on(struct veml6030_data *data)
{
- return regmap_update_bits(data->regmap, VEML6030_REG_ALS_CONF,
- VEML6030_ALS_SD, 0);
+ return regmap_clear_bits(data->regmap, VEML6030_REG_ALS_CONF,
+ VEML6030_ALS_SD);
}
static int veml6030_als_shut_down(struct veml6030_data *data)
diff --git a/drivers/iio/magnetometer/ak8974.c b/drivers/iio/magnetometer/ak8974.c
index d802034c5402..961b1e0bfb13 100644
--- a/drivers/iio/magnetometer/ak8974.c
+++ b/drivers/iio/magnetometer/ak8974.c
@@ -327,10 +327,7 @@ static int ak8974_trigmeas(struct ak8974 *ak8974)
}
/* Force a measurement */
- return regmap_update_bits(ak8974->map,
- AK8974_CTRL3,
- AK8974_CTRL3_FORCE,
- AK8974_CTRL3_FORCE);
+ return regmap_set_bits(ak8974->map, AK8974_CTRL3, AK8974_CTRL3_FORCE);
}
static int ak8974_await_drdy(struct ak8974 *ak8974)
@@ -438,10 +435,7 @@ static int ak8974_selftest(struct ak8974 *ak8974)
}
/* Trigger self-test */
- ret = regmap_update_bits(ak8974->map,
- AK8974_CTRL3,
- AK8974_CTRL3_SELFTEST,
- AK8974_CTRL3_SELFTEST);
+ ret = regmap_set_bits(ak8974->map, AK8974_CTRL3, AK8974_CTRL3_SELFTEST);
if (ret) {
dev_err(dev, "could not write CTRL3\n");
return ret;
diff --git a/drivers/iio/magnetometer/mmc35240.c b/drivers/iio/magnetometer/mmc35240.c
index c57932db455f..dd480a4a5f98 100644
--- a/drivers/iio/magnetometer/mmc35240.c
+++ b/drivers/iio/magnetometer/mmc35240.c
@@ -186,9 +186,8 @@ static int mmc35240_hw_set(struct mmc35240_data *data, bool set)
* Recharge the capacitor at VCAP pin, requested to be issued
* before a SET/RESET command.
*/
- ret = regmap_update_bits(data->regmap, MMC35240_REG_CTRL0,
- MMC35240_CTRL0_REFILL_BIT,
- MMC35240_CTRL0_REFILL_BIT);
+ ret = regmap_set_bits(data->regmap, MMC35240_REG_CTRL0,
+ MMC35240_CTRL0_REFILL_BIT);
if (ret < 0)
return ret;
usleep_range(MMC35240_WAIT_CHARGE_PUMP, MMC35240_WAIT_CHARGE_PUMP + 1);
@@ -198,8 +197,7 @@ static int mmc35240_hw_set(struct mmc35240_data *data, bool set)
else
coil_bit = MMC35240_CTRL0_RESET_BIT;
- return regmap_update_bits(data->regmap, MMC35240_REG_CTRL0,
- coil_bit, coil_bit);
+ return regmap_set_bits(data->regmap, MMC35240_REG_CTRL0, coil_bit);
}
diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
index 50d71ad83f37..49081b729618 100644
--- a/drivers/iio/pressure/bmp280-core.c
+++ b/drivers/iio/pressure/bmp280-core.c
@@ -1645,8 +1645,8 @@ static int bmp580_nvmem_write_impl(void *priv, unsigned int offset, void *val,
goto exit;
/* Disable programming mode bit */
- ret = regmap_update_bits(data->regmap, BMP580_REG_NVM_ADDR,
- BMP580_NVM_PROG_EN, 0);
+ ret = regmap_clear_bits(data->regmap, BMP580_REG_NVM_ADDR,
+ BMP580_NVM_PROG_EN);
if (ret) {
dev_err(data->dev, "error resetting nvm write\n");
goto exit;
diff --git a/drivers/iio/proximity/sx9324.c b/drivers/iio/proximity/sx9324.c
index aa0d14a49d5e..629f83c37d59 100644
--- a/drivers/iio/proximity/sx9324.c
+++ b/drivers/iio/proximity/sx9324.c
@@ -835,9 +835,8 @@ static int sx9324_init_compensation(struct iio_dev *indio_dev)
int ret;
/* run the compensation phase on all channels */
- ret = regmap_update_bits(data->regmap, SX9324_REG_STAT2,
- SX9324_REG_STAT2_COMPSTAT_MASK,
- SX9324_REG_STAT2_COMPSTAT_MASK);
+ ret = regmap_set_bits(data->regmap, SX9324_REG_STAT2,
+ SX9324_REG_STAT2_COMPSTAT_MASK);
if (ret)
return ret;
diff --git a/drivers/iio/proximity/sx9360.c b/drivers/iio/proximity/sx9360.c
index 75a1c29f14eb..2b90bf45a201 100644
--- a/drivers/iio/proximity/sx9360.c
+++ b/drivers/iio/proximity/sx9360.c
@@ -672,9 +672,8 @@ static int sx9360_init_compensation(struct iio_dev *indio_dev)
int ret;
/* run the compensation phase on all channels */
- ret = regmap_update_bits(data->regmap, SX9360_REG_STAT,
- SX9360_REG_STAT_COMPSTAT_MASK,
- SX9360_REG_STAT_COMPSTAT_MASK);
+ ret = regmap_set_bits(data->regmap, SX9360_REG_STAT,
+ SX9360_REG_STAT_COMPSTAT_MASK);
if (ret)
return ret;
diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c
index b89d49defd7a..92630812ece2 100644
--- a/drivers/iio/proximity/sx9500.c
+++ b/drivers/iio/proximity/sx9500.c
@@ -209,7 +209,7 @@ static int sx9500_inc_users(struct sx9500_data *data, int *counter,
/* Bit is already active, nothing to do. */
return 0;
- return regmap_update_bits(data->regmap, reg, bitmask, bitmask);
+ return regmap_set_bits(data->regmap, reg, bitmask);
}
static int sx9500_dec_users(struct sx9500_data *data, int *counter,
@@ -220,7 +220,7 @@ static int sx9500_dec_users(struct sx9500_data *data, int *counter,
/* There are more users, do not deactivate. */
return 0;
- return regmap_update_bits(data->regmap, reg, bitmask, 0);
+ return regmap_clear_bits(data->regmap, reg, bitmask);
}
static int sx9500_inc_chan_users(struct sx9500_data *data, int chan)
@@ -795,8 +795,8 @@ static int sx9500_init_compensation(struct iio_dev *indio_dev)
int i, ret;
unsigned int val;
- ret = regmap_update_bits(data->regmap, SX9500_REG_PROX_CTRL0,
- SX9500_CHAN_MASK, SX9500_CHAN_MASK);
+ ret = regmap_set_bits(data->regmap, SX9500_REG_PROX_CTRL0,
+ SX9500_CHAN_MASK);
if (ret < 0)
return ret;
@@ -815,8 +815,8 @@ static int sx9500_init_compensation(struct iio_dev *indio_dev)
}
out:
- regmap_update_bits(data->regmap, SX9500_REG_PROX_CTRL0,
- SX9500_CHAN_MASK, 0);
+ regmap_clear_bits(data->regmap, SX9500_REG_PROX_CTRL0,
+ SX9500_CHAN_MASK);
return ret;
}
diff --git a/drivers/iio/proximity/sx_common.c b/drivers/iio/proximity/sx_common.c
index fe07d1444ac3..a95e9814aaf2 100644
--- a/drivers/iio/proximity/sx_common.c
+++ b/drivers/iio/proximity/sx_common.c
@@ -111,17 +111,16 @@ static int sx_common_enable_irq(struct sx_common_data *data, unsigned int irq)
{
if (!data->client->irq)
return 0;
- return regmap_update_bits(data->regmap, data->chip_info->reg_irq_msk,
- irq << data->chip_info->irq_msk_offset,
- irq << data->chip_info->irq_msk_offset);
+ return regmap_set_bits(data->regmap, data->chip_info->reg_irq_msk,
+ irq << data->chip_info->irq_msk_offset);
}
static int sx_common_disable_irq(struct sx_common_data *data, unsigned int irq)
{
if (!data->client->irq)
return 0;
- return regmap_update_bits(data->regmap, data->chip_info->reg_irq_msk,
- irq << data->chip_info->irq_msk_offset, 0);
+ return regmap_clear_bits(data->regmap, data->chip_info->reg_irq_msk,
+ irq << data->chip_info->irq_msk_offset);
}
static int sx_common_update_chan_en(struct sx_common_data *data,
diff --git a/drivers/iio/temperature/ltc2983.c b/drivers/iio/temperature/ltc2983.c
index 24d19f3c7292..21f2cfc55bf8 100644
--- a/drivers/iio/temperature/ltc2983.c
+++ b/drivers/iio/temperature/ltc2983.c
@@ -8,6 +8,8 @@
#include <linux/bitfield.h>
#include <linux/completion.h>
#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/iio/iio.h>
#include <linux/interrupt.h>
@@ -432,10 +434,9 @@ __ltc2983_custom_sensor_new(struct ltc2983_data *st, const struct fwnode_handle
else
n_entries = fwnode_property_count_u64(fn, propname);
/* n_entries must be an even number */
- if (!n_entries || (n_entries % 2) != 0) {
- dev_err(dev, "Number of entries either 0 or not even\n");
- return ERR_PTR(-EINVAL);
- }
+ if (!n_entries || (n_entries % 2) != 0)
+ return dev_err_ptr_probe(dev, -EINVAL,
+ "Number of entries either 0 or not even\n");
new_custom = devm_kzalloc(dev, sizeof(*new_custom), GFP_KERNEL);
if (!new_custom)
@@ -443,19 +444,17 @@ __ltc2983_custom_sensor_new(struct ltc2983_data *st, const struct fwnode_handle
new_custom->size = n_entries * n_size;
/* check Steinhart size */
- if (is_steinhart && new_custom->size != LTC2983_CUSTOM_STEINHART_SIZE) {
- dev_err(dev, "Steinhart sensors size(%zu) must be %u\n", new_custom->size,
- LTC2983_CUSTOM_STEINHART_SIZE);
- return ERR_PTR(-EINVAL);
- }
+ if (is_steinhart && new_custom->size != LTC2983_CUSTOM_STEINHART_SIZE)
+ return dev_err_ptr_probe(dev, -EINVAL,
+ "Steinhart sensors size(%zu) must be %u\n",
+ new_custom->size, LTC2983_CUSTOM_STEINHART_SIZE);
+
/* Check space on the table. */
if (st->custom_table_size + new_custom->size >
- (LTC2983_CUST_SENS_TBL_END_REG -
- LTC2983_CUST_SENS_TBL_START_REG) + 1) {
- dev_err(dev, "No space left(%d) for new custom sensor(%zu)",
- st->custom_table_size, new_custom->size);
- return ERR_PTR(-EINVAL);
- }
+ (LTC2983_CUST_SENS_TBL_END_REG - LTC2983_CUST_SENS_TBL_START_REG) + 1)
+ return dev_err_ptr_probe(dev, -EINVAL,
+ "No space left(%d) for new custom sensor(%zu)\n",
+ st->custom_table_size, new_custom->size);
/* allocate the table */
if (is_steinhart)
@@ -688,21 +687,19 @@ ltc2983_thermocouple_new(const struct fwnode_handle *child, struct ltc2983_data
LTC2983_THERMOCOUPLE_OC_CURR(3);
break;
default:
- dev_err(&st->spi->dev,
- "Invalid open circuit current:%u", oc_current);
- return ERR_PTR(-EINVAL);
+ return dev_err_ptr_probe(&st->spi->dev, -EINVAL,
+ "Invalid open circuit current:%u\n",
+ oc_current);
}
thermo->sensor_config |= LTC2983_THERMOCOUPLE_OC_CHECK(1);
}
/* validate channel index */
if (!(thermo->sensor_config & LTC2983_THERMOCOUPLE_DIFF_MASK) &&
- sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) {
- dev_err(&st->spi->dev,
- "Invalid chann:%d for differential thermocouple",
- sensor->chan);
- return ERR_PTR(-EINVAL);
- }
+ sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN)
+ return dev_err_ptr_probe(&st->spi->dev, -EINVAL,
+ "Invalid chann:%d for differential thermocouple\n",
+ sensor->chan);
struct fwnode_handle *ref __free(fwnode_handle) =
fwnode_find_reference(child, "adi,cold-junction-handle", 0);
@@ -710,14 +707,13 @@ ltc2983_thermocouple_new(const struct fwnode_handle *child, struct ltc2983_data
ref = NULL;
} else {
ret = fwnode_property_read_u32(ref, "reg", &thermo->cold_junction_chan);
- if (ret) {
+ if (ret)
/*
* This would be catched later but we can just return
* the error right away.
*/
- dev_err(&st->spi->dev, "Property reg must be given\n");
- return ERR_PTR(ret);
- }
+ return dev_err_ptr_probe(&st->spi->dev, ret,
+ "Property reg must be given\n");
}
/* check custom sensor */
@@ -753,16 +749,14 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st,
struct fwnode_handle *ref __free(fwnode_handle) =
fwnode_find_reference(child, "adi,rsense-handle", 0);
- if (IS_ERR(ref)) {
- dev_err(dev, "Property adi,rsense-handle missing or invalid");
- return ERR_CAST(ref);
- }
+ if (IS_ERR(ref))
+ return dev_err_cast_probe(dev, ref,
+ "Property adi,rsense-handle missing or invalid\n");
ret = fwnode_property_read_u32(ref, "reg", &rtd->r_sense_chan);
- if (ret) {
- dev_err(dev, "Property reg must be given\n");
- return ERR_PTR(ret);
- }
+ if (ret)
+ return dev_err_ptr_probe(dev, ret,
+ "Property reg must be given\n");
ret = fwnode_property_read_u32(child, "adi,number-of-wires", &n_wires);
if (!ret) {
@@ -781,19 +775,19 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st,
rtd->sensor_config = LTC2983_RTD_N_WIRES(3);
break;
default:
- dev_err(dev, "Invalid number of wires:%u\n", n_wires);
- return ERR_PTR(-EINVAL);
+ return dev_err_ptr_probe(dev, -EINVAL,
+ "Invalid number of wires:%u\n",
+ n_wires);
}
}
if (fwnode_property_read_bool(child, "adi,rsense-share")) {
/* Current rotation is only available with rsense sharing */
if (fwnode_property_read_bool(child, "adi,current-rotate")) {
- if (n_wires == 2 || n_wires == 3) {
- dev_err(dev,
- "Rotation not allowed for 2/3 Wire RTDs");
- return ERR_PTR(-EINVAL);
- }
+ if (n_wires == 2 || n_wires == 3)
+ return dev_err_ptr_probe(dev, -EINVAL,
+ "Rotation not allowed for 2/3 Wire RTDs\n");
+
rtd->sensor_config |= LTC2983_RTD_C_ROTATE(1);
} else {
rtd->sensor_config |= LTC2983_RTD_R_SHARE(1);
@@ -816,29 +810,22 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st,
if (((rtd->sensor_config & LTC2983_RTD_KELVIN_R_SENSE_MASK)
== LTC2983_RTD_KELVIN_R_SENSE_MASK) &&
- (rtd->r_sense_chan <= min)) {
+ (rtd->r_sense_chan <= min))
/* kelvin rsense*/
- dev_err(dev,
- "Invalid rsense chann:%d to use in kelvin rsense",
- rtd->r_sense_chan);
-
- return ERR_PTR(-EINVAL);
- }
-
- if (sensor->chan < min || sensor->chan > max) {
- dev_err(dev, "Invalid chann:%d for the rtd config",
- sensor->chan);
-
- return ERR_PTR(-EINVAL);
- }
+ return dev_err_ptr_probe(dev, -EINVAL,
+ "Invalid rsense chann:%d to use in kelvin rsense\n",
+ rtd->r_sense_chan);
+
+ if (sensor->chan < min || sensor->chan > max)
+ return dev_err_ptr_probe(dev, -EINVAL,
+ "Invalid chann:%d for the rtd config\n",
+ sensor->chan);
} else {
/* same as differential case */
- if (sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) {
- dev_err(&st->spi->dev,
- "Invalid chann:%d for RTD", sensor->chan);
-
- return ERR_PTR(-EINVAL);
- }
+ if (sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN)
+ return dev_err_ptr_probe(&st->spi->dev, -EINVAL,
+ "Invalid chann:%d for RTD\n",
+ sensor->chan);
}
/* check custom sensor */
@@ -886,10 +873,9 @@ ltc2983_rtd_new(const struct fwnode_handle *child, struct ltc2983_data *st,
rtd->excitation_current = 0x08;
break;
default:
- dev_err(&st->spi->dev,
- "Invalid value for excitation current(%u)",
- excitation_current);
- return ERR_PTR(-EINVAL);
+ return dev_err_ptr_probe(&st->spi->dev, -EINVAL,
+ "Invalid value for excitation current(%u)\n",
+ excitation_current);
}
}
@@ -913,16 +899,14 @@ ltc2983_thermistor_new(const struct fwnode_handle *child, struct ltc2983_data *s
struct fwnode_handle *ref __free(fwnode_handle) =
fwnode_find_reference(child, "adi,rsense-handle", 0);
- if (IS_ERR(ref)) {
- dev_err(dev, "Property adi,rsense-handle missing or invalid");
- return ERR_CAST(ref);
- }
+ if (IS_ERR(ref))
+ return dev_err_cast_probe(dev, ref,
+ "Property adi,rsense-handle missing or invalid\n");
ret = fwnode_property_read_u32(ref, "reg", &thermistor->r_sense_chan);
- if (ret) {
- dev_err(dev, "rsense channel must be configured...\n");
- return ERR_PTR(ret);
- }
+ if (ret)
+ return dev_err_ptr_probe(dev, ret,
+ "rsense channel must be configured...\n");
if (fwnode_property_read_bool(child, "adi,single-ended")) {
thermistor->sensor_config = LTC2983_THERMISTOR_SGL(1);
@@ -937,12 +921,10 @@ ltc2983_thermistor_new(const struct fwnode_handle *child, struct ltc2983_data *s
}
/* validate channel index */
if (!(thermistor->sensor_config & LTC2983_THERMISTOR_DIFF_MASK) &&
- sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) {
- dev_err(&st->spi->dev,
- "Invalid chann:%d for differential thermistor",
- sensor->chan);
- return ERR_PTR(-EINVAL);
- }
+ sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN)
+ return dev_err_ptr_probe(&st->spi->dev, -EINVAL,
+ "Invalid chann:%d for differential thermistor\n",
+ sensor->chan);
/* check custom sensor */
if (sensor->type >= LTC2983_SENSOR_THERMISTOR_STEINHART) {
@@ -981,12 +963,10 @@ ltc2983_thermistor_new(const struct fwnode_handle *child, struct ltc2983_data *s
switch (excitation_current) {
case 0:
/* auto range */
- if (sensor->type >=
- LTC2983_SENSOR_THERMISTOR_STEINHART) {
- dev_err(&st->spi->dev,
- "Auto Range not allowed for custom sensors\n");
- return ERR_PTR(-EINVAL);
- }
+ if (sensor->type >= LTC2983_SENSOR_THERMISTOR_STEINHART)
+ return dev_err_ptr_probe(&st->spi->dev, -EINVAL,
+ "Auto Range not allowed for custom sensors\n");
+
thermistor->excitation_current = 0x0c;
break;
case 250:
@@ -1023,10 +1003,9 @@ ltc2983_thermistor_new(const struct fwnode_handle *child, struct ltc2983_data *s
thermistor->excitation_current = 0x0b;
break;
default:
- dev_err(&st->spi->dev,
- "Invalid value for excitation current(%u)",
- excitation_current);
- return ERR_PTR(-EINVAL);
+ return dev_err_ptr_probe(&st->spi->dev, -EINVAL,
+ "Invalid value for excitation current(%u)\n",
+ excitation_current);
}
}
@@ -1056,12 +1035,11 @@ ltc2983_diode_new(const struct fwnode_handle *child, const struct ltc2983_data *
/* validate channel index */
if (!(diode->sensor_config & LTC2983_DIODE_DIFF_MASK) &&
- sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) {
- dev_err(&st->spi->dev,
- "Invalid chann:%d for differential thermistor",
- sensor->chan);
- return ERR_PTR(-EINVAL);
- }
+ sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN)
+ return dev_err_ptr_probe(&st->spi->dev, -EINVAL,
+ "Invalid chann:%d for differential thermistor\n",
+ sensor->chan);
+
/* set common parameters */
diode->sensor.fault_handler = ltc2983_common_fault_handler;
diode->sensor.assign_chan = ltc2983_diode_assign_chan;
@@ -1083,10 +1061,9 @@ ltc2983_diode_new(const struct fwnode_handle *child, const struct ltc2983_data *
diode->excitation_current = 0x03;
break;
default:
- dev_err(&st->spi->dev,
- "Invalid value for excitation current(%u)",
- excitation_current);
- return ERR_PTR(-EINVAL);
+ return dev_err_ptr_probe(&st->spi->dev, -EINVAL,
+ "Invalid value for excitation current(%u)\n",
+ excitation_current);
}
}
@@ -1111,17 +1088,15 @@ static struct ltc2983_sensor *ltc2983_r_sense_new(struct fwnode_handle *child,
return ERR_PTR(-ENOMEM);
/* validate channel index */
- if (sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) {
- dev_err(&st->spi->dev, "Invalid chann:%d for r_sense",
- sensor->chan);
- return ERR_PTR(-EINVAL);
- }
+ if (sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN)
+ return dev_err_ptr_probe(&st->spi->dev, -EINVAL,
+ "Invalid chann:%d for r_sense\n",
+ sensor->chan);
ret = fwnode_property_read_u32(child, "adi,rsense-val-milli-ohms", &temp);
- if (ret) {
- dev_err(&st->spi->dev, "Property adi,rsense-val-milli-ohms missing\n");
- return ERR_PTR(-EINVAL);
- }
+ if (ret)
+ return dev_err_ptr_probe(&st->spi->dev, -EINVAL,
+ "Property adi,rsense-val-milli-ohms missing\n");
/*
* Times 1000 because we have milli-ohms and __convert_to_raw
* expects scales of 1000000 which are used for all other
@@ -1149,12 +1124,11 @@ static struct ltc2983_sensor *ltc2983_adc_new(struct fwnode_handle *child,
if (fwnode_property_read_bool(child, "adi,single-ended"))
adc->single_ended = true;
- if (!adc->single_ended &&
- sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) {
- dev_err(&st->spi->dev, "Invalid chan:%d for differential adc\n",
- sensor->chan);
- return ERR_PTR(-EINVAL);
- }
+ if (!adc->single_ended && sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN)
+ return dev_err_ptr_probe(&st->spi->dev, -EINVAL,
+ "Invalid chan:%d for differential adc\n",
+ sensor->chan);
+
/* set common parameters */
adc->sensor.assign_chan = ltc2983_adc_assign_chan;
adc->sensor.fault_handler = ltc2983_common_fault_handler;
@@ -1175,12 +1149,10 @@ static struct ltc2983_sensor *ltc2983_temp_new(struct fwnode_handle *child,
if (fwnode_property_read_bool(child, "adi,single-ended"))
temp->single_ended = true;
- if (!temp->single_ended &&
- sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) {
- dev_err(&st->spi->dev, "Invalid chan:%d for differential temp\n",
- sensor->chan);
- return ERR_PTR(-EINVAL);
- }
+ if (!temp->single_ended && sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN)
+ return dev_err_ptr_probe(&st->spi->dev, -EINVAL,
+ "Invalid chan:%d for differential temp\n",
+ sensor->chan);
temp->custom = __ltc2983_custom_sensor_new(st, child, "adi,custom-temp",
false, 4096, true);
@@ -1296,8 +1268,8 @@ static int ltc2983_reg_access(struct iio_dev *indio_dev,
if (readval)
return regmap_read(st->regmap, reg, readval);
- else
- return regmap_write(st->regmap, reg, writeval);
+
+ return regmap_write(st->regmap, reg, writeval);
}
static irqreturn_t ltc2983_irq_handler(int irq, void *data)
@@ -1330,10 +1302,9 @@ static int ltc2983_parse_fw(struct ltc2983_data *st)
device_property_read_u32(dev, "adi,filter-notch-freq", &st->filter_notch_freq);
st->num_channels = device_get_child_node_count(dev);
- if (!st->num_channels) {
- dev_err(&st->spi->dev, "At least one channel must be given!");
- return -EINVAL;
- }
+ if (!st->num_channels)
+ return dev_err_probe(&st->spi->dev, -EINVAL,
+ "At least one channel must be given!\n");
st->sensors = devm_kcalloc(dev, st->num_channels, sizeof(*st->sensors),
GFP_KERNEL);
@@ -1438,19 +1409,17 @@ static int ltc2983_eeprom_cmd(struct ltc2983_data *st, unsigned int cmd,
time = wait_for_completion_timeout(&st->completion,
msecs_to_jiffies(wait_time));
- if (!time) {
- dev_err(&st->spi->dev, "EEPROM command timed out\n");
- return -ETIMEDOUT;
- }
+ if (!time)
+ return dev_err_probe(&st->spi->dev, -ETIMEDOUT,
+ "EEPROM command timed out\n");
ret = regmap_read(st->regmap, status_reg, &val);
if (ret)
return ret;
- if (val & status_fail_mask) {
- dev_err(&st->spi->dev, "EEPROM command failed: 0x%02X\n", val);
- return -EINVAL;
- }
+ if (val & status_fail_mask)
+ return dev_err_probe(&st->spi->dev, -EINVAL,
+ "EEPROM command failed: 0x%02X\n", val);
return 0;
}
@@ -1464,10 +1433,9 @@ static int ltc2983_setup(struct ltc2983_data *st, bool assign_iio)
ret = regmap_read_poll_timeout(st->regmap, LTC2983_STATUS_REG, status,
LTC2983_STATUS_UP(status) == 1, 25000,
25000 * 10);
- if (ret) {
- dev_err(&st->spi->dev, "Device startup timed out\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(&st->spi->dev, ret,
+ "Device startup timed out\n");
ret = regmap_update_bits(st->regmap, LTC2983_GLOBAL_CONFIG_REG,
LTC2983_NOTCH_FREQ_MASK,
@@ -1583,10 +1551,9 @@ static int ltc2983_probe(struct spi_device *spi)
return -ENODEV;
st->regmap = devm_regmap_init_spi(spi, &ltc2983_regmap_config);
- if (IS_ERR(st->regmap)) {
- dev_err(&spi->dev, "Failed to initialize regmap\n");
- return PTR_ERR(st->regmap);
- }
+ if (IS_ERR(st->regmap))
+ return dev_err_probe(&spi->dev, PTR_ERR(st->regmap),
+ "Failed to initialize regmap\n");
mutex_init(&st->lock);
init_completion(&st->completion);
@@ -1624,10 +1591,9 @@ static int ltc2983_probe(struct spi_device *spi)
ret = devm_request_irq(&spi->dev, spi->irq, ltc2983_irq_handler,
IRQF_TRIGGER_RISING, st->info->name, st);
- if (ret) {
- dev_err(&spi->dev, "failed to request an irq, %d", ret);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(&spi->dev, ret,
+ "failed to request an irq\n");
if (st->info->has_eeprom) {
ret = ltc2983_eeprom_cmd(st, LTC2983_EEPROM_WRITE_CMD,
diff --git a/drivers/iio/temperature/mlx90632.c b/drivers/iio/temperature/mlx90632.c
index 4676e0edde4a..ae4ea587e7f9 100644
--- a/drivers/iio/temperature/mlx90632.c
+++ b/drivers/iio/temperature/mlx90632.c
@@ -334,8 +334,8 @@ static int mlx90632_perform_measurement(struct mlx90632_data *data)
unsigned int reg_status;
int ret;
- ret = regmap_update_bits(data->regmap, MLX90632_REG_STATUS,
- MLX90632_STAT_DATA_RDY, 0);
+ ret = regmap_clear_bits(data->regmap, MLX90632_REG_STATUS,
+ MLX90632_STAT_DATA_RDY);
if (ret < 0)
return ret;
diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c
index d76444030a28..0684329956d9 100644
--- a/drivers/iio/trigger/stm32-timer-trigger.c
+++ b/drivers/iio/trigger/stm32-timer-trigger.c
@@ -158,7 +158,7 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv,
regmap_write(priv->regmap, TIM_PSC, prescaler);
regmap_write(priv->regmap, TIM_ARR, prd - 1);
- regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, TIM_CR1_ARPE);
+ regmap_set_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE);
/* Force master mode to update mode */
if (stm32_timer_is_trgo2_name(trig->name))
@@ -169,10 +169,10 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv,
0x2 << TIM_CR2_MMS_SHIFT);
/* Make sure that registers are updated */
- regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG);
+ regmap_set_bits(priv->regmap, TIM_EGR, TIM_EGR_UG);
/* Enable controller */
- regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, TIM_CR1_CEN);
+ regmap_set_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN);
mutex_unlock(&priv->lock);
return 0;
@@ -189,19 +189,19 @@ static void stm32_timer_stop(struct stm32_timer_trigger *priv,
mutex_lock(&priv->lock);
/* Stop timer */
- regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, 0);
- regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0);
+ regmap_clear_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE);
+ regmap_clear_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN);
regmap_write(priv->regmap, TIM_PSC, 0);
regmap_write(priv->regmap, TIM_ARR, 0);
/* Force disable master mode */
if (stm32_timer_is_trgo2_name(trig->name))
- regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS2, 0);
+ regmap_clear_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS2);
else
- regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS, 0);
+ regmap_clear_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS);
/* Make sure that registers are updated */
- regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG);
+ regmap_set_bits(priv->regmap, TIM_EGR, TIM_EGR_UG);
if (priv->enabled) {
priv->enabled = false;
@@ -498,11 +498,9 @@ static int stm32_counter_write_raw(struct iio_dev *indio_dev,
priv->enabled = true;
clk_enable(priv->clk);
}
- regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN,
- TIM_CR1_CEN);
+ regmap_set_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN);
} else {
- regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN,
- 0);
+ regmap_clear_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN);
if (priv->enabled) {
priv->enabled = false;
clk_disable(priv->clk);
@@ -555,7 +553,7 @@ static int stm32_set_trigger_mode(struct iio_dev *indio_dev,
{
struct stm32_timer_trigger *priv = iio_priv(indio_dev);
- regmap_update_bits(priv->regmap, TIM_SMCR, TIM_SMCR_SMS, TIM_SMCR_SMS);
+ regmap_set_bits(priv->regmap, TIM_SMCR, TIM_SMCR_SMS);
return 0;
}
@@ -683,7 +681,7 @@ static ssize_t stm32_count_set_preset(struct iio_dev *indio_dev,
return ret;
/* TIMx_ARR register shouldn't be buffered (ARPE=0) */
- regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, 0);
+ regmap_clear_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE);
regmap_write(priv->regmap, TIM_ARR, preset);
return len;
@@ -757,9 +755,9 @@ static void stm32_timer_detect_trgo2(struct stm32_timer_trigger *priv)
* Master mode selection 2 bits can only be written and read back when
* timer supports it.
*/
- regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS2, TIM_CR2_MMS2);
+ regmap_set_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS2);
regmap_read(priv->regmap, TIM_CR2, &val);
- regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS2, 0);
+ regmap_clear_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS2);
priv->has_trgo2 = !!val;
}
@@ -820,7 +818,7 @@ static void stm32_timer_trigger_remove(struct platform_device *pdev)
/* Check if nobody else use the timer, then disable it */
regmap_read(priv->regmap, TIM_CCER, &val);
if (!(val & TIM_CCER_CCXE))
- regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0);
+ regmap_clear_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN);
if (priv->enabled)
clk_disable(priv->clk);
@@ -841,7 +839,7 @@ static int stm32_timer_trigger_suspend(struct device *dev)
regmap_read(priv->regmap, TIM_SMCR, &priv->bak.smcr);
/* Disable the timer */
- regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0);
+ regmap_clear_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN);
clk_disable(priv->clk);
}
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index fc13fa192189..c957a7710777 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -4382,6 +4382,34 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message)
return ctlr->transfer(spi, message);
}
+static void devm_spi_unoptimize_message(void *msg)
+{
+ spi_unoptimize_message(msg);
+}
+
+/**
+ * devm_spi_optimize_message - managed version of spi_optimize_message()
+ * @dev: the device that manages @msg (usually @spi->dev)
+ * @spi: the device that will be used for the message
+ * @msg: the message to optimize
+ * Return: zero on success, else a negative error code
+ *
+ * spi_unoptimize_message() will automatically be called when the device is
+ * removed.
+ */
+int devm_spi_optimize_message(struct device *dev, struct spi_device *spi,
+ struct spi_message *msg)
+{
+ int ret;
+
+ ret = spi_optimize_message(spi, msg);
+ if (ret)
+ return ret;
+
+ return devm_add_action_or_reset(dev, devm_spi_unoptimize_message, msg);
+}
+EXPORT_SYMBOL_GPL(devm_spi_optimize_message);
+
/**
* spi_async - asynchronous SPI transfer
* @spi: device with which data will be exchanged
diff --git a/include/dt-bindings/iio/adc/mediatek,mt6357-auxadc.h b/include/dt-bindings/iio/adc/mediatek,mt6357-auxadc.h
new file mode 100644
index 000000000000..03ebb1d23953
--- /dev/null
+++ b/include/dt-bindings/iio/adc/mediatek,mt6357-auxadc.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
+
+#ifndef _DT_BINDINGS_MEDIATEK_MT6357_AUXADC_H
+#define _DT_BINDINGS_MEDIATEK_MT6357_AUXADC_H
+
+/* ADC Channel Index */
+#define MT6357_AUXADC_BATADC 0
+#define MT6357_AUXADC_ISENSE 1
+#define MT6357_AUXADC_VCDT 2
+#define MT6357_AUXADC_BAT_TEMP 3
+#define MT6357_AUXADC_CHIP_TEMP 4
+#define MT6357_AUXADC_ACCDET 5
+#define MT6357_AUXADC_VDCXO 6
+#define MT6357_AUXADC_TSX_TEMP 7
+#define MT6357_AUXADC_HPOFS_CAL 8
+#define MT6357_AUXADC_DCXO_TEMP 9
+#define MT6357_AUXADC_VCORE_TEMP 10
+#define MT6357_AUXADC_VPROC_TEMP 11
+#define MT6357_AUXADC_VBAT 12
+
+#endif
diff --git a/include/dt-bindings/iio/adc/mediatek,mt6358-auxadc.h b/include/dt-bindings/iio/adc/mediatek,mt6358-auxadc.h
new file mode 100644
index 000000000000..efa08398fafd
--- /dev/null
+++ b/include/dt-bindings/iio/adc/mediatek,mt6358-auxadc.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
+
+#ifndef _DT_BINDINGS_MEDIATEK_MT6358_AUXADC_H
+#define _DT_BINDINGS_MEDIATEK_MT6358_AUXADC_H
+
+/* ADC Channel Index */
+#define MT6358_AUXADC_BATADC 0
+#define MT6358_AUXADC_VCDT 1
+#define MT6358_AUXADC_BAT_TEMP 2
+#define MT6358_AUXADC_CHIP_TEMP 3
+#define MT6358_AUXADC_ACCDET 4
+#define MT6358_AUXADC_VDCXO 5
+#define MT6358_AUXADC_TSX_TEMP 6
+#define MT6358_AUXADC_HPOFS_CAL 7
+#define MT6358_AUXADC_DCXO_TEMP 8
+#define MT6358_AUXADC_VBIF 9
+#define MT6358_AUXADC_VCORE_TEMP 10
+#define MT6358_AUXADC_VPROC_TEMP 11
+#define MT6358_AUXADC_VGPU_TEMP 12
+#define MT6358_AUXADC_VBAT 13
+
+#endif
diff --git a/include/dt-bindings/iio/adc/mediatek,mt6359-auxadc.h b/include/dt-bindings/iio/adc/mediatek,mt6359-auxadc.h
new file mode 100644
index 000000000000..59826393ee7e
--- /dev/null
+++ b/include/dt-bindings/iio/adc/mediatek,mt6359-auxadc.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
+
+#ifndef _DT_BINDINGS_MEDIATEK_MT6359_AUXADC_H
+#define _DT_BINDINGS_MEDIATEK_MT6359_AUXADC_H
+
+/* ADC Channel Index */
+#define MT6359_AUXADC_BATADC 0
+#define MT6359_AUXADC_BAT_TEMP 1
+#define MT6359_AUXADC_CHIP_TEMP 2
+#define MT6359_AUXADC_ACCDET 3
+#define MT6359_AUXADC_VDCXO 4
+#define MT6359_AUXADC_TSX_TEMP 5
+#define MT6359_AUXADC_HPOFS_CAL 6
+#define MT6359_AUXADC_DCXO_TEMP 7
+#define MT6359_AUXADC_VBIF 8
+#define MT6359_AUXADC_VCORE_TEMP 9
+#define MT6359_AUXADC_VPROC_TEMP 10
+#define MT6359_AUXADC_VGPU_TEMP 11
+#define MT6359_AUXADC_VBAT 12
+#define MT6359_AUXADC_IBAT 13
+
+#endif
diff --git a/include/linux/dev_printk.h b/include/linux/dev_printk.h
index ae80a303c216..ca32b5bb28eb 100644
--- a/include/linux/dev_printk.h
+++ b/include/linux/dev_printk.h
@@ -277,4 +277,12 @@ do { \
__printf(3, 4) int dev_err_probe(const struct device *dev, int err, const char *fmt, ...);
+/* Simple helper for dev_err_probe() when ERR_PTR() is to be returned. */
+#define dev_err_ptr_probe(dev, ___err, fmt, ...) \
+ ERR_PTR(dev_err_probe(dev, ___err, fmt, ##__VA_ARGS__))
+
+/* Simple helper for dev_err_probe() when ERR_CAST() is to be returned. */
+#define dev_err_cast_probe(dev, ___err_ptr, fmt, ...) \
+ ERR_PTR(dev_err_probe(dev, PTR_ERR(___err_ptr), fmt, ##__VA_ARGS__))
+
#endif /* _DEVICE_PRINTK_H_ */
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index 752dbde4cec1..9fc03068cabc 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -161,6 +161,16 @@ struct dma_interleaved_template {
};
/**
+ * struct dma_vec - DMA vector
+ * @addr: Bus address of the start of the vector
+ * @len: Length in bytes of the DMA vector
+ */
+struct dma_vec {
+ dma_addr_t addr;
+ size_t len;
+};
+
+/**
* enum dma_ctrl_flags - DMA flags to augment operation preparation,
* control completion, and communicate status.
* @DMA_PREP_INTERRUPT - trigger an interrupt (callback) upon completion of
@@ -910,6 +920,10 @@ struct dma_device {
struct dma_async_tx_descriptor *(*device_prep_dma_interrupt)(
struct dma_chan *chan, unsigned long flags);
+ struct dma_async_tx_descriptor *(*device_prep_peripheral_dma_vec)(
+ struct dma_chan *chan, const struct dma_vec *vecs,
+ size_t nents, enum dma_transfer_direction direction,
+ unsigned long flags);
struct dma_async_tx_descriptor *(*device_prep_slave_sg)(
struct dma_chan *chan, struct scatterlist *sgl,
unsigned int sg_len, enum dma_transfer_direction direction,
@@ -973,6 +987,25 @@ static inline struct dma_async_tx_descriptor *dmaengine_prep_slave_single(
dir, flags, NULL);
}
+/**
+ * dmaengine_prep_peripheral_dma_vec() - Prepare a DMA scatter-gather descriptor
+ * @chan: The channel to be used for this descriptor
+ * @vecs: The array of DMA vectors that should be transferred
+ * @nents: The number of DMA vectors in the array
+ * @dir: Specifies the direction of the data transfer
+ * @flags: DMA engine flags
+ */
+static inline struct dma_async_tx_descriptor *dmaengine_prep_peripheral_dma_vec(
+ struct dma_chan *chan, const struct dma_vec *vecs, size_t nents,
+ enum dma_transfer_direction dir, unsigned long flags)
+{
+ if (!chan || !chan->device || !chan->device->device_prep_peripheral_dma_vec)
+ return NULL;
+
+ return chan->device->device_prep_peripheral_dma_vec(chan, vecs, nents,
+ dir, flags);
+}
+
static inline struct dma_async_tx_descriptor *dmaengine_prep_slave_sg(
struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len,
enum dma_transfer_direction dir, unsigned long flags)
diff --git a/include/linux/iio/adc/ad_sigma_delta.h b/include/linux/iio/adc/ad_sigma_delta.h
index 383614ebd760..f8c1d2505940 100644
--- a/include/linux/iio/adc/ad_sigma_delta.h
+++ b/include/linux/iio/adc/ad_sigma_delta.h
@@ -37,6 +37,10 @@ struct iio_dev;
* @append_status: Will be called to enable status append at the end of the sample, may be NULL.
* @set_mode: Will be called to select the current mode, may be NULL.
* @disable_all: Will be called to disable all channels, may be NULL.
+ * @disable_one: Will be called to disable a single channel after
+ * ad_sigma_delta_single_conversion(), may be NULL.
+ * Usage of this callback expects iio_chan_spec.address to contain
+ * the value required for the driver to identify the channel.
* @postprocess_sample: Is called for each sampled data word, can be used to
* modify or drop the sample data, it, may be NULL.
* @has_registers: true if the device has writable and readable registers, false
@@ -55,6 +59,7 @@ struct ad_sigma_delta_info {
int (*append_status)(struct ad_sigma_delta *, bool append);
int (*set_mode)(struct ad_sigma_delta *, enum ad_sigma_delta_mode mode);
int (*disable_all)(struct ad_sigma_delta *);
+ int (*disable_one)(struct ad_sigma_delta *, unsigned int chan);
int (*postprocess_sample)(struct ad_sigma_delta *, unsigned int raw_sample);
bool has_registers;
unsigned int addr_shift;
@@ -140,6 +145,15 @@ static inline int ad_sigma_delta_disable_all(struct ad_sigma_delta *sd)
return 0;
}
+static inline int ad_sigma_delta_disable_one(struct ad_sigma_delta *sd,
+ unsigned int chan)
+{
+ if (sd->info->disable_one)
+ return sd->info->disable_one(sd, chan);
+
+ return 0;
+}
+
static inline int ad_sigma_delta_set_mode(struct ad_sigma_delta *sd,
unsigned int mode)
{
diff --git a/include/linux/iio/buffer-dma.h b/include/linux/iio/buffer-dma.h
index 6e27e47077d5..5eb66a399002 100644
--- a/include/linux/iio/buffer-dma.h
+++ b/include/linux/iio/buffer-dma.h
@@ -7,6 +7,7 @@
#ifndef __INDUSTRIALIO_DMA_BUFFER_H__
#define __INDUSTRIALIO_DMA_BUFFER_H__
+#include <linux/atomic.h>
#include <linux/list.h>
#include <linux/kref.h>
#include <linux/spinlock.h>
@@ -16,6 +17,9 @@
struct iio_dma_buffer_queue;
struct iio_dma_buffer_ops;
struct device;
+struct dma_buf_attachment;
+struct dma_fence;
+struct sg_table;
/**
* enum iio_block_state - State of a struct iio_dma_buffer_block
@@ -41,6 +45,10 @@ enum iio_block_state {
* @queue: Parent DMA buffer queue
* @kref: kref used to manage the lifetime of block
* @state: Current state of the block
+ * @cyclic: True if this is a cyclic buffer
+ * @fileio: True if this buffer is used for fileio mode
+ * @sg_table: DMA table for the transfer when transferring a DMABUF
+ * @fence: DMA fence to be signaled when a DMABUF transfer is complete
*/
struct iio_dma_buffer_block {
/* May only be accessed by the owner of the block */
@@ -63,6 +71,12 @@ struct iio_dma_buffer_block {
* queue->list_lock if the block is not owned by the core.
*/
enum iio_block_state state;
+
+ bool cyclic;
+ bool fileio;
+
+ struct sg_table *sg_table;
+ struct dma_fence *fence;
};
/**
@@ -72,6 +86,7 @@ struct iio_dma_buffer_block {
* @pos: Read offset in the active block
* @block_size: Size of each block
* @next_dequeue: index of next block that will be dequeued
+ * @enabled: Whether the buffer is operating in fileio mode
*/
struct iio_dma_buffer_queue_fileio {
struct iio_dma_buffer_block *blocks[2];
@@ -80,6 +95,7 @@ struct iio_dma_buffer_queue_fileio {
size_t block_size;
unsigned int next_dequeue;
+ bool enabled;
};
/**
@@ -95,6 +111,7 @@ struct iio_dma_buffer_queue_fileio {
* the DMA controller
* @incoming: List of buffers on the incoming queue
* @active: Whether the buffer is currently active
+ * @num_dmabufs: Total number of DMABUFs attached to this queue
* @fileio: FileIO state
*/
struct iio_dma_buffer_queue {
@@ -107,6 +124,7 @@ struct iio_dma_buffer_queue {
struct list_head incoming;
bool active;
+ atomic_t num_dmabufs;
struct iio_dma_buffer_queue_fileio fileio;
};
@@ -144,4 +162,17 @@ int iio_dma_buffer_init(struct iio_dma_buffer_queue *queue,
void iio_dma_buffer_exit(struct iio_dma_buffer_queue *queue);
void iio_dma_buffer_release(struct iio_dma_buffer_queue *queue);
+struct iio_dma_buffer_block *
+iio_dma_buffer_attach_dmabuf(struct iio_buffer *buffer,
+ struct dma_buf_attachment *attach);
+void iio_dma_buffer_detach_dmabuf(struct iio_buffer *buffer,
+ struct iio_dma_buffer_block *block);
+int iio_dma_buffer_enqueue_dmabuf(struct iio_buffer *buffer,
+ struct iio_dma_buffer_block *block,
+ struct dma_fence *fence,
+ struct sg_table *sgt,
+ size_t size, bool cyclic);
+void iio_dma_buffer_lock_queue(struct iio_buffer *buffer);
+void iio_dma_buffer_unlock_queue(struct iio_buffer *buffer);
+
#endif
diff --git a/include/linux/iio/buffer_impl.h b/include/linux/iio/buffer_impl.h
index 89c3fd7c29ca..e72552e026f3 100644
--- a/include/linux/iio/buffer_impl.h
+++ b/include/linux/iio/buffer_impl.h
@@ -9,8 +9,12 @@
#include <uapi/linux/iio/buffer.h>
#include <linux/iio/buffer.h>
+struct dma_buf_attachment;
+struct dma_fence;
struct iio_dev;
+struct iio_dma_buffer_block;
struct iio_buffer;
+struct sg_table;
/**
* INDIO_BUFFER_FLAG_FIXED_WATERMARK - Watermark level of the buffer can not be
@@ -39,6 +43,16 @@ struct iio_buffer;
* device stops sampling. Calles are balanced with @enable.
* @release: called when the last reference to the buffer is dropped,
* should free all resources allocated by the buffer.
+ * @attach_dmabuf: called from userspace via ioctl to attach one external
+ * DMABUF.
+ * @detach_dmabuf: called from userspace via ioctl to detach one previously
+ * attached DMABUF.
+ * @enqueue_dmabuf: called from userspace via ioctl to queue this DMABUF
+ * object to this buffer. Requires a valid DMABUF fd, that
+ * was previouly attached to this buffer.
+ * @lock_queue: called when the core needs to lock the buffer queue;
+ * it is used when enqueueing DMABUF objects.
+ * @unlock_queue: used to unlock a previously locked buffer queue
* @modes: Supported operating modes by this buffer type
* @flags: A bitmask combination of INDIO_BUFFER_FLAG_*
*
@@ -68,6 +82,17 @@ struct iio_buffer_access_funcs {
void (*release)(struct iio_buffer *buffer);
+ struct iio_dma_buffer_block * (*attach_dmabuf)(struct iio_buffer *buffer,
+ struct dma_buf_attachment *attach);
+ void (*detach_dmabuf)(struct iio_buffer *buffer,
+ struct iio_dma_buffer_block *block);
+ int (*enqueue_dmabuf)(struct iio_buffer *buffer,
+ struct iio_dma_buffer_block *block,
+ struct dma_fence *fence, struct sg_table *sgt,
+ size_t size, bool cyclic);
+ void (*lock_queue)(struct iio_buffer *buffer);
+ void (*unlock_queue)(struct iio_buffer *buffer);
+
unsigned int modes;
unsigned int flags;
};
@@ -136,6 +161,12 @@ struct iio_buffer {
/* @ref: Reference count of the buffer. */
struct kref ref;
+
+ /* @dmabufs: List of DMABUF attachments */
+ struct list_head dmabufs; /* P: dmabufs_mutex */
+
+ /* @dmabufs_mutex: Protects dmabufs */
+ struct mutex dmabufs_mutex;
};
/**
@@ -159,6 +190,8 @@ void iio_buffer_init(struct iio_buffer *buffer);
struct iio_buffer *iio_buffer_get(struct iio_buffer *buffer);
void iio_buffer_put(struct iio_buffer *buffer);
+void iio_buffer_signal_dmabuf_done(struct dma_fence *fence, int ret);
+
#else /* CONFIG_IIO_BUFFER */
static inline void iio_buffer_get(struct iio_buffer *buffer) {}
diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h
index e9910b41d48e..333d1d8ccb37 100644
--- a/include/linux/iio/consumer.h
+++ b/include/linux/iio/consumer.h
@@ -441,4 +441,14 @@ ssize_t iio_read_channel_ext_info(struct iio_channel *chan,
ssize_t iio_write_channel_ext_info(struct iio_channel *chan, const char *attr,
const char *buf, size_t len);
+/**
+ * iio_read_channel_label() - read label for a given channel
+ * @chan: The channel being queried.
+ * @buf: Where to store the attribute value. Assumed to hold
+ * at least PAGE_SIZE bytes.
+ *
+ * Returns the number of bytes written to buf, or an error code.
+ */
+ssize_t iio_read_channel_label(struct iio_channel *chan, char *buf);
+
#endif
diff --git a/include/linux/iio/imu/adis.h b/include/linux/iio/imu/adis.h
index 4bb0a53cf7ea..e6a75356567a 100644
--- a/include/linux/iio/imu/adis.h
+++ b/include/linux/iio/imu/adis.h
@@ -9,6 +9,7 @@
#ifndef __IIO_ADIS_H__
#define __IIO_ADIS_H__
+#include <linux/cleanup.h>
#include <linux/spi/spi.h>
#include <linux/interrupt.h>
#include <linux/iio/iio.h>
@@ -150,13 +151,8 @@ int __adis_reset(struct adis *adis);
*/
static inline int adis_reset(struct adis *adis)
{
- int ret;
-
- mutex_lock(&adis->state_lock);
- ret = __adis_reset(adis);
- mutex_unlock(&adis->state_lock);
-
- return ret;
+ guard(mutex)(&adis->state_lock);
+ return __adis_reset(adis);
}
int __adis_write_reg(struct adis *adis, unsigned int reg,
@@ -248,13 +244,8 @@ static inline int __adis_read_reg_32(struct adis *adis, unsigned int reg,
static inline int adis_write_reg(struct adis *adis, unsigned int reg,
unsigned int val, unsigned int size)
{
- int ret;
-
- mutex_lock(&adis->state_lock);
- ret = __adis_write_reg(adis, reg, val, size);
- mutex_unlock(&adis->state_lock);
-
- return ret;
+ guard(mutex)(&adis->state_lock);
+ return __adis_write_reg(adis, reg, val, size);
}
/**
@@ -267,13 +258,8 @@ static inline int adis_write_reg(struct adis *adis, unsigned int reg,
static int adis_read_reg(struct adis *adis, unsigned int reg,
unsigned int *val, unsigned int size)
{
- int ret;
-
- mutex_lock(&adis->state_lock);
- ret = __adis_read_reg(adis, reg, val, size);
- mutex_unlock(&adis->state_lock);
-
- return ret;
+ guard(mutex)(&adis->state_lock);
+ return __adis_read_reg(adis, reg, val, size);
}
/**
@@ -365,12 +351,8 @@ int __adis_update_bits_base(struct adis *adis, unsigned int reg, const u32 mask,
static inline int adis_update_bits_base(struct adis *adis, unsigned int reg,
const u32 mask, const u32 val, u8 size)
{
- int ret;
-
- mutex_lock(&adis->state_lock);
- ret = __adis_update_bits_base(adis, reg, mask, val, size);
- mutex_unlock(&adis->state_lock);
- return ret;
+ guard(mutex)(&adis->state_lock);
+ return __adis_update_bits_base(adis, reg, mask, val, size);
}
/**
@@ -411,35 +393,19 @@ int __adis_enable_irq(struct adis *adis, bool enable);
static inline int adis_enable_irq(struct adis *adis, bool enable)
{
- int ret;
-
- mutex_lock(&adis->state_lock);
- ret = __adis_enable_irq(adis, enable);
- mutex_unlock(&adis->state_lock);
-
- return ret;
+ guard(mutex)(&adis->state_lock);
+ return __adis_enable_irq(adis, enable);
}
static inline int adis_check_status(struct adis *adis)
{
- int ret;
-
- mutex_lock(&adis->state_lock);
- ret = __adis_check_status(adis);
- mutex_unlock(&adis->state_lock);
-
- return ret;
-}
-
-static inline void adis_dev_lock(struct adis *adis)
-{
- mutex_lock(&adis->state_lock);
+ guard(mutex)(&adis->state_lock);
+ return __adis_check_status(adis);
}
-static inline void adis_dev_unlock(struct adis *adis)
-{
- mutex_unlock(&adis->state_lock);
-}
+#define adis_dev_auto_lock(adis) guard(mutex)(&(adis)->state_lock)
+#define adis_dev_auto_scoped_lock(adis) \
+ scoped_guard(mutex, &(adis)->state_lock)
int adis_single_conversion(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
diff --git a/include/linux/math.h b/include/linux/math.h
index dd4152711de7..f5f18dc3616b 100644
--- a/include/linux/math.h
+++ b/include/linux/math.h
@@ -112,6 +112,8 @@ struct type##_fract { \
__##type numerator; \
__##type denominator; \
};
+__STRUCT_FRACT(s8)
+__STRUCT_FRACT(u8)
__STRUCT_FRACT(s16)
__STRUCT_FRACT(u16)
__STRUCT_FRACT(s32)
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index 98fdef6e28f2..8f119f355632 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -1269,6 +1269,8 @@ static inline void spi_message_free(struct spi_message *m)
extern int spi_optimize_message(struct spi_device *spi, struct spi_message *msg);
extern void spi_unoptimize_message(struct spi_message *msg);
+extern int devm_spi_optimize_message(struct device *dev, struct spi_device *spi,
+ struct spi_message *msg);
extern int spi_setup(struct spi_device *spi);
extern int spi_async(struct spi_device *spi, struct spi_message *message);
diff --git a/include/uapi/linux/iio/buffer.h b/include/uapi/linux/iio/buffer.h
index 13939032b3f6..c666aa95e532 100644
--- a/include/uapi/linux/iio/buffer.h
+++ b/include/uapi/linux/iio/buffer.h
@@ -5,6 +5,28 @@
#ifndef _UAPI_IIO_BUFFER_H_
#define _UAPI_IIO_BUFFER_H_
+#include <linux/types.h>
+
+/* Flags for iio_dmabuf.flags */
+#define IIO_BUFFER_DMABUF_CYCLIC (1 << 0)
+#define IIO_BUFFER_DMABUF_SUPPORTED_FLAGS 0x00000001
+
+/**
+ * struct iio_dmabuf - Descriptor for a single IIO DMABUF object
+ * @fd: file descriptor of the DMABUF object
+ * @flags: one or more IIO_BUFFER_DMABUF_* flags
+ * @bytes_used: number of bytes used in this DMABUF for the data transfer.
+ * Should generally be set to the DMABUF's size.
+ */
+struct iio_dmabuf {
+ __u32 fd;
+ __u32 flags;
+ __u64 bytes_used;
+};
+
#define IIO_BUFFER_GET_FD_IOCTL _IOWR('i', 0x91, int)
+#define IIO_BUFFER_DMABUF_ATTACH_IOCTL _IOW('i', 0x92, int)
+#define IIO_BUFFER_DMABUF_DETACH_IOCTL _IOW('i', 0x93, int)
+#define IIO_BUFFER_DMABUF_ENQUEUE_IOCTL _IOW('i', 0x94, struct iio_dmabuf)
#endif /* _UAPI_IIO_BUFFER_H_ */