summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2024-07-04 12:04:20 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2024-07-04 12:04:20 +0300
commit14c4dc8bb620c4c75b06d267a542eb1ac44cdd29 (patch)
tree26b6e7c00604aacde2d9baeb3856bb498c914edd
parentdfd19866d1a3f681cc12aae67ab05011eb3aa3d8 (diff)
parent529d2e1900642eba6df28307e26e19793e227546 (diff)
downloadlinux-14c4dc8bb620c4c75b06d267a542eb1ac44cdd29.tar.xz
Merge tag 'iio-for-6.11b' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/jic23/iio into char-misc-next
Jonathan writes: IIO: 2nd set of new device support, features and cleanup for 6.11 The big one here is we finally have Paul Cercueil's (and others) DMA buffer support for IIO devices enabling high speed zero copy transfer of data to and from sensors supported by IIO (and for example USB). This should aid with upstream support of a range of higher performance ADCs and DACs. Two merges from other trees - spi/spi_devm_optimize used for simplification in ad7944. - dmaengine/topic_dma_vec to enable the DMABUF series. One feature with impact outside IIO. - Richer set of dev_err_probe() like helpers to cover ERR_PTR() cases. New device support ================== adi,ad7173 - Add support for AD4111, AD4112, AD4114, AD4115 and ADC4116 pseudo differential ADCs. Major driver rework was needed to enabled these. adi,ad7944 - Use devm_spi_optimize_message() to avoid a local devm cleanup callback. This is the example case from the patch set, others will follow. mediatek,mt6359-auxadc - New driver for this ADC IP found in MT6357, MT6358 and MT6359 PMICs. st,accel - Add support for the LIS2DS12 accelerometer ti,ads1119 - New driver for this 16 bit 2-differential or 4-single ended channel ADC. Features ======== dt-bindings - Introduce new common-mode-channel property to help handle pseudo differential ADCs where we have something that looks like one side of differential input, but which is only suited for use with a slow moving reference. adi,adf4350 - Support use as a clock provider. iio-hmwon - Support reading of labels from IIO devices by their consumers and use this in the hwmon bridge. Cleanup and minor fixes ======================= Treewide - Use regmap_clear_bits() / regmap_set_bits() to simplify open coded equivalents. - Use devm_regulator_get_enable_read_voltage() to replace equivalent opencoded boilerplate. In some cases enabled complete conversion to devm handling and removal of explicit remove() callbacks. - Introduce dev_err_ptr_probe() and other variants and make use of of them in a couple of examples driver cleanups. Will find use in many more drivers soon. adi,ad7192 - Introduce local struct device *dev and use dev_err_probe() to give more readable code. adi,adi-axi-adc/dac - Improved consistency of messages using dev_err_probe() adi,adis - Split the trigger handling into cases that needed paging and those that don't resulting in more readable code. - Use cleanup.h to simplify error paths via scoped cleanup. - Add adis specific lock helpers and make use of them in a number of drivers. adi,ad7192 - Update maintainer (Alisa-Dariana Roman) adi,ad7606 - dt-binding cleanup. avago,apds9306 - Add a maintainer entry (Subhajit Ghosh) linear,ltc2309 - Fix a wrong endian type. st,stm32-dfsdm - Fix a missing port property in the dt-binding. st,sensors - Relax whoami match failure to a warning print rather than probe failure. This enables fallback compatibles to existing parts from those that don't necessarily even exit yet. * tag 'iio-for-6.11b' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (112 commits) iio: adc: ad7173: Fix uninitialized symbol is_current_chan iio: adc: Add support for MediaTek MT6357/8/9 Auxiliary ADC math.h: Add unsigned 8 bits fractional numbers type dt-bindings: iio: adc: Add MediaTek MT6359 PMIC AUXADC iio: common: scmi_iio: convert to dev_err_probe() iio: backend: make use of dev_err_cast_probe() iio: temperature: ltc2983: convert to dev_err_probe() dev_printk: add new dev_err_probe() helpers iio: xilinx-ams: Add labels iio: adc: ad7944: use devm_spi_optimize_message() Documentation: iio: Document high-speed DMABUF based API iio: buffer-dmaengine: Support new DMABUF based userspace API iio: buffer-dma: Enable support for DMABUFs iio: core: Add new DMABUF interface infrastructure MAINTAINERS: Update AD7192 driver maintainer iio: adc: ad7192: use devm_regulator_get_enable_read_voltage iio: st_sensors: relax WhoAmI check in st_sensors_verify_id() MAINTAINERS: Add AVAGO APDS9306 dt-bindings: iio: adc: adi,ad7606: comment and sort the compatible names dt-bindings: iio: adc: adi,ad7606: add missing datasheet link ...
-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_ */