diff --git a/Documentation/ABI/testing/debugfs-iio-ad9910 b/Documentation/ABI/testing/debugfs-iio-ad9910
new file mode 100644
index 000000000000..7083a20d5a40
--- /dev/null
+++ b/Documentation/ABI/testing/debugfs-iio-ad9910
@@ -0,0 +1,23 @@
+What: /sys/kernel/debug/iio/iio:deviceX/frequency_source
+KernelVersion: 7.3
+Contact: linux-iio@vger.kernel.org
+Description:
+ Read-only. Reports the channel label that is read from the
+
_[Y]_label attribute, which corresponds to the on-chip
+ signal generator that is currently driving the output frequency.
+
+What: /sys/kernel/debug/iio/iio:deviceX/phase_source
+KernelVersion: 7.3
+Contact: linux-iio@vger.kernel.org
+Description:
+ Read-only. Reports the channel label that is read from the
+ _[Y]_label attribute, which corresponds to the on-chip
+ signal generator that is currently driving the output phase.
+
+What: /sys/kernel/debug/iio/iio:deviceX/amplitude_source
+KernelVersion: 7.3
+Contact: linux-iio@vger.kernel.org
+Description:
+ Read-only. Reports the channel label that is read from the
+ _[Y]_label attribute, which corresponds to the on-chip
+ signal generator that is currently driving the output amplitude.
diff --git a/Documentation/ABI/testing/debugfs-iio-backend b/Documentation/ABI/testing/debugfs-iio-backend
index 01ab94469432..2a2f2e5508c0 100644
--- a/Documentation/ABI/testing/debugfs-iio-backend
+++ b/Documentation/ABI/testing/debugfs-iio-backend
@@ -8,13 +8,13 @@ What: /sys/kernel/debug/iio/iio:deviceX/backendY/direct_reg_access
KernelVersion: 6.11
Contact: linux-iio@vger.kernel.org
Description:
- Directly access the registers of backend Y. Typical usage is:
+ Directly access the registers of backend Y. Typical usage is::
- Reading address 0x50
- echo 0x50 > direct_reg_access
- cat direct_reg_access
+ # Reading address 0x50
+ echo 0x50 > direct_reg_access
+ cat direct_reg_access
- Writing address 0x50
- echo 0x50 0x3 > direct_reg_access
- //readback address 0x50
- cat direct_reg_access
+ # Writing address 0x50
+ echo 0x50 0x3 > direct_reg_access
+ # readback address 0x50
+ cat direct_reg_access
diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
index a4f5595722ad..2b6f57041763 100644
--- a/Documentation/ABI/testing/sysfs-bus-iio
+++ b/Documentation/ABI/testing/sysfs-bus-iio
@@ -442,6 +442,14 @@ What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_i_offset
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_q_offset
What: /sys/bus/iio/devices/iio:deviceX/in_currentY_offset
What: /sys/bus/iio/devices/iio:deviceX/in_current_offset
+What: /sys/bus/iio/devices/iio:deviceX/in_phaseY_offset
+What: /sys/bus/iio/devices/iio:deviceX/in_phase_offset
+What: /sys/bus/iio/devices/iio:deviceX/out_phaseY_offset
+What: /sys/bus/iio/devices/iio:deviceX/out_phase_offset
+What: /sys/bus/iio/devices/iio:deviceX/in_frequencyY_offset
+What: /sys/bus/iio/devices/iio:deviceX/in_frequency_offset
+What: /sys/bus/iio/devices/iio:deviceX/out_frequencyY_offset
+What: /sys/bus/iio/devices/iio:deviceX/out_frequency_offset
What: /sys/bus/iio/devices/iio:deviceX/in_tempY_offset
What: /sys/bus/iio/devices/iio:deviceX/in_temp_offset
What: /sys/bus/iio/devices/iio:deviceX/in_pressureY_offset
@@ -475,10 +483,22 @@ What: /sys/bus/iio/devices/iio:deviceX/in_voltage_scale
What: /sys/bus/iio/devices/iio:deviceX/in_voltage-voltage_scale
What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_scale
What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_scale
+What: /sys/bus/iio/devices/iio:deviceX/in_phaseY_scale
+What: /sys/bus/iio/devices/iio:deviceX/in_phase_scale
+What: /sys/bus/iio/devices/iio:deviceX/out_phaseY_scale
+What: /sys/bus/iio/devices/iio:deviceX/out_phase_scale
+What: /sys/bus/iio/devices/iio:deviceX/in_frequencyY_scale
+What: /sys/bus/iio/devices/iio:deviceX/in_frequency_scale
+What: /sys/bus/iio/devices/iio:deviceX/out_frequencyY_scale
+What: /sys/bus/iio/devices/iio:deviceX/out_frequency_scale
What: /sys/bus/iio/devices/iio:deviceX/in_currentY_scale
What: /sys/bus/iio/devices/iio:deviceX/in_currentY_supply_scale
What: /sys/bus/iio/devices/iio:deviceX/in_current_scale
What: /sys/bus/iio/devices/iio:deviceX/in_current_q_scale
+What: /sys/bus/iio/devices/iio:deviceX/in_altcurrentY_scale
+What: /sys/bus/iio/devices/iio:deviceX/in_altcurrent_scale
+What: /sys/bus/iio/devices/iio:deviceX/out_altcurrentY_scale
+What: /sys/bus/iio/devices/iio:deviceX/out_altcurrent_scale
What: /sys/bus/iio/devices/iio:deviceX/in_accel_scale
What: /sys/bus/iio/devices/iio:deviceX/in_accel_peak_scale
What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_scale
@@ -507,6 +527,7 @@ What: /sys/bus/iio/devices/iio:deviceX/in_intensity_z_scale
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_red_scale
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_green_scale
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_blue_scale
+What: /sys/bus/iio/devices/iio:deviceX/in_intensity_clear_scale
What: /sys/bus/iio/devices/iio:deviceX/in_concentration_co2_scale
What: /sys/bus/iio/devices/iio:deviceX/in_volumeflow_scale
What: /sys/bus/iio/devices/iio:deviceX/in_volumeflowY_scale
@@ -762,6 +783,8 @@ What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_powerdown_mode
What: /sys/bus/iio/devices/iio:deviceX/out_voltage_powerdown_mode
What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_powerdown_mode
What: /sys/bus/iio/devices/iio:deviceX/out_altvoltage_powerdown_mode
+What: /sys/bus/iio/devices/iio:deviceX/out_currentY_powerdown_mode
+What: /sys/bus/iio/devices/iio:deviceX/out_current_powerdown_mode
KernelVersion: 2.6.38
Contact: linux-iio@vger.kernel.org
Description:
@@ -774,6 +797,7 @@ Description:
6kohm_to_gnd: connected to ground via a 6kOhm resistor,
7.7kohm_to_gnd: connected to ground via a 7.7kOhm resistor,
10kohm_to_gnd: connected to ground via a 10kOhm resistor,
+ 15kohm_to_gnd: connected to ground via a 15kOhm resistor,
16kohm_to_gnd: connected to ground via a 16kOhm resistor,
20kohm_to_gnd: connected to ground via a 20kOhm resistor,
32kohm_to_gnd: connected to ground via a 32kOhm resistor,
@@ -802,6 +826,10 @@ What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_powerdown
What: /sys/bus/iio/devices/iio:deviceX/out_voltage_powerdown
What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_powerdown
What: /sys/bus/iio/devices/iio:deviceX/out_altvoltage_powerdown
+What: /sys/bus/iio/devices/iio:deviceX/out_currentY_powerdown
+What: /sys/bus/iio/devices/iio:deviceX/out_current_powerdown
+What: /sys/bus/iio/devices/iio:deviceX/out_altcurrentY_powerdown
+What: /sys/bus/iio/devices/iio:deviceX/out_altcurrent_powerdown
KernelVersion: 2.6.38
Contact: linux-iio@vger.kernel.org
Description:
@@ -812,6 +840,7 @@ Description:
together.
What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_frequency
+What: /sys/bus/iio/devices/iio:deviceX/out_altcurrentY_frequency
KernelVersion: 3.4.0
Contact: linux-iio@vger.kernel.org
Description:
@@ -838,8 +867,10 @@ Description:
all the other channels, since it involves changing the VCO
fundamental output frequency.
+What: /sys/bus/iio/devices/iio:deviceX/in_altcurrentY_phase
What: /sys/bus/iio/devices/iio:deviceX/in_altvoltageY_i_phase
What: /sys/bus/iio/devices/iio:deviceX/in_altvoltageY_q_phase
+What: /sys/bus/iio/devices/iio:deviceX/out_altcurrentY_phase
What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_phase
What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_i_phase
What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_q_phase
@@ -853,6 +884,7 @@ Description:
channel.
What: /sys/bus/iio/devices/iio:deviceX/out_currentY_raw
+What: /sys/bus/iio/devices/iio:deviceX/out_altcurrentY_raw
Date: May 2012
KernelVersion: 3.5
Contact: Johan Hovold
@@ -1739,6 +1771,7 @@ Description:
What: /sys/bus/iio/devices/iio:deviceX/in_currentY_raw
What: /sys/bus/iio/devices/iio:deviceX/in_currentY_supply_raw
+What: /sys/bus/iio/devices/iio:deviceX/in_altcurrentY_raw
KernelVersion: 3.17
Contact: linux-iio@vger.kernel.org
Description:
@@ -2129,7 +2162,9 @@ Description:
Raw counter device counters direction for channel Y.
+What: /sys/bus/iio/devices/iio:deviceX/in_altcurrentY_label
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_label
+What: /sys/bus/iio/devices/iio:deviceX/out_altcurrentY_label
What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_label
KernelVersion: 5.8
Contact: linux-iio@vger.kernel.org
@@ -2139,6 +2174,50 @@ Description:
specific attributes. This is useful for userspace to be able to
better identify an individual channel.
+What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_parent
+What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_parent
+What: /sys/bus/iio/devices/iio:deviceX/in_altvoltageY_parent
+What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_parent
+What: /sys/bus/iio/devices/iio:deviceX/in_currentY_parent
+What: /sys/bus/iio/devices/iio:deviceX/out_currentY_parent
+What: /sys/bus/iio/devices/iio:deviceX/in_altcurrentY_parent
+What: /sys/bus/iio/devices/iio:deviceX/out_altcurrentY_parent
+KernelVersion: 7.3
+Contact: linux-iio@vger.kernel.org
+Description:
+ Read-only attribute containing the sysfs name prefix of the parent
+ channel for hierarchical channel relationships (e.g. "out_altvoltage0").
+ The prefix uniquely identifies the parent channel and can be used by
+ userspace to organize channels in tree-like structures that reflects
+ virtual or logical relationships between them.
+
+ For example, an IIO device may expose a primary output channel as
+ "out_voltage0" together with a set of profile-based or mode-based
+ subchannels used to configure or compose the output signal. These
+ subchannels may carry common attributes such as frequency, phase, etc.
+ They do not represent physical outputs, but rather logical/virtual
+ channels grouping configurations that affect the primary output.
+ Each subchannel exposes a _[Y]_parent attribute reading
+ "out_voltage0", allowing userspace to group controls under the output
+ channel they belong to rather than treating them as unrelated top-level
+ channels.
+
+What: /sys/bus/iio/devices/iio:deviceX/in_frequencyY_raw
+KernelVersion: 7.3
+Contact: linux-iio@vger.kernel.org
+Description:
+ Raw (unscaled) frequency reading from channel Y.
+ Units after application of scale and offset are Hz.
+
+What: /sys/bus/iio/devices/iio:deviceX/out_frequencyY_raw
+KernelVersion: 7.3
+Contact: linux-iio@vger.kernel.org
+Description:
+ Raw (unscaled, no bias etc.) output frequency for channel Y.
+ The number must always be specified and unique if the output
+ corresponds to a single channel. Units after application of
+ scale and offset are Hz.
+
What: /sys/bus/iio/devices/iio:deviceX/in_phaseY_raw
KernelVersion: 4.18
Contact: linux-iio@vger.kernel.org
@@ -2146,6 +2225,15 @@ Description:
Raw (unscaled) phase difference reading from channel Y.
Units after application of scale and offset are radians.
+What: /sys/bus/iio/devices/iio:deviceX/out_phaseY_raw
+KernelVersion: 7.3
+Contact: linux-iio@vger.kernel.org
+Description:
+ Raw (unscaled, no bias etc.) output phase for channel Y.
+ The number must always be specified and unique if the output
+ corresponds to a single channel. Units after application of
+ scale and offset are radians.
+
What: /sys/bus/iio/devices/iio:deviceX/in_massconcentration_pm1_input
What: /sys/bus/iio/devices/iio:deviceX/in_massconcentrationY_pm1_input
What: /sys/bus/iio/devices/iio:deviceX/in_massconcentration_pm2p5_input
@@ -2380,6 +2468,7 @@ Description:
* "sinc4+lp" - Sinc4 + Low Pass Filter.
* "sinc4+sinc1" - Sinc4 + averaging by 8. Low 1st conversion
time.
+ * "sinc4+sinc1+pf1" - Sinc4 + Sinc1 + device specific Post Filter 1.
* "sinc4+rej60" - Sinc4 + 60Hz rejection.
* "sinc5" - The digital sinc5 filter. Excellent noise
performance
@@ -2401,6 +2490,32 @@ Description:
Specifies which filter type apply to the channel. The possible
values are given by the filter_type_available attribute.
+What: /sys/bus/iio/devices/iio:deviceX/in_resistanceY_settlingtime
+What: /sys/bus/iio/devices/iio:deviceX/in_tempY_settlingtime
+What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_settlingtime
+What: /sys/bus/iio/devices/iio:deviceX/in_voltageY-voltageZ_settlingtime
+KernelVersion: 7.4
+Contact: linux-iio@vger.kernel.org
+Description:
+ Set/read total settling time in seconds for a device to settle
+ after starting the first conversion after any settings have
+ changed. The data for the conversion is outputted at the end of
+ this time.
+
+ Depending on the device and how it is used, this settling time
+ may apply to more than just the first conversion, e.g. to every
+ conversion in a single-shot conversion mode or when a device
+ setting changes after each conversion (input chopping).
+
+What: /sys/bus/iio/devices/iio:deviceX/in_resistanceY_settlingtime_available
+What: /sys/bus/iio/devices/iio:deviceX/in_tempY_settlingtime_available
+What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_settlingtime_available
+What: /sys/bus/iio/devices/iio:deviceX/in_voltageY-voltageZ_settlingtime_available
+KernelVersion: 7.4
+Contact: linux-iio@vger.kernel.org
+Description:
+ Available settlingtime values in IIO range or list format.
+
What: /sys/.../events/in_proximity_thresh_either_runningperiod
KernelVersion: 6.6
Contact: linux-iio@vger.kernel.org
diff --git a/Documentation/ABI/testing/sysfs-bus-iio-adc b/Documentation/ABI/testing/sysfs-bus-iio-adc
new file mode 100644
index 000000000000..e1309b371efb
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-iio-adc
@@ -0,0 +1,9 @@
+What: /sys/bus/iio/devices/iio:deviceX/in_resistanceY_burnoutraw
+What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_burnoutraw
+What: /sys/bus/iio/devices/iio:deviceX/in_voltageY-voltageZ_burnoutraw
+KernelVersion: 7.4
+Contact: linux-iio@vger.kernel.org
+Description:
+ Raw value from channel Y read using a single conversion with
+ the channel burnout current enabled. This is typically used
+ for diagnostic purposes to detect an open or shorted input.
diff --git a/Documentation/ABI/testing/sysfs-bus-iio-frequency-ad9910 b/Documentation/ABI/testing/sysfs-bus-iio-frequency-ad9910
new file mode 100644
index 000000000000..4e25f538af4a
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-iio-frequency-ad9910
@@ -0,0 +1,31 @@
+What: /sys/bus/iio/devices/iio:deviceX/out_altcurrentY_dwell_en
+What: /sys/bus/iio/devices/iio:deviceX/out_frequencyY_dwell_en
+What: /sys/bus/iio/devices/iio:deviceX/out_phaseY_dwell_en
+KernelVersion: 7.3
+Contact: linux-iio@vger.kernel.org
+Description:
+ For a channel that produces parametric sweeps, this attribute controls
+ the sweep behavior at the configured limit. It enables dwell mode at a
+ sweep limit when set to 1, i.e., after the sweep is complete the output
+ value stays at the limit. Otherwise (setting this value to 0), the sweep
+ may stop or restart from the initial position, or even continue by
+ reversing the sweep direction.
+
+What: /sys/bus/iio/devices/iio:deviceX/out_altcurrentY_raw_roc
+What: /sys/bus/iio/devices/iio:deviceX/out_frequencyY_raw_roc
+What: /sys/bus/iio/devices/iio:deviceX/out_phaseY_raw_roc
+KernelVersion: 7.3
+Contact: linux-iio@vger.kernel.org
+Description:
+ For a channel that produces parametric sweeps, this attribute controls
+ the rate of change of the parameter in raw units per second (slope).
+ This value may be influenced by the channel sampling_frequency attribute
+ if available. Multiplying this value by the scale attribute of the
+ channel yields the rate of change in physical units per second.
+
+What: /sys/bus/iio/devices/iio:deviceX/out_altcurrentY_raw_roc_available
+KernelVersion: 7.3
+Contact: linux-iio@vger.kernel.org
+Description:
+ Lists the available roc values for the channel. Values are
+ space-separated in ascending order.
diff --git a/Documentation/devicetree/bindings/iio/accel/adi,adis16201.yaml b/Documentation/devicetree/bindings/iio/accel/adi,adis16201.yaml
index b6ba7ad1a8d5..3ce5fb1be574 100644
--- a/Documentation/devicetree/bindings/iio/accel/adi,adis16201.yaml
+++ b/Documentation/devicetree/bindings/iio/accel/adi,adis16201.yaml
@@ -4,21 +4,23 @@
$id: http://devicetree.org/schemas/iio/accel/adi,adis16201.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
-title: ADIS16201 Dual Axis Inclinometer and similar
+title: ADIS16201 Inclinometer and similar
maintainers:
- Jonathan Cameron
description: |
- Two similar parts from external interface point of view.
+ Three similar parts from external interface point of view.
SPI interface.
https://www.analog.com/en/products/adis16201.html
+ https://www.analog.com/en/products/adis16203.html
https://www.analog.com/en/products/adis16209.html
properties:
compatible:
enum:
- adi,adis16201
+ - adi,adis16203
- adi,adis16209
reg:
diff --git a/Documentation/devicetree/bindings/iio/accel/adi,adxl367.yaml b/Documentation/devicetree/bindings/iio/accel/adi,adxl367.yaml
index f10d98d34cb8..115170eac058 100644
--- a/Documentation/devicetree/bindings/iio/accel/adi,adxl367.yaml
+++ b/Documentation/devicetree/bindings/iio/accel/adi,adxl367.yaml
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Analog Devices ADXL367 3-Axis Digital Accelerometer
maintainers:
- - Cosmin Tanislav
+ - Antoniu Miclaus
description: |
The ADXL367 is an ultralow power, 3-axis MEMS accelerometer.
@@ -33,7 +33,14 @@ properties:
maxItems: 1
interrupts:
- maxItems: 1
+ minItems: 1
+ maxItems: 2
+
+ interrupt-names:
+ minItems: 1
+ items:
+ - enum: [INT1, INT2]
+ - const: INT2
vdd-supply: true
vddio-supply: true
@@ -61,6 +68,7 @@ examples:
reg = <0x53>;
interrupt-parent = <&gpio>;
interrupts = <25 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "INT1";
};
};
- |
@@ -76,5 +84,6 @@ examples:
spi-max-frequency = <1000000>;
interrupt-parent = <&gpio>;
interrupts = <25 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "INT1";
};
};
diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad4080.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad4080.yaml
index db8467b98e67..c8ac92e6f8e1 100644
--- a/Documentation/devicetree/bindings/iio/adc/adi,ad4080.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/adi,ad4080.yaml
@@ -41,6 +41,7 @@ properties:
- adi,ad4880
- adi,ad4883
- adi,ad4884
+ - adi,ad4885
reg:
minItems: 1
@@ -105,6 +106,7 @@ allOf:
- adi,ad4880
- adi,ad4883
- adi,ad4884
+ - adi,ad4885
then:
properties:
reg:
@@ -127,15 +129,15 @@ examples:
#size-cells = <0>;
adc@0 {
- compatible = "adi,ad4080";
- reg = <0>;
- spi-max-frequency = <10000000>;
- vdd33-supply = <&vdd33>;
- vddldo-supply = <&vddldo>;
- vrefin-supply = <&vrefin>;
- clocks = <&cnv>;
- clock-names = "cnv";
- io-backends = <&iio_backend>;
+ compatible = "adi,ad4080";
+ reg = <0>;
+ spi-max-frequency = <10000000>;
+ vdd33-supply = <&vdd33>;
+ vddldo-supply = <&vddldo>;
+ vrefin-supply = <&vrefin>;
+ clocks = <&cnv>;
+ clock-names = "cnv";
+ io-backends = <&iio_backend>;
};
};
- |
@@ -144,15 +146,15 @@ examples:
#size-cells = <0>;
adc@0 {
- compatible = "adi,ad4880";
- reg = <0>, <1>;
- spi-max-frequency = <10000000>;
- vdd33-supply = <&vdd33>;
- vddldo-supply = <&vddldo>;
- vrefin-supply = <&vrefin>;
- clocks = <&cnv>;
- clock-names = "cnv";
- io-backends = <&iio_backend_cha>, <&iio_backend_chb>;
+ compatible = "adi,ad4880";
+ reg = <0>, <1>;
+ spi-max-frequency = <10000000>;
+ vdd33-supply = <&vdd33>;
+ vddldo-supply = <&vddldo>;
+ vrefin-supply = <&vrefin>;
+ clocks = <&cnv>;
+ clock-names = "cnv";
+ io-backends = <&iio_backend_cha>, <&iio_backend_chb>;
};
};
...
diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad4130.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad4130.yaml
index cc38617bb829..a4ab6adef1c6 100644
--- a/Documentation/devicetree/bindings/iio/adc/adi,ad4130.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/adi,ad4130.yaml
@@ -8,7 +8,8 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Analog Devices AD4130 family ADCs
maintainers:
- - Cosmin Tanislav
+ - Marcelo Schmitt
+ - Antoniu Miclaus
description: |
Bindings for the Analog Devices AD4130 family ADCs.
diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad4851.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad4851.yaml
index b107322e0ea3..49708ce0b230 100644
--- a/Documentation/devicetree/bindings/iio/adc/adi,ad4851.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/adi,ad4851.yaml
@@ -142,13 +142,13 @@ examples:
io-backends = <&iio_backend>;
channel@0 {
- reg = <0>;
- diff-channels = <0 0>;
- bipolar;
+ reg = <0>;
+ diff-channels = <0 0>;
+ bipolar;
};
channel@1 {
- reg = <1>;
+ reg = <1>;
};
};
};
diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7173.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7173.yaml
index 62d906e24997..e178007b9a22 100644
--- a/Documentation/devicetree/bindings/iio/adc/adi,ad7173.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7173.yaml
@@ -443,7 +443,7 @@ examples:
#address-cells = <1>;
#size-cells = <0>;
- adc@0 {
+ adc@0 {
compatible = "adi,ad4111";
reg = <0>;
diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.yaml
index dfa2d7fa9fb3..7b72d14e104c 100644
--- a/Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.yaml
@@ -238,9 +238,9 @@ examples:
};
regulators {
- vcm_reg: vcm-output {
- regulator-name = "ad7768-1-vcm";
- };
+ vcm_reg: vcm-output {
+ regulator-name = "ad7768-1-vcm";
+ };
};
};
};
diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7768.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7768.yaml
new file mode 100644
index 000000000000..d8e489fa1f6f
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7768.yaml
@@ -0,0 +1,270 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/adc/adi,ad7768.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices AD7768 and AD7768-4 ADC
+
+maintainers:
+ - Janani Sunil
+
+description: |
+ The AD7768 is an 8-channel, 24-bit simultaneous sampling ADC with configurable
+ power and performance modes. The AD7768-4 is a 4-channel version.
+
+ This binding covers SPI mode only (register access via SPI). Pin control mode,
+ where configuration is set via hardware pins rather than SPI registers, is not
+ supported.
+
+ The io-backend represents the high-speed data output interface, consuming the
+ DOUTx data lines, DCLK (data clock), and DRDY (data ready) signals.
+
+ Datasheet at:
+ https://www.analog.com/media/en/technical-documentation/data-sheets/ad7768-ad7768-4.pdf
+
+ HDL reference design:
+ https://github.com/analogdevicesinc/hdl/tree/main/projects/ad7768evb
+
+properties:
+ compatible:
+ enum:
+ - adi,ad7768
+ - adi,ad7768-4
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ clock-names:
+ description:
+ Describes the type of master clock (MCLK) attached to the XTAL1 and
+ XTAL2/MCLK pins. A CMOS clock is supplied on the XTAL2/MCLK pin, a
+ crystal oscillator is connected between the XTAL1 and XTAL2 pins, and an
+ LVDS differential clock is supplied on the XTAL1/XTAL2 pin pair. CMOS and
+ LVDS clocks must operate from 1.15 MHz to 34 MHz. Crystals must operate
+ from 8 MHz to 34 MHz.
+ enum:
+ - mclk
+ - xtal
+ - lvds
+
+ avdd1-supply:
+ description:
+ Analog supply. Its voltage is used to derive the supply-dependent VCM
+ output level, so it must be a regulator that can report its voltage.
+
+ avss-supply:
+ description:
+ Negative analog supply. If omitted, AVSS is assumed to be at system
+ ground.
+
+ avdd2-supply: true
+
+ iovdd-supply: true
+
+ ref1p-supply: true
+
+ ref1n-supply:
+ description:
+ Negative reference input supply for REF1. If omitted, REF1- is assumed
+ to be connected to ground.
+
+ ref2p-supply: true
+
+ ref2n-supply:
+ description:
+ Negative reference input supply for REF2. If omitted, REF2- is assumed
+ to be connected to ground.
+
+ reset-gpios:
+ maxItems: 1
+ description: GPIO connected to the active-low RESET pin
+
+ start-gpios:
+ maxItems: 1
+ description:
+ GPIO connected to the START pin. An active-low pulse on this pin
+ synchronizes the device to other AD7768 devices. When not used, this
+ pin must be tied to a logic high level through a pull-up resistor.
+ When used, SYNC_OUT must be wired back to SYNC_IN on all devices in
+ the synchronization chain.
+
+ sync-in-gpios:
+ maxItems: 1
+ description:
+ GPIO connected to the SYNC_IN pin. Receives the synchronization pulse
+ generated on SYNC_OUT in response to a START pulse. Must be synchronous
+ to the MCLK clock domain. In multi-device or daisy-chained systems,
+ two successive synchronization pulses must be applied to guarantee all
+ ADCs are synchronized.
+
+ gpio-controller: true
+
+ '#gpio-cells':
+ const: 2
+
+ adi,data-lines-number:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [1, 2, 4, 8]
+ description:
+ Number of DOUTx lines used for the high-speed data output interface
+ (distinct from the SPI control interface). AD7768 supports 1, 2, or 8
+ lines; AD7768-4 supports 1 or 4 lines. Defaults to the maximum number
+ of lines for the selected variant if omitted.
+
+ regulators:
+ type: object
+ description: Container for the on-chip VCM regulator.
+ additionalProperties: false
+
+ properties:
+ vcm-output:
+ type: object
+ description:
+ Buffered common-mode voltage output on the VCM pin. Use
+ regulator-always-on when no consumer node references this output.
+ Channel 0 must be present and enabled while VCM is used, since
+ putting channel 0 in standby disables the VCM output.
+ $ref: /schemas/regulator/regulator.yaml#
+ unevaluatedProperties: false
+
+ io-backends:
+ maxItems: 1
+
+ '#address-cells':
+ const: 1
+
+ '#size-cells':
+ const: 0
+
+patternProperties:
+ "^channel@[0-7]$":
+ type: object
+ description:
+ Represents the external channels which are connected to the device.
+ AD7768 supports channels 0-7, AD7768-4 supports channels 0-3.
+
+ properties:
+ reg:
+ minimum: 0
+ maximum: 7
+ description: The channel number
+
+ adi,prechargebuf-pos-enable:
+ type: boolean
+ description: Enable positive input precharge buffer
+
+ adi,prechargebuf-neg-enable:
+ type: boolean
+ description: Enable negative input precharge buffer
+
+ adi,refbuf-pos-enable:
+ type: boolean
+ description: Enable positive reference buffer
+
+ adi,refbuf-neg-enable:
+ type: boolean
+ description: Enable negative reference buffer
+
+ required:
+ - reg
+
+ additionalProperties: false
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+ - avdd1-supply
+ - avdd2-supply
+ - iovdd-supply
+ - ref1p-supply
+ - ref2p-supply
+ - io-backends
+
+allOf:
+ - $ref: /schemas/spi/spi-peripheral-props.yaml#
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: adi,ad7768-4
+ then:
+ properties:
+ adi,data-lines-number:
+ enum: [1, 4]
+ patternProperties:
+ "^channel@[0-3]$":
+ properties:
+ reg:
+ maximum: 3
+ "^channel@[4-7]$": false
+ else:
+ properties:
+ adi,data-lines-number:
+ enum: [1, 2, 8]
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include
+
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ adc@0 {
+ compatible = "adi,ad7768";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+
+ avdd1-supply = <&avdd1_regulator>;
+ avss-supply = <&avss_regulator>;
+ avdd2-supply = <&avdd2_regulator>;
+ iovdd-supply = <&iovdd_regulator>;
+ ref1p-supply = <&ref1p_regulator>;
+ ref1n-supply = <&ref1n_regulator>;
+ ref2p-supply = <&ref2p_regulator>;
+ ref2n-supply = <&ref2n_regulator>;
+ reset-gpios = <&gpio0 86 GPIO_ACTIVE_LOW>;
+
+ clocks = <&ad7768_mclk>;
+ clock-names = "mclk";
+
+ adi,data-lines-number = <8>;
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ io-backends = <&iio_backend>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ channel@0 {
+ reg = <0>;
+ adi,prechargebuf-pos-enable;
+ adi,refbuf-pos-enable;
+ };
+
+ channel@1 {
+ reg = <1>;
+ adi,prechargebuf-pos-enable;
+ adi,prechargebuf-neg-enable;
+ adi,refbuf-pos-enable;
+ adi,refbuf-neg-enable;
+ };
+
+ channel@7 {
+ reg = <7>;
+ adi,prechargebuf-pos-enable;
+ adi,refbuf-pos-enable;
+ };
+ };
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7779.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7779.yaml
index ba3f7b2bd6cf..37e25a6196e7 100644
--- a/Documentation/devicetree/bindings/iio/adc/adi,ad7779.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7779.yaml
@@ -122,14 +122,14 @@ examples:
#size-cells = <0>;
adc@0 {
- compatible = "adi,ad7779";
- reg = <0>;
- start-gpios = <&gpio0 87 GPIO_ACTIVE_LOW>;
- reset-gpios = <&gpio0 93 GPIO_ACTIVE_LOW>;
- interrupt-parent = <&intc>;
- interrupts = <0 56 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-names = "adc_rdy";
- clocks = <&adc_clk>;
+ compatible = "adi,ad7779";
+ reg = <0>;
+ start-gpios = <&gpio0 87 GPIO_ACTIVE_LOW>;
+ reset-gpios = <&gpio0 93 GPIO_ACTIVE_LOW>;
+ interrupt-parent = <&intc>;
+ interrupts = <0 56 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "adc_rdy";
+ clocks = <&adc_clk>;
};
};
@@ -140,13 +140,13 @@ examples:
#size-cells = <0>;
adc@0 {
- compatible = "adi,ad7779";
- reg = <0>;
- start-gpios = <&gpio0 87 GPIO_ACTIVE_LOW>;
- reset-gpios = <&gpio0 93 GPIO_ACTIVE_LOW>;
- clocks = <&adc_clk>;
- io-backends = <&iio_backend>;
- adi,num-lanes = <4>;
+ compatible = "adi,ad7779";
+ reg = <0>;
+ start-gpios = <&gpio0 87 GPIO_ACTIVE_LOW>;
+ reset-gpios = <&gpio0 93 GPIO_ACTIVE_LOW>;
+ clocks = <&adc_clk>;
+ io-backends = <&iio_backend>;
+ adi,num-lanes = <4>;
};
};
...
diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ade9000.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ade9000.yaml
index f22eba0250ee..0971a29bf372 100644
--- a/Documentation/devicetree/bindings/iio/adc/adi,ade9000.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/adi,ade9000.yaml
@@ -5,21 +5,23 @@
$id: http://devicetree.org/schemas/iio/adc/adi,ade9000.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
-title: Analog Devices ADE9000 High Performance, Polyphase Energy Metering
+title: Analog Devices ADE9000/ADE9078 High Performance, Polyphase Energy Metering
maintainers:
- Antoniu Miclaus
description: |
- The ADE9000 is a highly accurate, fully integrated, multiphase energy and power
- quality monitoring device. Superior analog performance and a digital signal
- processing (DSP) core enable accurate energy monitoring over a wide dynamic
- range. An integrated high end reference ensures low drift over temperature
- with a combined drift of less than ±25 ppm/°C maximum for the entire channel
- including a programmable gain amplifier (PGA) and an analog-to-digital
- converter (ADC).
+ The ADE9000 and ADE9078 are highly accurate, fully integrated, multiphase
+ energy and power quality monitoring devices. Superior analog performance and a
+ digital signal processing (DSP) core enable accurate energy monitoring over a
+ wide dynamic range. An integrated high end reference ensures low drift over
+ temperature with a combined drift of less than ±25 ppm/°C maximum for the
+ entire channel including a programmable gain amplifier (PGA) and an
+ analog-to-digital converter (ADC). The ADE9078 does not provide the on-chip
+ dip/swell detection available on the ADE9000.
https://www.analog.com/media/en/technical-documentation/data-sheets/ADE9000.pdf
+ https://www.analog.com/media/en/technical-documentation/data-sheets/ADE9078.pdf
$ref: /schemas/spi/spi-peripheral-props.yaml#
@@ -27,6 +29,7 @@ properties:
compatible:
enum:
- adi,ade9000
+ - adi,ade9078
reg:
maxItems: 1
@@ -67,6 +70,17 @@ required:
- reg
- vdd-supply
+allOf:
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: adi,ade9078
+ then:
+ properties:
+ spi-max-frequency:
+ maximum: 10000000
+
unevaluatedProperties: false
examples:
@@ -75,20 +89,20 @@ examples:
#include
spi {
- #address-cells = <1>;
- #size-cells = <0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
- adc@0 {
- compatible = "adi,ade9000";
- reg = <0>;
- spi-max-frequency = <7000000>;
+ adc@0 {
+ compatible = "adi,ade9000";
+ reg = <0>;
+ spi-max-frequency = <7000000>;
- #clock-cells = <0>;
- reset-gpios = <&gpio 4 GPIO_ACTIVE_LOW>;
- interrupts = <2 IRQ_TYPE_EDGE_FALLING>, <3 IRQ_TYPE_EDGE_FALLING>, <4 IRQ_TYPE_EDGE_FALLING>;
- interrupt-names = "irq0", "irq1", "dready";
- interrupt-parent = <&gpio>;
- clocks = <&ext_clock_24576khz>;
- vdd-supply = <&vdd_reg>;
- };
+ #clock-cells = <0>;
+ reset-gpios = <&gpio 4 GPIO_ACTIVE_LOW>;
+ interrupts = <2 IRQ_TYPE_EDGE_FALLING>, <3 IRQ_TYPE_EDGE_FALLING>, <4 IRQ_TYPE_EDGE_FALLING>;
+ interrupt-names = "irq0", "irq1", "dready";
+ interrupt-parent = <&gpio>;
+ clocks = <&ext_clock_24576khz>;
+ vdd-supply = <&vdd_reg>;
+ };
};
diff --git a/Documentation/devicetree/bindings/iio/adc/adi,max40080.yaml b/Documentation/devicetree/bindings/iio/adc/adi,max40080.yaml
new file mode 100644
index 000000000000..b0ec9159a293
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/adi,max40080.yaml
@@ -0,0 +1,65 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/adc/adi,max40080.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices MAX40080 bidirectional current-sense amplifier
+
+maintainers:
+ - Ciprian Hegbeli
+ - Stefan Popa
+
+description: |
+ The MAX40080 is a high-precision, bidirectional current-sense amplifier with
+ an integrated 12-bit ADC and an I2C/SMBus interface. It measures the voltage
+ across an external shunt resistor and the input bus voltage, and stores the
+ results in an internal FIFO.
+
+ Datasheet:
+ https://www.analog.com/max40080
+
+properties:
+ compatible:
+ const: adi,max40080
+
+ reg:
+ maxItems: 1
+
+ "#io-channel-cells":
+ const: 1
+
+ vdd-supply:
+ description: Power supply for the device.
+
+ interrupts:
+ maxItems: 1
+ description: ALERT_ output for overcurrent/undervoltage threshold events.
+
+ shunt-resistor-micro-ohms:
+ description:
+ Value of the current-sense shunt resistor connected between the RS+ and
+ RS- inputs. Used to scale the reported current.
+
+required:
+ - compatible
+ - reg
+ - shunt-resistor-micro-ohms
+ - vdd-supply
+
+additionalProperties: false
+
+examples:
+ - |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ adc@20 {
+ compatible = "adi,max40080";
+ reg = <0x20>;
+ #io-channel-cells = <1>;
+ vdd-supply = <&vdd>;
+ shunt-resistor-micro-ohms = <100000>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/iio/adc/axiado,ax3000-saradc.yaml b/Documentation/devicetree/bindings/iio/adc/axiado,ax3000-saradc.yaml
new file mode 100644
index 000000000000..b910852aa56f
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/axiado,ax3000-saradc.yaml
@@ -0,0 +1,63 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/adc/axiado,ax3000-saradc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Axiado AX3000/AX3005 Successive Approximation Register ADC
+
+description:
+ The Axiado AX3000/AX3005 SAR ADC is a 10-bit ADC with sixteen input
+ channels on AX3000 and eight input channels on AX3005.
+
+maintainers:
+ - Petar Stepanovic
+ - Akhila Kavi
+ - Prasad Bolisetty
+
+properties:
+ compatible:
+ enum:
+ - axiado,ax3000-saradc
+ - axiado,ax3005-saradc
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ clock-names:
+ const: saradc
+
+ '#io-channel-cells':
+ const: 1
+
+ vref-supply:
+ description: Reference voltage regulator supplying the ADC
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+ - '#io-channel-cells'
+ - vref-supply
+
+additionalProperties: false
+
+examples:
+ - |
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ adc@806a0000 {
+ compatible = "axiado,ax3000-saradc";
+ reg = <0x0 0x806a0000 0x0 0x400>;
+ clocks = <&pclk>;
+ clock-names = "saradc";
+ vref-supply = <&vref_reg>;
+ #io-channel-cells = <1>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/iio/adc/lltc,ltc2497.yaml b/Documentation/devicetree/bindings/iio/adc/lltc,ltc2497.yaml
index c884b6e03767..67445ad2bb3b 100644
--- a/Documentation/devicetree/bindings/iio/adc/lltc,ltc2497.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/lltc,ltc2497.yaml
@@ -4,7 +4,7 @@
$id: http://devicetree.org/schemas/iio/adc/lltc,ltc2497.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
-title: Linear Technology / Analog Devices LTC2497 and LTC2309 ADC
+title: Linear Technology / Analog Devices LTC2497 and similar ADCs
maintainers:
- Michael Hennerich
diff --git a/Documentation/devicetree/bindings/iio/adc/maxim,max34408.yaml b/Documentation/devicetree/bindings/iio/adc/maxim,max34408.yaml
index 4cba856e8d47..bad780d1bbfb 100644
--- a/Documentation/devicetree/bindings/iio/adc/maxim,max34408.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/maxim,max34408.yaml
@@ -118,22 +118,22 @@ examples:
#size-cells = <0>;
adc@1e {
- compatible = "maxim,max34409";
- reg = <0x1e>;
- powerdown-gpios = <&gpio0 1 GPIO_ACTIVE_LOW>;
- powerdown-status-gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>;
+ compatible = "maxim,max34409";
+ reg = <0x1e>;
+ powerdown-gpios = <&gpio0 1 GPIO_ACTIVE_LOW>;
+ powerdown-status-gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>;
- #address-cells = <1>;
- #size-cells = <0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
- channel@0 {
- reg = <0x0>;
- maxim,rsense-val-micro-ohms = <5000>;
- };
+ channel@0 {
+ reg = <0x0>;
+ maxim,rsense-val-micro-ohms = <5000>;
+ };
- channel@1 {
- reg = <0x1>;
- maxim,rsense-val-micro-ohms = <10000>;
- };
+ channel@1 {
+ reg = <0x1>;
+ maxim,rsense-val-micro-ohms = <10000>;
+ };
};
};
diff --git a/Documentation/devicetree/bindings/iio/adc/mediatek,mt2701-auxadc.yaml b/Documentation/devicetree/bindings/iio/adc/mediatek,mt2701-auxadc.yaml
index d9e825e5054f..750e1e837fb8 100644
--- a/Documentation/devicetree/bindings/iio/adc/mediatek,mt2701-auxadc.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/mediatek,mt2701-auxadc.yaml
@@ -38,6 +38,7 @@ properties:
- const: mediatek,mt7986-auxadc
- items:
- enum:
+ - mediatek,mt6572-auxadc
- mediatek,mt6893-auxadc
- mediatek,mt8183-auxadc
- mediatek,mt8186-auxadc
diff --git a/Documentation/devicetree/bindings/iio/adc/nxp,lpc1850-adc.yaml b/Documentation/devicetree/bindings/iio/adc/nxp,lpc1850-adc.yaml
index 70b38038a080..1e2df3dd15d1 100644
--- a/Documentation/devicetree/bindings/iio/adc/nxp,lpc1850-adc.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/nxp,lpc1850-adc.yaml
@@ -56,6 +56,6 @@ examples:
clocks = <&ccu1 CLK_APB3_ADC0>;
vref-supply = <®_vdda>;
resets = <&rgu 40>;
- };
+ };
};
...
diff --git a/Documentation/devicetree/bindings/iio/adc/renesas,r9a09g077-adc.yaml b/Documentation/devicetree/bindings/iio/adc/renesas,r9a09g077-adc.yaml
index dc0206b28231..5b496729022e 100644
--- a/Documentation/devicetree/bindings/iio/adc/renesas,r9a09g077-adc.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/renesas,r9a09g077-adc.yaml
@@ -34,8 +34,6 @@ properties:
- description: A/D scan end interrupt for Group C
- description: Window A compare match
- description: Window B compare match
- - description: Compare match
- - description: Compare mismatch
interrupt-names:
items:
@@ -44,8 +42,6 @@ properties:
- const: gcadi
- const: cmpai
- const: cmpbi
- - const: wcmpm
- - const: wcmpum
clocks:
items:
@@ -57,6 +53,18 @@ properties:
- const: adclk
- const: pclk
+ dmas:
+ minItems: 1
+ maxItems: 3
+ description:
+ Must contain a list of references to DMA RX specifiers.
+
+ dma-names:
+ minItems: 1
+ maxItems: 3
+ items:
+ const: rx
+
power-domains:
maxItems: 1
@@ -107,11 +115,9 @@ examples:
,
,
,
- ,
- ,
- ;
+ ;
interrupt-names = "adi", "gbadi", "gcadi",
- "cmpai", "cmpbi", "wcmpm", "wcmpum";
+ "cmpai", "cmpbi";
clocks = <&cpg CPG_CORE R9A09G077_CLK_PCLKL>,
<&cpg CPG_MOD 225>;
clock-names = "adclk", "pclk";
diff --git a/Documentation/devicetree/bindings/iio/adc/renesas,rzg2l-adc.yaml b/Documentation/devicetree/bindings/iio/adc/renesas,rzg2l-adc.yaml
index 40341d541726..f08f5439d127 100644
--- a/Documentation/devicetree/bindings/iio/adc/renesas,rzg2l-adc.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/renesas,rzg2l-adc.yaml
@@ -25,7 +25,9 @@ properties:
- renesas,r9a07g054-adc # RZ/V2L
- const: renesas,rzg2l-adc
- items:
- - const: renesas,r9a08g045-adc # RZ/G3S
+ - enum:
+ - renesas,r9a08g045-adc # RZ/G3S
+ - renesas,r9a08g046-adc1 # RZ/G3L ADC for TSU
reg:
maxItems: 1
@@ -121,6 +123,19 @@ allOf:
reg:
maximum: 7
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: renesas,r9a08g046-adc1
+ then:
+ patternProperties:
+ "^channel@[0-7]$": false
+ "^channel@[8]$":
+ properties:
+ reg:
+ const: 8
+
additionalProperties: false
examples:
diff --git a/Documentation/devicetree/bindings/iio/adc/ti,ads1015.yaml b/Documentation/devicetree/bindings/iio/adc/ti,ads1015.yaml
index 718f633c6e04..777a75c21d7f 100644
--- a/Documentation/devicetree/bindings/iio/adc/ti,ads1015.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/ti,ads1015.yaml
@@ -66,6 +66,11 @@ patternProperties:
- minimum: 0
maximum: 7
+ label:
+ $ref: /schemas/types.yaml#/definitions/string
+ description:
+ A descriptive name for this channel, like "vcc_ram" or "CH3".
+
ti,gain:
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
@@ -125,6 +130,7 @@ examples:
reg = <4>;
ti,gain = <3>;
ti,datarate = <5>;
+ label = "CH3";
};
};
};
diff --git a/Documentation/devicetree/bindings/iio/adc/ti,ads1100.yaml b/Documentation/devicetree/bindings/iio/adc/ti,ads1100.yaml
index 970ccab15e1e..28c5e2dd0ad6 100644
--- a/Documentation/devicetree/bindings/iio/adc/ti,ads1100.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/ti,ads1100.yaml
@@ -4,19 +4,23 @@
$id: http://devicetree.org/schemas/iio/adc/ti,ads1100.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
-title: TI ADS1100/ADS1000 single channel I2C analog to digital converter
+title: TI ADS1100 and similar single channel I2C Analog to Digital Converters
maintainers:
- Mike Looijmans
description: |
- Datasheet at: https://www.ti.com/lit/gpn/ads1100
+ Datasheets:
+ - https://www.ti.com/lit/gpn/ads1000
+ - https://www.ti.com/lit/gpn/ads1100
+ - https://www.ti.com/lit/gpn/ads1110
properties:
compatible:
enum:
- - ti,ads1100
- ti,ads1000
+ - ti,ads1100
+ - ti,ads1110
reg:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/iio/adc/ti,ads112c04.yaml b/Documentation/devicetree/bindings/iio/adc/ti,ads112c04.yaml
new file mode 100644
index 000000000000..95a123cd7b67
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/ti,ads112c04.yaml
@@ -0,0 +1,149 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/adc/ti,ads112c04.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Texas Instruments ADS112C04 ADC
+
+maintainers:
+ - Kyle Hsieh
+
+description:
+ The ADS112C04 (16-bit) are precision analog-to-digital converters (ADCs)
+ with an I2C interface. They feature a flexible input multiplexer, a
+ low-noise programmable gain amplifier (PGA), two programmable excitation
+ current sources, a voltage reference, and a precision temperature sensor.
+
+properties:
+ compatible:
+ enum:
+ - ti,ads112c04
+
+ reg:
+ maxItems: 1
+ description: I2C address of the device.
+
+ interrupts:
+ maxItems: 1
+ description:
+ Data ready (DRDY) interrupt output. DRDY pulses low when a conversion
+ result is ready and returns high once the result is latched, so an
+ edge trigger should be used.
+
+ "#address-cells":
+ const: 1
+
+ "#size-cells":
+ const: 0
+
+ reset-gpios:
+ maxItems: 1
+ description: GPIO connected to the RESET pin. Active low.
+
+ avdd-supply: true
+ dvdd-supply: true
+
+ refp-supply: true
+ refn-supply: true
+
+ ti,refp-refn-resistor-ohms:
+ description: Resistance of the external resistor between REFP and REFN.
+
+patternProperties:
+ "^channel@[0-9a-b]$":
+ $ref: adc.yaml
+ unevaluatedProperties: false
+ properties:
+ reg:
+ items:
+ - maximum: 11
+
+ single-channel:
+ maximum: 3
+
+ diff-channels:
+ items:
+ maximum: 3
+
+ excitation-channels:
+ maxItems: 2
+ items:
+ maximum: 5
+ description:
+ Additionally to AIN0-AIN3, IDAC1/IDAC2 can also be routed to
+ REFP0 (4) and REFN0 (5).
+
+ excitation-current-nanoamp:
+ enum: [10000, 50000, 100000, 250000, 500000, 1000000, 1500000]
+
+ burn-out-current-nanoamp:
+ const: 10000
+
+ reference-sources:
+ items:
+ - enum: [internal, external, avdd]
+ default: [ internal ]
+
+ dependencies:
+ excitation-channels: [ excitation-current-nanoamp ]
+ excitation-current-nanoamp: [ excitation-channels ]
+
+ oneOf:
+ - required: [ single-channel ]
+ - required: [ diff-channels ]
+
+required:
+ - compatible
+ - reg
+ - avdd-supply
+ - dvdd-supply
+
+dependencies:
+ refn-supply: [ refp-supply ]
+
+oneOf:
+ - required:
+ - refp-supply
+ - required:
+ - ti,refp-refn-resistor-ohms
+ - properties:
+ refp-supply: false
+ refn-supply: false
+ ti,refp-refn-resistor-ohms: false
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include
+ #include
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ adc@40 {
+ compatible = "ti,ads112c04";
+ reg = <0x40>;
+ interrupt-parent = <&gpio>;
+ interrupts = <12 IRQ_TYPE_EDGE_FALLING>;
+
+ reset-gpios = <&gpio 13 GPIO_ACTIVE_LOW>;
+ avdd-supply = <&vdd_3v3_reg>;
+ dvdd-supply = <&vdd_3v3_reg>;
+ refp-supply = <&vref_reg>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ channel@0 {
+ reg = <0>;
+ diff-channels = <0>, <1>;
+ };
+
+ channel@1 {
+ reg = <1>;
+ single-channel = <2>;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/iio/adc/ti,ads1298.yaml b/Documentation/devicetree/bindings/iio/adc/ti,ads1298.yaml
index 71f9f9b745cb..afcc683db149 100644
--- a/Documentation/devicetree/bindings/iio/adc/ti,ads1298.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/ti,ads1298.yaml
@@ -65,15 +65,15 @@ examples:
#size-cells = <0>;
adc@1 {
- reg = <1>;
- compatible = "ti,ads1298";
- label = "ads1298-1-ecg";
- avdd-supply = <®_iso_5v_a>;
- clocks = <&clk_ads1298>;
- interrupt-parent = <&gpio0>;
- interrupts = <78 IRQ_TYPE_EDGE_FALLING>;
- spi-max-frequency = <20000000>;
- spi-cpha;
+ reg = <1>;
+ compatible = "ti,ads1298";
+ label = "ads1298-1-ecg";
+ avdd-supply = <®_iso_5v_a>;
+ clocks = <&clk_ads1298>;
+ interrupt-parent = <&gpio0>;
+ interrupts = <78 IRQ_TYPE_EDGE_FALLING>;
+ spi-max-frequency = <20000000>;
+ spi-cpha;
};
};
...
diff --git a/Documentation/devicetree/bindings/iio/addac/adi,ad74115.yaml b/Documentation/devicetree/bindings/iio/addac/adi,ad74115.yaml
index 2a04906531fb..6aa86cb56032 100644
--- a/Documentation/devicetree/bindings/iio/addac/adi,ad74115.yaml
+++ b/Documentation/devicetree/bindings/iio/addac/adi,ad74115.yaml
@@ -7,7 +7,8 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Analog Devices AD74115H device
maintainers:
- - Cosmin Tanislav
+ - Marcelo Schmitt
+ - Antoniu Miclaus
description: |
The AD74115H is a single-channel software configurable input/output
diff --git a/Documentation/devicetree/bindings/iio/addac/adi,ad74413r.yaml b/Documentation/devicetree/bindings/iio/addac/adi,ad74413r.yaml
index 590ea7936ad7..5318a00e7669 100644
--- a/Documentation/devicetree/bindings/iio/addac/adi,ad74413r.yaml
+++ b/Documentation/devicetree/bindings/iio/addac/adi,ad74413r.yaml
@@ -7,7 +7,8 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Analog Devices AD74412R/AD74413R device
maintainers:
- - Cosmin Tanislav
+ - Marcelo Schmitt
+ - Antoniu Miclaus
description: |
The AD74412R and AD74413R are quad-channel software configurable input/output
diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad3530r.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad3530r.yaml
index 2fe098619772..bf0278335583 100644
--- a/Documentation/devicetree/bindings/iio/dac/adi,ad3530r.yaml
+++ b/Documentation/devicetree/bindings/iio/dac/adi,ad3530r.yaml
@@ -10,13 +10,13 @@ maintainers:
- Kim Seer Paller
description: |
- The AD3530/AD3530R (8-channel), AD3531/AD3531R (4-channel), and AD3532/AD3532R
- (16-channel) are low-power, 16-bit, buffered voltage output digital-to-analog
- converters (DACs) with software-programmable gain controls, providing
- full-scale output spans of 2.5V or 5V for reference voltages of 2.5V. These
- devices operate from a single 2.7V to 5.5V supply and are guaranteed monotonic
- by design. The "R" variants include a 2.5V, 5ppm/°C internal reference, which
- is disabled by default.
+ The AD3530/AD3530R (8-channel), AD3531/AD3531R (4-channel), AD3532/AD3532R
+ (16-channel), 16-bit and AD3536R (16-channel), 12-bit are low-power, buffered
+ voltage output digital-to-analog converters (DACs) with software-programmable
+ gain controls, providing full-scale output spans of 2.5V or 5V for reference
+ voltages of 2.5V. These devices operate from a single 2.7V to 5.5V supply and
+ are guaranteed monotonic by design. The "R" variants include a 2.5V, 5ppm/°C
+ internal reference, which is disabled by default.
Datasheet can be found here:
https://www.analog.com/media/en/technical-documentation/data-sheets/ad3530_ad530r.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/ad3531-ad3531r.pdf
@@ -31,6 +31,7 @@ properties:
- adi,ad3531r
- adi,ad3532
- adi,ad3532r
+ - adi,ad3536r
reg:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad5529r.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad5529r.yaml
new file mode 100644
index 000000000000..9c390d460e5f
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/dac/adi,ad5529r.yaml
@@ -0,0 +1,254 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/dac/adi,ad5529r.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices AD5529R 16-Channel 12/16-bit High Voltage DAC
+
+maintainers:
+ - Janani Sunil
+
+description: |
+ The AD5529R is a 16-channel, 12-bit or 16-bit, high voltage, buffered voltage
+ output digital-to-analog converter (DAC) with an integrated precision reference.
+ The device operates from unipolar and bipolar supplies. It is guaranteed
+ monotonic and has built-in rail-to-rail output buffers that can source or
+ sink up to 25mA.
+
+ Specifications:
+ * 16 independent 12-bit or 16-bit DAC channels
+ * Independently programmable output ranges: 0V to 5V, 0V to 10V, 0V to 20V,
+ 0V to 40V, ±5V, ±10V, ±15V, and ±20V
+ * The device supports SPI communication with Mode 0 and Mode 3.
+ * 4.096V precision reference, 12ppm/°C maximum
+ * Built-in function generation: Toggle, Sinusoidal Dither, and Ramp waveforms
+ * Multiplexer for output voltage, load current sense and die temperature
+
+ Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ad5529r.pdf
+
+properties:
+ compatible:
+ enum:
+ - adi,ad5529r-16 # 16-bit variant
+ - adi,ad5529r-12 # 12-bit variant
+
+ reg:
+ maxItems: 1
+
+ spi-max-frequency:
+ maximum: 25000000
+ description:
+ Maximum SPI frequency. The device supports SPI Mode 0 and Mode 3.
+ Read operations are limited to 25MHz maximum.
+
+ reset-gpios:
+ maxItems: 1
+ description:
+ GPIO connected to the RESET pin. Active low. When asserted low,
+ performs a power-on reset and initializes the device to its default state.
+
+ clear-gpios:
+ maxItems: 1
+ description:
+ GPIO connected to the CLEAR pin. Active low. When asserted low,
+ clears all DAC data registers without affecting configuration settings.
+
+ interrupts:
+ maxItems: 1
+ description:
+ Interrupt connected to the ALARM pin. Active low interrupt output
+ for overtemperature conditions, SPI CRC errors, and function completion.
+
+ pwms:
+ minItems: 1
+ maxItems: 4
+ description:
+ PWM signals connected to the TG0-TG3 toggle pins. Pulsing these pins
+ based on trigger edge settings allows selected DACs to be updated
+ synchronously for digital function generation.
+
+ pwm-names:
+ minItems: 1
+ maxItems: 4
+ items:
+ enum: [ tg0, tg1, tg2, tg3 ]
+
+ io-channels:
+ maxItems: 1
+ description:
+ ADC channel connected to the MUXOUT pin for monitoring output voltage,
+ load current sense, and die temperature.
+
+ io-channel-names:
+ const: muxout
+
+ vdd-io-supply:
+ description: Digital power supply (1.08V to 1.98V)
+
+ vdd-5v-supply:
+ description: Analog power supply (4.75V to 5.25V)
+
+ vdd-hv0-supply:
+ description:
+ High voltage positive supply (7V to 45V) for channels 0 to 3.
+
+ vdd-hv1-supply:
+ description:
+ High voltage positive supply (7V to 45V) for channels 4 to 7.
+
+ vdd-hv2-supply:
+ description:
+ High voltage positive supply (7V to 45V) for channels 8 to 11.
+
+ vdd-hv3-supply:
+ description:
+ High voltage positive supply (7V to 45V) for channels 12 to 15.
+
+ vss-hv0-supply:
+ description:
+ High voltage negative supply (-22.5V to 0V) for channels 0 to 3.
+
+ vss-hv1-supply:
+ description:
+ High voltage negative supply (-22.5V to 0V) for channels 4 to 7.
+
+ vss-hv2-supply:
+ description:
+ High voltage negative supply (-22.5V to 0V) for channels 8 to 11.
+
+ vss-hv3-supply:
+ description:
+ High voltage negative supply (-22.5V to 0V) for channels 12 to 15.
+
+ vref-supply:
+ description:
+ External voltage reference supply (4.056V to 4.136V, typically 4.096V).
+ When specified, the device uses external reference mode and the VREF pin
+ becomes an input. The device uses the internal 4.096V precision reference
+ otherwise.
+
+ spi-device-addr:
+ minItems: 1
+ maxItems: 4
+ items:
+ enum: [0, 1, 2, 3]
+ default: 0
+ description:
+ Hardware address of each device, selected by the ID0 and ID1 pins.
+ Up to four AD5529R devices can share a single SPI chip select.
+
+ "#address-cells":
+ const: 1
+
+ "#size-cells":
+ const: 0
+
+patternProperties:
+ "^channel@([0-9a-f]{1,2})$":
+ $ref: dac.yaml
+ type: object
+ description: Child nodes for individual channel configuration
+
+ properties:
+ reg:
+ description:
+ Flattened channel number across all AD5529R devices sharing the chip
+ select. Within each 16-channel block, the physical channel number is reg % 16.
+ minimum: 0
+ maximum: 63
+
+ output-range-microvolt:
+ description:
+ Output voltage range for this channel as [min, max] in
+ microvolts.
+ oneOf:
+ - items:
+ - const: 0
+ default: 0
+ - enum: [5000000, 10000000, 20000000, 40000000]
+ default: 5000000
+ - items:
+ - const: -5000000
+ - const: 5000000
+ - items:
+ - const: -10000000
+ - const: 10000000
+ - items:
+ - const: -15000000
+ - const: 15000000
+ - items:
+ - const: -20000000
+ - const: 20000000
+
+ required:
+ - reg
+
+ additionalProperties: false
+
+required:
+ - compatible
+ - reg
+ - vdd-io-supply
+ - vdd-5v-supply
+ - vdd-hv0-supply
+ - vdd-hv1-supply
+ - vdd-hv2-supply
+ - vdd-hv3-supply
+
+dependencies:
+ spi-cpha: [ spi-cpol ]
+ spi-cpol: [ spi-cpha ]
+
+allOf:
+ - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include
+
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ dac@0 {
+ compatible = "adi,ad5529r-16";
+ reg = <0>;
+ spi-max-frequency = <25000000>;
+ spi-device-addr = <0>;
+
+ vdd-io-supply = <&vdd_io_regulator>;
+ vdd-5v-supply = <&vdd_5v_regulator>;
+ vdd-hv0-supply = <&vdd_hv0_regulator>;
+ vdd-hv1-supply = <&vdd_hv1_regulator>;
+ vdd-hv2-supply = <&vdd_hv2_regulator>;
+ vdd-hv3-supply = <&vdd_hv3_regulator>;
+ vss-hv0-supply = <&vss_hv0_regulator>;
+ vss-hv1-supply = <&vss_hv1_regulator>;
+ vss-hv2-supply = <&vss_hv2_regulator>;
+ vss-hv3-supply = <&vss_hv3_regulator>;
+
+ reset-gpios = <&gpio0 87 GPIO_ACTIVE_LOW>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ channel@0 {
+ reg = <0>;
+ output-range-microvolt = <0 5000000>;
+ };
+
+ channel@1 {
+ reg = <1>;
+ output-range-microvolt = <(-10000000) 10000000>;
+ };
+
+ channel@2 {
+ reg = <2>;
+ output-range-microvolt = <0 40000000>;
+ };
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad5710r.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad5710r.yaml
new file mode 100644
index 000000000000..cdcc3da4f4ea
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/dac/adi,ad5710r.yaml
@@ -0,0 +1,145 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/dac/adi,ad5710r.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices AD5710R/AD5711R 8-channel 12-/16-bit Configurable IDAC/VDAC
+
+maintainers:
+ - Kim Seer Paller
+
+description: |
+ The AD5710R (16-bit) and AD5711R (12-bit) are 8-channel, low-power,
+ configurable current/voltage output digital-to-analog converters (DACs) with
+ an on-chip 2.5V, 3ppm/°C reference. Each channel can be independently
+ configured as a voltage output (0V to VREF or 0V to 2 x VREF) or a current
+ output (0mA to 50mA). These devices operate from a single 2.7V to 5.5V
+ supply and are guaranteed monotonic by design.
+
+ Datasheet can be found here:
+ https://www.analog.com/media/en/technical-documentation/data-sheets/ad5711r-ad5710r.pdf
+
+properties:
+ compatible:
+ enum:
+ - adi,ad5710r
+ - adi,ad5711r
+
+ reg:
+ maxItems: 1
+
+ spi-max-frequency:
+ maximum: 20000000
+
+ '#address-cells':
+ const: 1
+
+ '#size-cells':
+ const: 0
+
+ vdd-supply:
+ description: Power Supply Input.
+
+ iovdd-supply:
+ description: Digital Power Supply Input.
+
+ io-channels:
+ description:
+ ADC channel used to monitor internal die temperature, output voltages, and
+ current of a selected channel via the MUXOUT pin.
+ maxItems: 1
+
+ ref-supply:
+ description:
+ Reference Input/Output. The voltage at the REF pin sets the full-scale
+ range of all channels. If not provided the internal reference is used and
+ also provided on the VREF pin.
+
+ reset-gpios:
+ description:
+ Active low signal that is falling edge sensitive. When it is deasserted,
+ the digital core initialization is performed and all DAC registers except
+ the Interface Configuration A register are reset to their default values.
+ maxItems: 1
+
+ ldac-gpios:
+ description:
+ LDAC pin to be used as a hardware trigger to update the DAC channels. If
+ not present, the DAC channels are updated by Software LDAC.
+ maxItems: 1
+
+ adi,range-double:
+ description:
+ Configure the output range for all channels. If the property is present,
+ the output will range from 0V to 2 x Vref. If the property is not present,
+ the output will range from 0V to Vref.
+ type: boolean
+
+patternProperties:
+ "^channel@[0-7]$":
+ $ref: /schemas/iio/dac/dac.yaml#
+ type: object
+ description:
+ Represents the external channels which are connected to the DAC.
+
+ properties:
+ reg:
+ description: Channel number
+ minimum: 0
+ maximum: 7
+
+ adi,ch-func:
+ description:
+ Channel output type. The values are defined in
+ . Use
+ CH_FUNC_VOLTAGE_OUTPUT (1) for voltage output or
+ CH_FUNC_CURRENT_OUTPUT (2) for current output.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [1, 2]
+
+ required:
+ - reg
+ - adi,ch-func
+
+ unevaluatedProperties: false
+
+required:
+ - compatible
+ - reg
+ - vdd-supply
+ - iovdd-supply
+
+allOf:
+ - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include
+
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ dac@0 {
+ compatible = "adi,ad5710r";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ vdd-supply = <&vdd>;
+ iovdd-supply = <&iovdd>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ channel@0 {
+ reg = <0>;
+ adi,ch-func = ;
+ };
+
+ channel@1 {
+ reg = <1>;
+ adi,ch-func = ;
+ };
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/iio/dac/microchip,mcp47feb02.yaml b/Documentation/devicetree/bindings/iio/dac/microchip,mcp47feb02.yaml
index d131f136bd15..a86d094f0d4b 100644
--- a/Documentation/devicetree/bindings/iio/dac/microchip,mcp47feb02.yaml
+++ b/Documentation/devicetree/bindings/iio/dac/microchip,mcp47feb02.yaml
@@ -4,58 +4,92 @@
$id: http://devicetree.org/schemas/iio/dac/microchip,mcp47feb02.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
-title: Microchip MCP47F(E/V)B(0/1/2)(1/2/4/8) DAC with I2C Interface Families
+title: Microchip MCP4(7/8)F(E/V)B(0/1/2)(1/2/4/8) DAC with I2C/SPI Interface Families
maintainers:
- Ariana Lazar
description: |
- Datasheet for MCP47FEB01, MCP47FEB11, MCP47FEB21, MCP47FEB02, MCP47FEB12,
- MCP47FEB22 can be found here:
- https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/20005375A.pdf
- Datasheet for MCP47FVB01, MCP47FVB11, MCP47FVB21, MCP47FVB02, MCP47FVB12,
- MCP47FVB22 can be found here:
- https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/20005405A.pdf
- Datasheet for MCP47FEB04, MCP47FEB14, MCP47FEB24, MCP47FEB08, MCP47FEB18,
- MCP47FEB28, MCP47FVB04, MCP47FVB14, MCP47FVB24, MCP47FVB08, MCP47FVB18,
- MCP47FVB28 can be found here:
- https://ww1.microchip.com/downloads/aemDocuments/documents/MSLD/ProductDocuments/DataSheets/MCP47FXBX48-Data-Sheet-DS200006368A.pdf
+ Datasheets for MCP47F(E/V)B(0/1/2)(1/2/4/8) DAC with I2C Interface Families:
+ Datasheet for MCP47FEB01, MCP47FEB02, MCP47FEB11, MCP47FEB12, MCP47FEB21,
+ MCP47FEB22 can be found here:
+ https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/20005375A.pdf
+ Datasheet for MCP47FVB01, MCP47FVB02, MCP47FVB11, MCP47FVB12, MCP47FVB21,
+ MCP47FVB22 can be found here:
+ https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/20005405A.pdf
+ Datasheet for MCP47FEB04, MCP47FEB08, MCP47FEB14, MCP47FEB18, MCP47FEB24,
+ MCP47FEB28, MCP47FVB04, MCP47FVB08, MCP47FVB14, MCP47FVB18, MCP47FVB24,
+ MCP47FVB28 can be found here:
+ https://ww1.microchip.com/downloads/aemDocuments/documents/MSLD/ProductDocuments/DataSheets/MCP47FXBX48-Data-Sheet-DS200006368A.pdf
+ Datasheets for MCP48F(E/V)B(0/1/2)(1/2/4/8) DAC with SPI Interface Families:
+ Datasheet for MCP48FEB01, MCP48FEB02, MCP48FEB11, MCP48FEB12, MCP48FEB21,
+ MCP48FEB22 can be found here:
+ https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/20005429B.pdf
+ Datasheet for MCP48FVB01, MCP48FVB02, MCP48FVB11, MCP48FVB12, MCP48FVB21,
+ MCP48FVB22 can be found here:
+ https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/20005466A.pdf
+ Datasheet for MCP48FEB04, MCP48FEB14, MCP48FEB24, MCP48FEB08, MCP48FEB18,
+ MCP48FEB28, MCP48FVB04, MCP48FVB14, MCP48FVB24, MCP48FVB08, MCP48FVB18,
+ MCP48FVB28 can be found here:
+ https://ww1.microchip.com/downloads/aemDocuments/documents/MSLD/ProductDocuments/DataSheets/MCP48FXBX4-8-Family-Data-Sheet-DS20006362A.pdf
- +------------+--------------+-------------+-------------+------------+
- | Device | Resolution | Channels | Vref number | Memory |
- |------------|--------------|-------------|-------------|------------|
- | MCP47FEB01 | 8-bit | 1 | 1 | EEPROM |
- | MCP47FEB11 | 10-bit | 1 | 1 | EEPROM |
- | MCP47FEB21 | 12-bit | 1 | 1 | EEPROM |
- |------------|--------------|-------------|-------------|------------|
- | MCP47FEB02 | 8-bit | 2 | 1 | EEPROM |
- | MCP47FEB12 | 10-bit | 2 | 1 | EEPROM |
- | MCP47FEB22 | 12-bit | 2 | 1 | EEPROM |
- |------------|--------------|-------------|-------------|------------|
- | MCP47FVB01 | 8-bit | 1 | 1 | RAM |
- | MCP47FVB11 | 10-bit | 1 | 1 | RAM |
- | MCP47FVB21 | 12-bit | 1 | 1 | RAM |
- |------------|--------------|-------------|-------------|------------|
- | MCP47FVB02 | 8-bit | 2 | 1 | RAM |
- | MCP47FVB12 | 10-bit | 2 | 1 | RAM |
- | MCP47FVB22 | 12-bit | 2 | 1 | RAM |
- |------------|--------------|-------------|-------------|------------|
- | MCP47FVB04 | 8-bit | 4 | 2 | RAM |
- | MCP47FVB14 | 10-bit | 4 | 2 | RAM |
- | MCP47FVB24 | 12-bit | 4 | 2 | RAM |
- |------------|--------------|-------------|-------------|------------|
- | MCP47FVB08 | 8-bit | 8 | 2 | RAM |
- | MCP47FVB18 | 10-bit | 8 | 2 | RAM |
- | MCP47FVB28 | 12-bit | 8 | 2 | RAM |
- |------------|--------------|-------------|-------------|------------|
- | MCP47FEB04 | 8-bit | 4 | 2 | EEPROM |
- | MCP47FEB14 | 10-bit | 4 | 2 | EEPROM |
- | MCP47FEB24 | 12-bit | 4 | 2 | EEPROM |
- |------------|--------------|-------------|-------------|------------|
- | MCP47FEB08 | 8-bit | 8 | 2 | EEPROM |
- | MCP47FEB18 | 10-bit | 8 | 2 | EEPROM |
- | MCP47FEB28 | 12-bit | 8 | 2 | EEPROM |
- +------------+--------------+-------------+-------------+------------+
+ +------------+--------------+-------------+-------------+------------+------------+
+ | Device | Resolution | Channels | Vref number | Memory | Interface |
+ |------------|--------------|-------------|-------------|------------|------------|
+ | MCP47FEB01 | | 1 | 1 | EEPROM | I2C |
+ | MCP47FEB02 | | 2 | 1 | EEPROM | I2C |
+ | MCP47FEB04 | | 4 | 2 | EEPROM | I2C |
+ | MCP47FEB08 | 8-bit | 8 | 2 | EEPROM | I2C |
+ | MCP48FEB01 | | 1 | 1 | EEPROM | SPI |
+ | MCP48FEB02 | | 2 | 1 | EEPROM | SPI |
+ | MCP48FEB04 | | 4 | 2 | EEPROM | SPI |
+ | MCP48FEB08 | | 8 | 2 | EEPROM | SPI |
+ |------------|--------------|-------------|-------------|------------|------------|
+ | MCP47FEB11 | | 1 | 1 | EEPROM | I2C |
+ | MCP47FEB12 | | 2 | 1 | EEPROM | I2C |
+ | MCP47FEB14 | | 4 | 2 | EEPROM | I2C |
+ | MCP47FEB18 | 10-bit | 8 | 2 | EEPROM | I2C |
+ | MCP48FEB11 | | 1 | 1 | EEPROM | SPI |
+ | MCP48FEB12 | | 2 | 1 | EEPROM | SPI |
+ | MCP48FEB14 | | 4 | 2 | EEPROM | SPI |
+ | MCP48FEB18 | | 8 | 2 | EEPROM | SPI |
+ |------------|--------------|-------------|-------------|------------|------------|
+ | MCP47FEB21 | | 1 | 1 | EEPROM | I2C |
+ | MCP47FEB22 | | 2 | 1 | EEPROM | I2C |
+ | MCP47FEB24 | | 4 | 2 | EEPROM | I2C |
+ | MCP47FEB28 | 12-bit | 8 | 2 | EEPROM | I2C |
+ | MCP48FEB21 | | 1 | 1 | EEPROM | SPI |
+ | MCP48FEB22 | | 2 | 1 | EEPROM | SPI |
+ | MCP48FEB24 | | 4 | 2 | EEPROM | SPI |
+ | MCP48FEB28 | | 8 | 2 | EEPROM | SPI |
+ |------------|--------------|-------------|-------------|------------|------------|
+ | MCP47FVB01 | | 1 | 1 | RAM | I2C |
+ | MCP47FVB02 | | 2 | 1 | RAM | I2C |
+ | MCP47FVB04 | | 4 | 2 | RAM | I2C |
+ | MCP47FVB08 | 8-bit | 8 | 2 | RAM | I2C |
+ | MCP48FVB01 | | 1 | 1 | RAM | SPI |
+ | MCP48FVB02 | | 2 | 1 | RAM | SPI |
+ | MCP48FVB04 | | 4 | 2 | RAM | SPI |
+ | MCP48FVB08 | | 8 | 2 | RAM | SPI |
+ |------------|--------------|-------------|-------------|------------|------------|
+ | MCP47FVB11 | | 1 | 1 | RAM | I2C |
+ | MCP47FVB12 | | 2 | 1 | RAM | I2C |
+ | MCP47FVB14 | | 4 | 2 | RAM | I2C |
+ | MCP47FVB18 | 10-bit | 8 | 2 | RAM | I2C |
+ | MCP48FVB11 | | 1 | 1 | RAM | SPI |
+ | MCP48FVB12 | | 2 | 1 | RAM | SPI |
+ | MCP48FVB14 | | 4 | 2 | RAM | SPI |
+ | MCP48FVB18 | | 8 | 2 | RAM | SPI |
+ |------------|--------------|-------------|-------------|------------|------------|
+ | MCP47FVB21 | | 1 | 1 | RAM | I2C |
+ | MCP47FVB22 | | 2 | 1 | RAM | I2C |
+ | MCP47FVB24 | | 4 | 2 | RAM | I2C |
+ | MCP47FVB28 | 12-bit | 8 | 2 | RAM | I2C |
+ | MCP48FVB21 | | 1 | 1 | RAM | SPI |
+ | MCP48FVB22 | | 2 | 1 | RAM | SPI |
+ | MCP48FVB24 | | 4 | 2 | RAM | SPI |
+ | MCP48FVB28 | | 8 | 2 | RAM | SPI |
+ +------------+--------------+-------------+-------------+------------+------------+
properties:
compatible:
@@ -84,10 +118,37 @@ properties:
- microchip,mcp47feb08
- microchip,mcp47feb18
- microchip,mcp47feb28
+ - microchip,mcp48feb01
+ - microchip,mcp48feb02
+ - microchip,mcp48feb04
+ - microchip,mcp48feb08
+ - microchip,mcp48feb11
+ - microchip,mcp48feb12
+ - microchip,mcp48feb14
+ - microchip,mcp48feb18
+ - microchip,mcp48feb21
+ - microchip,mcp48feb22
+ - microchip,mcp48feb24
+ - microchip,mcp48feb28
+ - microchip,mcp48fvb01
+ - microchip,mcp48fvb02
+ - microchip,mcp48fvb04
+ - microchip,mcp48fvb08
+ - microchip,mcp48fvb11
+ - microchip,mcp48fvb12
+ - microchip,mcp48fvb14
+ - microchip,mcp48fvb18
+ - microchip,mcp48fvb21
+ - microchip,mcp48fvb22
+ - microchip,mcp48fvb24
+ - microchip,mcp48fvb28
reg:
maxItems: 1
+ spi-max-frequency:
+ maximum: 10000000
+
"#address-cells":
const: 1
@@ -178,6 +239,21 @@ required:
- vdd-supply
allOf:
+ - if:
+ properties:
+ compatible:
+ contains:
+ pattern: "^microchip,mcp48f[ev]b[0-2][1248]$"
+ then:
+ $ref: /schemas/spi/spi-peripheral-props.yaml#
+ dependencies:
+ spi-cpha: [ spi-cpol ]
+ spi-cpol: [ spi-cpha ]
+ else:
+ properties:
+ spi-max-frequency: false
+ spi-cpha: false
+ spi-cpol: false
- if:
properties:
compatible:
@@ -189,6 +265,12 @@ allOf:
- microchip,mcp47fvb01
- microchip,mcp47fvb11
- microchip,mcp47fvb21
+ - microchip,mcp48feb01
+ - microchip,mcp48feb11
+ - microchip,mcp48feb21
+ - microchip,mcp48fvb01
+ - microchip,mcp48fvb11
+ - microchip,mcp48fvb21
then:
properties:
lat1-gpios: false
@@ -211,6 +293,12 @@ allOf:
- microchip,mcp47fvb02
- microchip,mcp47fvb12
- microchip,mcp47fvb22
+ - microchip,mcp48feb02
+ - microchip,mcp48feb12
+ - microchip,mcp48feb22
+ - microchip,mcp48fvb02
+ - microchip,mcp48fvb12
+ - microchip,mcp48fvb22
then:
properties:
lat1-gpios: false
@@ -233,6 +321,12 @@ allOf:
- microchip,mcp47feb04
- microchip,mcp47feb14
- microchip,mcp47feb24
+ - microchip,mcp48feb04
+ - microchip,mcp48feb14
+ - microchip,mcp48feb24
+ - microchip,mcp48fvb04
+ - microchip,mcp48fvb14
+ - microchip,mcp48fvb24
then:
patternProperties:
"^channel@[0-3]$":
@@ -251,6 +345,12 @@ allOf:
- microchip,mcp47feb08
- microchip,mcp47feb18
- microchip,mcp47feb28
+ - microchip,mcp48feb08
+ - microchip,mcp48feb18
+ - microchip,mcp48feb28
+ - microchip,mcp48fvb08
+ - microchip,mcp48fvb18
+ - microchip,mcp48fvb28
then:
patternProperties:
"^channel@[0-7]$":
@@ -272,7 +372,7 @@ allOf:
properties:
microchip,vref1-buffered: false
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
@@ -299,4 +399,29 @@ examples:
};
};
};
+ - |
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ dac@0 {
+ compatible = "microchip,mcp48feb02";
+ reg = <0x0>;
+ vdd-supply = <&vdac_vdd>;
+ vref-supply = <&vref_reg>;
+ spi-max-frequency = <10000000>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+ channel@0 {
+ reg = <0>;
+ label = "Adjustable_voltage_ch0";
+ };
+
+ channel@1 {
+ reg = <0x1>;
+ label = "Adjustable_voltage_ch1";
+ };
+ };
+ };
...
diff --git a/Documentation/devicetree/bindings/iio/frequency/adi,ad9910.yaml b/Documentation/devicetree/bindings/iio/frequency/adi,ad9910.yaml
new file mode 100644
index 000000000000..4eebbd388b27
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/frequency/adi,ad9910.yaml
@@ -0,0 +1,209 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/frequency/adi,ad9910.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices AD9910 Direct Digital Synthesizer
+
+maintainers:
+ - Rodrigo Alencar
+
+description: >
+ The AD9910 is a 1 GSPS direct digital synthesizer (DDS) with an integrated
+ 14-bit DAC. It features single tone mode with 8 configurable profiles,
+ a digital ramp generator, RAM control, OSK, and a parallel data port for
+ high-speed streaming.
+
+ https://www.analog.com/en/products/ad9910.html
+
+properties:
+ compatible:
+ const: adi,ad9910
+
+ reg:
+ maxItems: 1
+
+ spi-max-frequency:
+ maximum: 70000000
+
+ clocks:
+ minItems: 1
+ items:
+ - description: Reference clock (REF_CLK).
+ - description: Optional synchronization clock (SYNC_IN).
+
+ clock-names:
+ minItems: 1
+ items:
+ - const: ref_clk
+ - const: sync_in
+
+ '#clock-cells':
+ const: 1
+
+ clock-output-names:
+ items:
+ - const: sync_clk
+ - const: pdclk
+ - const: sync_out
+
+ interrupts:
+ minItems: 1
+ maxItems: 2
+ description:
+ Requires interrupt-names property with the same number of items. The
+ supported interrupts are 'drover' (digital ramp generator limit) and
+ 'ram_swp_ovr' (end of RAM sweep).
+
+ interrupt-names:
+ minItems: 1
+ maxItems: 2
+ items:
+ enum: [ drover, ram_swp_ovr ]
+
+ dvdd-io33-supply:
+ description: 3.3V Digital I/O supply.
+
+ avdd33-supply:
+ description: 3.3V Analog DAC supply.
+
+ dvdd18-supply:
+ description: 1.8V Digital Core supply.
+
+ avdd18-supply:
+ description: 1.8V Analog Core supply.
+
+ reset-gpios:
+ maxItems: 1
+ description:
+ GPIOs controlling the Main Device reset.
+
+ io-reset-gpios:
+ maxItems: 1
+ description:
+ GPIO controlling the I/O_RESET pin.
+
+ powerdown-gpios:
+ maxItems: 1
+ description:
+ GPIO controlling the EXT_PWR_DWN pin.
+
+ update-gpios:
+ maxItems: 1
+ description:
+ GPIO controlling the I/O_UPDATE pin.
+
+ profile-gpios:
+ minItems: 3
+ maxItems: 3
+ description:
+ GPIOs controlling the PROFILE[2:0] pins for profile selection.
+
+ sync-err-gpios:
+ maxItems: 1
+ description:
+ GPIO used to read SYNC_SMP_ERR pin status.
+
+ lock-detect-gpios:
+ maxItems: 1
+ description:
+ GPIO used to read PLL_LOCK pin status.
+
+ pwms:
+ maxItems: 1
+ description:
+ PWM used to drive the DRCTL pin, which controls the digital ramp
+ generator slope direction.
+
+ pwm-names:
+ items:
+ - const: drctl
+
+ adi,pll-enable:
+ type: boolean
+ description:
+ Enables the internal PLL. Applicable when external loop filter components
+ are connected to the PLL_LOOP_FILTER pin and low reference clock
+ frequencies are used, often provided by a crystal or by a single-ended
+ on-board oscillator.
+
+ adi,charge-pump-current-microamp:
+ minimum: 212
+ maximum: 387
+ default: 212
+ description:
+ PLL charge pump current in microamps. Only applicable when the internal
+ PLL is enabled. The value is rounded to the nearest supported step. This
+ value depends mostly on the loop filter design.
+
+ adi,refclk-out-drive-strength:
+ $ref: /schemas/types.yaml#/definitions/string
+ enum: [ disabled, low, medium, high ]
+ default: disabled
+ description:
+ Reference clock output (DRV0) drive strength. Only applicable when
+ the internal PLL is enabled.
+
+dependencies:
+ adi,charge-pump-current-microamp: [ 'adi,pll-enable' ]
+ adi,refclk-out-drive-strength: [ 'adi,pll-enable' ]
+ lock-detect-gpios: [ 'adi,pll-enable' ]
+ interrupts: [ interrupt-names ]
+ pwms: [ pwm-names ]
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+ - '#clock-cells'
+ - dvdd-io33-supply
+ - avdd33-supply
+ - dvdd18-supply
+ - avdd18-supply
+
+allOf:
+ - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ dds@0 {
+ compatible = "adi,ad9910";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+
+ #clock-cells = <1>;
+ clock-output-names = "sync_clk", "pdclk", "sync_out";
+
+ clocks = <&ad9910_refclk>;
+ clock-names = "ref_clk";
+
+ dvdd-io33-supply = <&vdd_io33>;
+ avdd33-supply = <&vdd_a33>;
+ dvdd18-supply = <&vdd_d18>;
+ avdd18-supply = <&vdd_a18>;
+
+ reset-gpios = <&gpio 0 GPIO_ACTIVE_HIGH>;
+ io-reset-gpios = <&gpio 1 GPIO_ACTIVE_HIGH>;
+ powerdown-gpios = <&gpio 2 GPIO_ACTIVE_HIGH>;
+ update-gpios = <&gpio 3 GPIO_ACTIVE_HIGH>;
+ profile-gpios = <&gpio 4 GPIO_ACTIVE_HIGH>,
+ <&gpio 5 GPIO_ACTIVE_HIGH>,
+ <&gpio 6 GPIO_ACTIVE_HIGH>;
+
+ pwms = <&pwm 0 1000000 0>;
+ pwm-names = "drctl";
+
+ adi,pll-enable;
+ adi,charge-pump-current-microamp = <387>;
+ adi,refclk-out-drive-strength = "disabled";
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
index 81b6e85decd5..9e22b603d47f 100644
--- a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
+++ b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
@@ -26,16 +26,20 @@ description: |
properties:
compatible:
- enum:
- - invensense,icm42600
- - invensense,icm42602
- - invensense,icm42605
- - invensense,icm42607
- - invensense,icm42607p
- - invensense,icm42622
- - invensense,icm42631
- - invensense,icm42686
- - invensense,icm42688
+ oneOf:
+ - enum:
+ - invensense,icm42600
+ - invensense,icm42602
+ - invensense,icm42605
+ - invensense,icm42607
+ - invensense,icm42607p
+ - invensense,icm42622
+ - invensense,icm42631
+ - invensense,icm42686
+ - invensense,icm42688
+ - items:
+ - const: invensense,icm42630
+ - const: invensense,icm42631
reg:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/iio/light/adux1020.yaml b/Documentation/devicetree/bindings/iio/light/adux1020.yaml
index d7d14f2f1c20..83abe984a1da 100644
--- a/Documentation/devicetree/bindings/iio/light/adux1020.yaml
+++ b/Documentation/devicetree/bindings/iio/light/adux1020.yaml
@@ -40,10 +40,10 @@ examples:
#size-cells = <0>;
adux1020@64 {
- compatible = "adi,adux1020";
- reg = <0x64>;
- interrupt-parent = <&msmgpio>;
- interrupts = <24 IRQ_TYPE_LEVEL_HIGH>;
+ compatible = "adi,adux1020";
+ reg = <0x64>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <24 IRQ_TYPE_LEVEL_HIGH>;
};
};
...
diff --git a/Documentation/devicetree/bindings/iio/light/amstaos,tsl2591.yaml b/Documentation/devicetree/bindings/iio/light/amstaos,tsl2591.yaml
index 83b88c6a243d..512625d625a8 100644
--- a/Documentation/devicetree/bindings/iio/light/amstaos,tsl2591.yaml
+++ b/Documentation/devicetree/bindings/iio/light/amstaos,tsl2591.yaml
@@ -45,6 +45,6 @@ examples:
compatible = "amstaos,tsl2591";
reg = <0x29>;
interrupts = <20 IRQ_TYPE_EDGE_FALLING>;
- };
+ };
};
...
diff --git a/Documentation/devicetree/bindings/iio/light/capella,cm32181.yaml b/Documentation/devicetree/bindings/iio/light/capella,cm32181.yaml
new file mode 100644
index 000000000000..e64085a9cb2b
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/light/capella,cm32181.yaml
@@ -0,0 +1,44 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/light/capella,cm32181.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Capella CM32181 ambient light sensor
+
+maintainers:
+ - Kevin Tsai
+
+properties:
+ compatible:
+ const: capella,cm32181
+
+ reg:
+ maxItems: 1
+
+ vdd-supply: true
+
+ interrupts:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+
+additionalProperties: false
+
+examples:
+ - |
+ #include
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ light-sensor@10 {
+ compatible = "capella,cm32181";
+ reg = <0x10>;
+ vdd-supply = <&vdd_3v3>;
+ interrupt-parent = <&gpio>;
+ interrupts = <17 IRQ_TYPE_EDGE_RISING>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/iio/light/isl29018.yaml b/Documentation/devicetree/bindings/iio/light/isl29018.yaml
index 0ea278b07d1c..9524f0a1d195 100644
--- a/Documentation/devicetree/bindings/iio/light/isl29018.yaml
+++ b/Documentation/devicetree/bindings/iio/light/isl29018.yaml
@@ -50,9 +50,9 @@ examples:
#size-cells = <0>;
sensor@44 {
- compatible = "isil,isl29018";
- reg = <0x44>;
- interrupts-extended = <&msmgpio 61 IRQ_TYPE_LEVEL_HIGH>;
+ compatible = "isil,isl29018";
+ reg = <0x44>;
+ interrupts-extended = <&msmgpio 61 IRQ_TYPE_LEVEL_HIGH>;
};
};
...
diff --git a/Documentation/devicetree/bindings/iio/light/liteon,ltr501.yaml b/Documentation/devicetree/bindings/iio/light/liteon,ltr501.yaml
index c8074f180a79..20abd7da080d 100644
--- a/Documentation/devicetree/bindings/iio/light/liteon,ltr501.yaml
+++ b/Documentation/devicetree/bindings/iio/light/liteon,ltr501.yaml
@@ -9,15 +9,14 @@ title: LiteON LTR501 I2C Proximity and Light sensor
maintainers:
- Nikita Travkin
-allOf:
- - $ref: ../common.yaml#
-
properties:
compatible:
enum:
+ - liteon,ltr301
+ - liteon,ltr303
+ - liteon,ltr329
- liteon,ltr501
- liteon,ltr559
- - liteon,ltr301
reg:
maxItems: 1
@@ -36,6 +35,31 @@ required:
- compatible
- reg
+allOf:
+ - $ref: ../common.yaml#
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - liteon,ltr329
+ then:
+ properties:
+ interrupts: false
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - liteon,ltr301
+ - liteon,ltr303
+ - liteon,ltr329
+ then:
+ properties:
+ proximity-near-level: false
+
examples:
- |
#include
diff --git a/Documentation/devicetree/bindings/iio/light/noa1305.yaml b/Documentation/devicetree/bindings/iio/light/noa1305.yaml
index fe7bfe1adbda..e1c64c151932 100644
--- a/Documentation/devicetree/bindings/iio/light/noa1305.yaml
+++ b/Documentation/devicetree/bindings/iio/light/noa1305.yaml
@@ -39,8 +39,8 @@ examples:
#size-cells = <0>;
light@39 {
- compatible = "onnn,noa1305";
- reg = <0x39>;
+ compatible = "onnn,noa1305";
+ reg = <0x39>;
};
};
...
diff --git a/Documentation/devicetree/bindings/iio/light/stk33xx.yaml b/Documentation/devicetree/bindings/iio/light/stk33xx.yaml
index e4341fdced98..f655a570aac7 100644
--- a/Documentation/devicetree/bindings/iio/light/stk33xx.yaml
+++ b/Documentation/devicetree/bindings/iio/light/stk33xx.yaml
@@ -4,14 +4,14 @@
$id: http://devicetree.org/schemas/iio/light/stk33xx.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
-title: |
- Sensortek STK33xx I2C Ambient Light and Proximity sensor
+title: Sensortek STK33xx/STK36C61 I2C Ambient Light and Proximity sensor
maintainers:
- Jonathan Cameron
-description: |
- Ambient light and proximity sensor over an i2c interface.
+description:
+ Ambient light and proximity sensor over an i2c interface. The STK36C61
+ additionally provides RGBC colour channels.
allOf:
- $ref: ../common.yaml#
@@ -26,6 +26,7 @@ properties:
- items:
- enum:
- sensortek,stk3013
+ - sensortek,stk36c61
- const: sensortek,stk3310
reg:
@@ -52,11 +53,11 @@ examples:
#size-cells = <0>;
stk3310@48 {
- compatible = "sensortek,stk3310";
- reg = <0x48>;
- proximity-near-level = <25>;
- interrupt-parent = <&gpio1>;
- interrupts = <5 IRQ_TYPE_LEVEL_LOW>;
+ compatible = "sensortek,stk3310";
+ reg = <0x48>;
+ proximity-near-level = <25>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <5 IRQ_TYPE_LEVEL_LOW>;
};
};
...
diff --git a/Documentation/devicetree/bindings/iio/light/tsl2583.yaml b/Documentation/devicetree/bindings/iio/light/tsl2583.yaml
index 7b92ba8cbb9f..aed4ab710e46 100644
--- a/Documentation/devicetree/bindings/iio/light/tsl2583.yaml
+++ b/Documentation/devicetree/bindings/iio/light/tsl2583.yaml
@@ -41,8 +41,8 @@ examples:
#size-cells = <0>;
light-sensor@29 {
- compatible = "amstaos,tsl2581";
- reg = <0x29>;
+ compatible = "amstaos,tsl2581";
+ reg = <0x29>;
};
};
...
diff --git a/Documentation/devicetree/bindings/iio/light/tsl2772.yaml b/Documentation/devicetree/bindings/iio/light/tsl2772.yaml
index 9921ccaa64a0..38a3c82cb879 100644
--- a/Documentation/devicetree/bindings/iio/light/tsl2772.yaml
+++ b/Documentation/devicetree/bindings/iio/light/tsl2772.yaml
@@ -74,13 +74,13 @@ examples:
#size-cells = <0>;
sensor@39 {
- compatible = "amstaos,tsl2772";
- reg = <0x39>;
- interrupts-extended = <&msmgpio 61 IRQ_TYPE_EDGE_FALLING>;
- vdd-supply = <&pm8941_l17>;
- vddio-supply = <&pm8941_lvs1>;
- amstaos,proximity-diodes = <0>;
- led-max-microamp = <100000>;
+ compatible = "amstaos,tsl2772";
+ reg = <0x39>;
+ interrupts-extended = <&msmgpio 61 IRQ_TYPE_EDGE_FALLING>;
+ vdd-supply = <&pm8941_l17>;
+ vddio-supply = <&pm8941_lvs1>;
+ amstaos,proximity-diodes = <0>;
+ led-max-microamp = <100000>;
};
};
...
diff --git a/Documentation/devicetree/bindings/iio/light/vishay,veml6030.yaml b/Documentation/devicetree/bindings/iio/light/vishay,veml6030.yaml
index 0041e1db6838..2eb1932f7b14 100644
--- a/Documentation/devicetree/bindings/iio/light/vishay,veml6030.yaml
+++ b/Documentation/devicetree/bindings/iio/light/vishay,veml6030.yaml
@@ -4,7 +4,8 @@
$id: http://devicetree.org/schemas/iio/light/vishay,veml6030.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
-title: VEML3235, VEML3328, VEML6030, VEML6035 and VEML7700 Ambient Light Sensors (ALS)
+title: VEML3235, VEML3328, VEML6030, VEML6031x00 series, VEML6035
+ and VEML7700 Ambient Light Sensors (ALS)
maintainers:
- Rishi Gupta
@@ -23,6 +24,8 @@ description: |
https://www.vishay.com/docs/80131/veml3235.pdf
https://www.vishay.com/docs/84968/veml3328.pdf
https://www.vishay.com/docs/84366/veml6030.pdf
+ https://www.vishay.com/docs/80007/veml6031x00.pdf
+ https://www.vishay.com/docs/80008/veml6031x01.pdf
https://www.vishay.com/docs/84889/veml6035.pdf
https://www.vishay.com/docs/84286/veml7700.pdf
@@ -32,6 +35,10 @@ properties:
- vishay,veml3235
- vishay,veml3328
- vishay,veml6030
+ - vishay,veml6031x00
+ - vishay,veml6031x01
+ - vishay,veml60311x00
+ - vishay,veml60311x01
- vishay,veml6035
- vishay,veml7700
@@ -69,6 +76,8 @@ allOf:
properties:
compatible:
enum:
+ - vishay,veml6031x00
+ - vishay,veml6031x01
- vishay,veml6035
then:
properties:
@@ -82,6 +91,8 @@ allOf:
enum:
- vishay,veml3235
- vishay,veml3328
+ - vishay,veml60311x00
+ - vishay,veml60311x01
- vishay,veml7700
then:
properties:
@@ -101,10 +112,10 @@ examples:
#size-cells = <0>;
light-sensor@10 {
- compatible = "vishay,veml6030";
- reg = <0x10>;
- interrupts = <12 IRQ_TYPE_LEVEL_LOW>;
- vdd-supply = <&vdd>;
+ compatible = "vishay,veml6030";
+ reg = <0x10>;
+ interrupts = <12 IRQ_TYPE_LEVEL_LOW>;
+ vdd-supply = <&vdd>;
};
};
...
diff --git a/Documentation/devicetree/bindings/iio/pressure/infineon,dps310.yaml b/Documentation/devicetree/bindings/iio/pressure/infineon,dps310.yaml
index e5d1e6c48939..1912a1b0b4ba 100644
--- a/Documentation/devicetree/bindings/iio/pressure/infineon,dps310.yaml
+++ b/Documentation/devicetree/bindings/iio/pressure/infineon,dps310.yaml
@@ -45,10 +45,10 @@ examples:
#size-cells = <0>;
dps: pressure-sensor@76 {
- compatible = "infineon,dps310";
- reg = <0x76>;
- #io-channel-cells = <0>;
- vdd-supply = <&vref1>;
- vddio-supply = <&vref2>;
+ compatible = "infineon,dps310";
+ reg = <0x76>;
+ #io-channel-cells = <0>;
+ vdd-supply = <&vref1>;
+ vddio-supply = <&vref2>;
};
};
diff --git a/Documentation/devicetree/bindings/iio/proximity/pulsedlight,lidar-lite-v2.yaml b/Documentation/devicetree/bindings/iio/proximity/pulsedlight,lidar-lite-v2.yaml
new file mode 100644
index 000000000000..dd739319b9eb
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/proximity/pulsedlight,lidar-lite-v2.yaml
@@ -0,0 +1,71 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/proximity/pulsedlight,lidar-lite-v2.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Pulsedlight/Garmin LIDAR-Lite range-finding sensors
+
+maintainers:
+ - Matt Ranostay
+ - Rodrigo Gobbi
+
+description: |
+ This binding covers the I2C interface of the Pulsedlight/Garmin
+ LIDAR-Lite v2 and v3 laser rangefinders.
+
+ Besides I2C, the mode control pin can also trigger acquisitions and
+ report the measured distance through a PWM signal, without using I2C
+ at all. That usage is bidirectional and non-cyclic, and is not
+ described by this binding. The same pin can also be used, while I2C
+ remains the active interface, as a plain status output signalling
+ when an acquisition has completed.
+
+ Datasheets:
+ https://static.garmin.com/pumac/LIDAR_Lite_v3_Operation_Manual_and_Technical_Specifications.pdf
+ https://github.com/PulsedLight3D/LIDAR-Lite-Documentation/blob/master/Docs/LIDAR-Lite-v2-Docs.pdf
+
+properties:
+ compatible:
+ oneOf:
+ - items:
+ - enum:
+ - grmn,lidar-lite-v3
+ - const: pulsedlight,lidar-lite-v2
+ - const: pulsedlight,lidar-lite-v2
+
+ reg:
+ maxItems: 1
+
+ powerdown-gpios:
+ description: GPIO that can be driven low to shut off power to the device.
+ maxItems: 1
+
+ vdd-supply: true
+
+ interrupts:
+ description:
+ Mode control pin used as a status output, driven while the device is
+ busy performing an acquisition. Can be used to signal completion
+ instead of polling over I2C.
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - vdd-supply
+
+additionalProperties: false
+
+examples:
+ - |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ lidar@62 {
+ compatible = "grmn,lidar-lite-v3", "pulsedlight,lidar-lite-v2";
+ reg = <0x62>;
+ vdd-supply = <&vdd_5v0>;
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/iio/proximity/vishay,vcnl3020.yaml b/Documentation/devicetree/bindings/iio/proximity/vishay,vcnl3020.yaml
index fbd3a2e32280..f84aece886ab 100644
--- a/Documentation/devicetree/bindings/iio/proximity/vishay,vcnl3020.yaml
+++ b/Documentation/devicetree/bindings/iio/proximity/vishay,vcnl3020.yaml
@@ -57,8 +57,8 @@ examples:
#size-cells = <0>;
proximity@13 {
- compatible = "vishay,vcnl3020";
- reg = <0x13>;
- vishay,led-current-microamp = <200000>;
+ compatible = "vishay,vcnl3020";
+ reg = <0x13>;
+ vishay,led-current-microamp = <200000>;
};
};
diff --git a/Documentation/devicetree/bindings/iio/temperature/adi,ltc2983.yaml b/Documentation/devicetree/bindings/iio/temperature/adi,ltc2983.yaml
index 13e5f29f0588..09b809f01550 100644
--- a/Documentation/devicetree/bindings/iio/temperature/adi,ltc2983.yaml
+++ b/Documentation/devicetree/bindings/iio/temperature/adi,ltc2983.yaml
@@ -17,6 +17,7 @@ description: |
- LTC2986
- LTM2985
+ https://www.analog.com/media/en/technical-documentation/data-sheets/adt7604.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/2983fc.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/2984fb.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/29861fa.pdf
diff --git a/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml b/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml
index 880a9f624566..4894196c8f9c 100644
--- a/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml
+++ b/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml
@@ -142,6 +142,13 @@ properties:
minItems: 2
maxItems: 4
+ spi-device-addr:
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+ description:
+ Device addresses used when multiple peripherals share a single chip
+ select. The array allows one logical peripheral to comprise multiple
+ physical devices, with one address per physical device.
+
st,spi-midi-ns:
deprecated: true
description: |
diff --git a/Documentation/devicetree/bindings/trivial-devices.yaml b/Documentation/devicetree/bindings/trivial-devices.yaml
index 2de8eb09cb7d..002543c71edf 100644
--- a/Documentation/devicetree/bindings/trivial-devices.yaml
+++ b/Documentation/devicetree/bindings/trivial-devices.yaml
@@ -62,6 +62,8 @@ properties:
# Aosong temperature & humidity sensors with I2C interface
- aosong,aht10
- aosong,aht20
+ - aosong,am2315
+ - aosong,am2320
- aosong,dht20
# Arduino microcontroller interface over SPI on UnoQ board
- arduino,unoq-mcu
@@ -77,8 +79,6 @@ properties:
- atmel,atsha204a
# BPA-RS600: Power Supply
- blutek,bpa-rs600
- # CM32181: Ambient Light Sensor
- - capella,cm32181
# CM3232: Ambient Light Sensor
- capella,cm3232
# CM3323: Ambient Light Sensor
@@ -400,8 +400,6 @@ properties:
- onnn,adt7462
# 48-Lane, 12-Port PCI Express Gen 2 (5.0 GT/s) Switch
- plx,pex8648
- # Pulsedlight LIDAR range-finding sensor
- - pulsedlight,lidar-lite-v2
# Renesas HS3001 Temperature and Relative Humidity Sensors
- renesas,hs3001
# Renesas ISL29501 time-of-flight sensor
diff --git a/Documentation/iio/ad7768.rst b/Documentation/iio/ad7768.rst
new file mode 100644
index 000000000000..9f5fbcae7173
--- /dev/null
+++ b/Documentation/iio/ad7768.rst
@@ -0,0 +1,275 @@
+.. SPDX-License-Identifier: GPL-2.0-only
+
+=============
+AD7768 driver
+=============
+
+ADC driver for Analog Devices Inc. AD7768 and AD7768-4 devices. The module name
+is ``ad7768``.
+
+Supported devices
+=================
+
+The following chips are supported by this driver:
+
+* `AD7768 `_ -
+ 8-channel, 24-bit simultaneous sampling ADC
+* `AD7768-4 `_ -
+ 4-channel, 24-bit simultaneous sampling ADC
+
+Supported features
+==================
+
+Clock sources
+-------------
+
+The master clock source is selected using the ``clock-names`` device tree
+property:
+
+* ``mclk`` selects a CMOS clock on XTAL2/MCLK. CLK_SEL must be low and XTAL1
+ must be connected to DGND.
+* ``xtal`` selects a crystal connected between XTAL1 and XTAL2. CLK_SEL must
+ be high. The driver drives FILTER/GPIO4 high and keeps channel 4 on the
+ AD7768 or channel 2 on the AD7768-4 enabled to maintain crystal excitation.
+* ``lvds`` selects a differential clock on XTAL1 and XTAL2. CLK_SEL must be
+ high. The driver drives FILTER/GPIO4 low before enabling the LVDS input.
+
+GPIO4 is reserved when ``xtal`` or ``lvds`` is selected.
+
+Power modes
+-----------
+
+The AD7768 family supports three power and performance modes:
+
+* **Low power mode** - Optimized for lowest power consumption
+* **Median mode** - Balanced power and performance
+* **Fast mode** - Highest performance with maximum sampling rates
+
+The driver initializes the device in fast mode and uses the maximum fast-mode
+output data rate as the default sampling frequency.
+
+When buffered capture starts, the driver selects the lowest-noise mode that can
+produce the requested output data rates for all enabled channels. Where output
+data rates overlap, fast mode is preferred over median mode, and median mode is
+preferred over low power mode. This prioritizes the lower RMS noise and higher
+dynamic range offered by a faster mode at the same output data rate.
+
+Data output configuration
+-------------------------
+
+The devices support flexible serial data output configurations:
+
+AD7768 data lines
+^^^^^^^^^^^^^^^^^
+
+* 1 data line (DOUT0) - Standard single-lane output
+* 2 data lines (DOUT0, DOUT1) - Dual-lane output for higher throughput
+* 8 data lines (DOUT0-DOUT7) - Maximum throughput, one line per channel
+
+AD7768-4 data lines
+^^^^^^^^^^^^^^^^^^^
+
+* 1 data line (DOUT0) - Standard single-lane output
+* 4 data lines (DOUT0-DOUT3) - Maximum throughput, one line per channel
+
+The number of data lines can be configured via the ``adi,data-lines-number``
+device tree property. If omitted, the driver uses the maximum supported by the
+selected variant: eight lines for AD7768 and four lines for AD7768-4.
+
+Channel configuration
+---------------------
+
+Each channel can be individually configured with:
+
+Channel modes
+^^^^^^^^^^^^^
+
+* **Mode A** - First set of filter and decimation settings
+* **Mode B** - Second set of filter and decimation settings
+
+The hardware provides two mode profiles (A and B), each holding one
+(frequency, filter) combination. When buffered capture is started,
+enabled channels are grouped by their configured (frequency, filter)
+pair. Up to two distinct groups are supported; the driver automatically
+assigns each group to a mode slot and programs the hardware accordingly.
+If the enabled channels request more than two distinct pairs, buffer setup
+fails and capture does not start.
+
+Precharge and reference buffers
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Per-channel buffer control for optimal signal integrity:
+
+* Positive input precharge buffer (``adi,prechargebuf-pos-enable``)
+* Negative input precharge buffer (``adi,prechargebuf-neg-enable``)
+* Positive reference buffer (``adi,refbuf-pos-enable``)
+* Negative reference buffer (``adi,refbuf-neg-enable``)
+
+Common mode voltage
+-------------------
+
+The VCM pin provides a buffered common-mode voltage output used to bias
+the analog inputs. The driver exposes this as a standard voltage regulator
+provider under a ``regulators`` subnode in the device tree. Supported
+output voltage levels are:
+
+* (AVDD1 - AVSS) / 2 - Mid-supply (hardware default), reported as half the
+ voltage provided by ``avdd1-supply``
+* 1,650,000 µV - 1.65V
+* 2,500,000 µV - 2.5V
+* 2,140,000 µV - 2.14V
+
+The regulator can be enabled and disabled at runtime using the standard
+regulator framework interfaces.
+
+The VCM circuitry is associated with channel 0. When VCM is used externally,
+``channel@0`` must be present in the device tree and channel 0 must remain
+enabled in the active scan mask. Placing channel 0 in standby disables the VCM
+output.
+
+Filter types
+------------
+
+Two digital filter types are available:
+
+* **Wideband** - Optimized for wide bandwidth applications
+* **Sinc5** - Fifth-order sinc filter for high rejection of out-of-band noise
+
+IIO backend support
+-------------------
+
+The driver integrates with IIO backends (e.g., AXI ADC) for high-speed data
+capture and DMA operations. Features include:
+
+* Automatic channel enable/disable based on scan mask
+* CRC on data interface. CRC replaces the header every 4th output sample.
+* High-throughput buffered data acquisition
+
+GPIO controller
+---------------
+
+The AD7768 includes a 5-pin GPIO controller for auxiliary digital I/O
+operations. The GPIO pins can be configured as inputs or outputs.
+
+GPIO4 is reserved when a crystal or LVDS master clock is used. GPIO0 through
+GPIO3 remain available in these configurations.
+
+Device attributes
+=================
+
+The following IIO attributes are available for each enabled channel:
+
+Voltage scale
+-------------
+
+.. list-table::
+ :header-rows: 1
+ :widths: 40 60
+
+ * - Attribute
+ - Description
+ * - ``in_voltage_scale``
+ - Scale in millivolts per least significant bit for signed 24-bit data,
+ calculated as twice the differential reference voltage used by channel
+ N divided by 2\ :sup:`24`.
+
+Sampling frequency
+------------------
+
+.. list-table::
+ :header-rows: 1
+ :widths: 40 60
+
+ * - Attribute
+ - Description
+ * - ``in_voltage_sampling_frequency``
+ - Requested sampling frequency in Hz for channel N. Enabled channels are
+ grouped into up to two profiles at capture time.
+ * - ``in_voltage_sampling_frequency_available``
+ - Available sampling frequencies in Hz for channel N across all power
+ modes, based on the master clock frequency. Buffer setup fails if no
+ single power mode supports the frequencies requested by all enabled
+ channels.
+
+Filter configuration
+---------------------
+
+.. list-table::
+ :header-rows: 1
+ :widths: 40 60
+
+ * - Attribute
+ - Description
+ * - ``in_voltage_filter_type``
+ - Requested filter type for channel N: "wideband" or "sinc5". It is
+ grouped with sampling frequency at capture time.
+ * - ``in_voltage_filter_type_available``
+ - Available filter types for channel N: "wideband sinc5".
+
+Per-channel calibration
+-----------------------
+
+.. list-table::
+ :header-rows: 1
+ :widths: 40 60
+
+ * - Attribute
+ - Description
+ * - ``in_voltage_calibbias``
+ - Signed 24-bit two's complement channel offset register value.
+ * - ``in_voltage_calibscale``
+ - Raw unsigned 24-bit channel gain register value.
+ * - ``in_voltage_convdelay``
+ - Per-channel conversion delay. The driver exposes the sync phase offset
+ value in seconds with picosecond precision. Resolution and valid range
+ depend on the decimation ratio in use (see datasheet
+ Table 32).
+
+Device buffers
+==============
+
+This driver supports IIO buffered data acquisition through IIO backends.
+When used with compatible backends like the AXI ADC, it provides:
+
+* High-speed simultaneous sampling across all enabled channels
+* Hardware-driven data capture
+* DMA-based data transfer for minimal CPU overhead
+* CRC error detection
+
+See :doc:`iio_devbuf` for more information about IIO device buffers.
+
+Example usage
+=============
+
+.. code-block:: bash
+
+ # Read current sampling frequency for channel 0
+ cat /sys/bus/iio/devices/iio:device0/in_voltage0_sampling_frequency
+
+ # Update sampling frequency for channel 0
+ echo 8000 > /sys/bus/iio/devices/iio:device0/in_voltage0_sampling_frequency
+
+ # Read current filter type for channel 0
+ cat /sys/bus/iio/devices/iio:device0/in_voltage0_filter_type
+
+ # List available filter types for channel 0
+ cat /sys/bus/iio/devices/iio:device0/in_voltage0_filter_type_available
+
+ # Update filter type for channel 0 to wideband
+ echo wideband > /sys/bus/iio/devices/iio:device0/in_voltage0_filter_type
+
+ # Buffer setup fails if enabled channels request more than two distinct
+ # (sampling frequency, filter type) combinations.
+
+ # Read calibration scale for channel 0
+ cat /sys/bus/iio/devices/iio:device0/in_voltage0_calibscale
+
+ # Read conversion delay for channel 0
+ cat /sys/bus/iio/devices/iio:device0/in_voltage0_convdelay
+
+
+Unimplemented features
+======================
+
+* CRC message every 16 samples (CRC_SEL configuration) - currently only
+ supports CRC every 4 samples
diff --git a/Documentation/iio/ad9910.rst b/Documentation/iio/ad9910.rst
new file mode 100644
index 000000000000..aab569f561db
--- /dev/null
+++ b/Documentation/iio/ad9910.rst
@@ -0,0 +1,792 @@
+.. SPDX-License-Identifier: GPL-2.0-only
+
+=============
+AD9910 driver
+=============
+
+Direct Digital Synthesizer (DDS) driver for the Analog Devices Inc. AD9910.
+The module name is ``ad9910``.
+
+* `AD9910 `_
+
+The AD9910 is a 1 GSPS DDS with a 14-bit DAC, controlled over SPI. The driver
+exposes the device through a hierarchy of typed IIO output channels. The root
+``phy`` channel controls the system clock and full-scale output current.
+Sub-channels provide independent control over single tone profiles, parallel
+port modulation, digital ramp generation (DRG), RAM playback and output shift
+keying (OSK).
+
+
+Channel hierarchy
+=================
+
+The driver exposes the following IIO output channels, each identified by a
+unique channel number and a human-readable label. The ``phy`` channel is the
+root of the hierarchy. Changing its ``sampling_frequency`` reconfigures the
+system clock (SYSCLK) which affects all other channels.
+
+.. flat-table::
+ :header-rows: 1
+
+ * - Channel
+ - Label
+ - Parent
+ - Description
+
+ * - ``out_altcurrent100``
+ - ``phy``
+ -
+ - Physical output: system clock and full-scale output current (:math:`I_{FS}`).
+ See `Physical channel`_.
+
+ * - ``out_altcurrent110`` ... ``out_altcurrent117``
+ - ``profile0`` ... ``profile7``
+ - ``phy``
+ - Single tone control: frequency, phase, amplitude, enable.
+ See `Single Tone mode`_.
+
+ * - ``out_altcurrent120``
+ - ``parallel_amplitude``
+ - ``phy``
+ - Parallel port amplitude channel.
+ See `Parallel Port mode`_.
+
+ * - ``out_phase120``
+ - ``parallel_phase``
+ - ``phy``
+ - Parallel port phase channel.
+
+ * - ``out_frequency120``
+ - ``parallel_frequency``
+ - ``phy``
+ - Parallel port frequency channel: ``scale`` sets the FM gain
+ (power-of-2 multiplier), ``offset`` sets the base FTW.
+
+ * - ``out_altcurrent121``
+ - ``parallel_polar_amplitude``
+ - ``phy``
+ - Parallel polar amplitude channel: ``scale`` is the amplitude
+ resolution, ``offset`` is the amplitude bias (lower 6 bits of ASF).
+
+ * - ``out_phase121``
+ - ``parallel_polar_phase``
+ - ``phy``
+ - Parallel polar phase channel: ``scale`` is the phase resolution,
+ ``offset`` is the phase bias (lower 8 bits of POW).
+
+ * - ``out_frequency130``
+ - ``drg_frequency``
+ - ``phy``
+ - DRG frequency channel: ``en`` selects and enables the DRG with
+ frequency as the ramp target.
+ See `Digital ramp generator (DRG)`_.
+
+ * - ``out_frequency131``
+ - ``drg_rising_frequency``
+ - ``drg_frequency``
+ - DRG frequency rising-ramp parameters: limit code, dwell enable,
+ ramp clock, rate of change.
+
+ * - ``out_frequency132``
+ - ``drg_falling_frequency``
+ - ``drg_frequency``
+ - DRG frequency falling-ramp parameters: limit code, dwell enable,
+ ramp clock, rate of change.
+
+ * - ``out_phase130``
+ - ``drg_phase``
+ - ``phy``
+ - DRG phase channel: ``en`` selects and enables the DRG with phase
+ as the ramp target.
+ See `Digital ramp generator (DRG)`_.
+
+ * - ``out_phase131``
+ - ``drg_rising_phase``
+ - ``drg_phase``
+ - DRG phase rising-ramp parameters: limit code, dwell enable, ramp clock,
+ rate of change.
+
+ * - ``out_phase132``
+ - ``drg_falling_phase``
+ - ``drg_phase``
+ - DRG phase falling-ramp parameters: limit code, dwell enable, ramp clock,
+ rate of change.
+
+ * - ``out_altcurrent130``
+ - ``drg_amplitude``
+ - ``phy``
+ - DRG amplitude channel: ``en`` selects and enables the DRG with
+ amplitude as the ramp target.
+ See `Digital ramp generator (DRG)`_.
+
+ * - ``out_altcurrent131``
+ - ``drg_rising_amplitude``
+ - ``drg_amplitude``
+ - DRG amplitude rising-ramp parameters: limit code, dwell enable,
+ ramp clock, rate of change.
+
+ * - ``out_altcurrent132``
+ - ``drg_falling_amplitude``
+ - ``drg_amplitude``
+ - DRG amplitude falling-ramp parameters: limit code, dwell enable,
+ ramp clock, rate of change.
+
+ * - ``out_altcurrent140``
+ - ``ram``
+ - ``phy``
+ - RAM playback: enable, frequency, phase and sampling frequency for
+ the active profile. See `RAM mode`_.
+
+ * - ``out_altcurrent150``
+ - ``osk``
+ - ``phy``
+ - Output shift keying (OSK): enable, amplitude code, ramp rate,
+ rate of change. See `Output Shift Keying (OSK)`_.
+
+DDS modes
+=========
+
+The AD9910 supports multiple modes of operation that can be configured
+independently or in combination. Each DDS core parameter (frequency, phase
+and amplitude) can come from different sources, but only one is active at a
+time. This activation depends on a priority list, which is based on the enable
+and destination configurations for such modes. The following tables are
+extracted from the AD9910 datasheet and summarize the control parameters for
+each mode and their priority when multiple sources are enabled simultaneously:
+
+.. flat-table:: DDS Frequency Control
+ :header-rows: 1
+
+ * - Priority
+ - Data Source
+ - Conditions
+
+ * - Highest Priority
+ - RAM
+ - RAM enabled and data destination is frequency
+
+ * -
+ - DRG
+ - DRG enabled and data destination is frequency
+
+ * -
+ - Parallel data and Frequency Tuning Word, FTW (frequency_offset)
+ - Parallel data port enabled and data destination is frequency
+
+ * -
+ - FTW register (frequency)
+ - RAM enabled and data destination is not frequency
+
+ * - Lowest Priority
+ - FTW (frequency) in single tone channel for the active profile
+ - All other cases
+
+.. flat-table:: DDS Phase Control
+ :header-rows: 1
+
+ * - Priority
+ - Data Source
+ - Conditions
+
+ * - Highest Priority
+ - RAM
+ - RAM enabled and data destination is phase or polar
+
+ * -
+ - DRG
+ - DRG enabled and data destination is phase
+
+ * -
+ - Parallel data port
+ - Parallel data port enabled and data destination is phase
+
+ * -
+ - Parallel data port and Phase Offset Word, POW register LSBs (phase_offset)
+ - Parallel data port enabled and data destination is polar
+
+ * -
+ - POW register (phase)
+ - RAM enabled and destination is not phase nor polar
+
+ * - Lowest Priority
+ - POW (phase) in single tone channel for the active profile
+ - All other cases
+
+.. flat-table:: DDS Amplitude Control
+ :header-rows: 1
+
+ * - Priority
+ - Data Source
+ - Conditions
+
+ * - Highest Priority
+ - Amplitude Scale Factor, ASF register and OSK generator
+ - OSK enabled
+
+ * -
+ - RAM
+ - RAM enabled and data destination is amplitude or polar
+
+ * -
+ - DRG
+ - DRG enabled and data destination is amplitude
+
+ * -
+ - Parallel data port
+ - Parallel data port enabled and data destination is amplitude
+
+ * -
+ - Parallel data port and ASF register LSBs (scale_offset)
+ - Parallel data port enabled and data destination is polar
+
+ * - Lowest Priority
+ - ASF (scale) in single tone channel for the active profile
+ - (Amplitude scale is already enabled by default)
+
+While debugging or testing, the debug attributes ``frequency_source``,
+``phase_source`` and ``amplitude_source`` can be used to read the label of
+the channel that is actively controlling the correspondent DDS parameter,
+which reflects the priority list described above.
+
+Single Tone mode
+----------------
+
+Single tone is the baseline operating mode. The ``profileY`` channels
+provide enable, frequency, phase and amplitude control:
+
+.. flat-table::
+ :header-rows: 1
+
+ * - Attribute
+ - Unit
+ - Description
+
+ * - ``en``
+ - boolean (0 or 1)
+ - Enable/disable profile Y. Only one profile can be active at a
+ time. When enabling a profile it disables the current active profile.
+ Disabling an active profile brings the device to a powered down state.
+
+ * - ``frequency``
+ - Hz
+ - Output frequency. Range :math:`[0, f_{SYSCLK} / 2)`. Stored in the
+ profile's frequency tuning word (FTW).
+
+ * - ``phase``
+ - rad
+ - Phase offset. Range :math:`[0, 2\pi)`. Stored in the profile's phase
+ offset word (POW).
+
+ * - ``raw``
+ - integer
+ - Amplitude scale factor code. Range :math:`[0, 16383]`. Stored in the
+ profile's amplitude scale factor (ASF) register. The physical output
+ amplitude is ``raw * scale`` where ``scale`` is read from the ``phy``
+ channel.
+
+Profile switching is allowed while RAM mode is enabled. In that case single
+tone parameters are stored in a shadow register and are not written to
+hardware until RAM mode is disabled.
+
+Usage examples
+^^^^^^^^^^^^^^
+
+Configure a 100 MHz tone in profile 2 and set it as the active profile:
+
+.. code-block:: bash
+
+ echo 100000000 > /sys/bus/iio/devices/iio\:device0/out_altcurrent112_frequency
+ echo 0 > /sys/bus/iio/devices/iio\:device0/out_altcurrent112_phase
+ echo 16383 > /sys/bus/iio/devices/iio\:device0/out_altcurrent112_raw
+
+ # Activate profile 2
+ echo 1 > /sys/bus/iio/devices/iio\:device0/out_altcurrent112_en
+
+Read back the current single tone frequency:
+
+.. code-block:: bash
+
+ cat /sys/bus/iio/devices/iio\:device0/out_altcurrent112_frequency
+
+Parallel Port mode
+------------------
+
+The parallel port allows real-time modulation of DDS parameters through a
+16-bit external data bus. The driver exposes separate typed channels for each
+modulation target.
+
+Non-polar modulation
+^^^^^^^^^^^^^^^^^^^^
+
+In non-polar mode each DDS parameter is controlled by an independent 16-bit bus
+input. The parallel port channels expose the resolution and base offset of their
+respective bus inputs:
+
+.. flat-table::
+ :header-rows: 1
+
+ * - Channel
+ - Attribute
+ - Unit
+ - Description
+
+ * - ``out_phase120``
+ - ``scale``
+ - rad
+ - Phase resolution per parallel bus LSB. Fixed at :math:`\pi / 2^{15}`
+ rad/LSB (full 16-bit POW resolution).
+
+ * - ``out_frequency120``
+ - ``scale``
+ - Hz
+ - Outputs the frequency scale evaluated as
+ :math:`f_{SYSCLK} \cdot FM / 2^{32}`. Assuming that :math:`f_{SYSCLK}` is
+ fixed, it is used to configure the modulation gain :math:`FM`, which is a
+ power-of-2 multiplier in range :math:`[1, 32768]`. Writing to this
+ attribute rounds up to the nearest :math:`FM` power of 2.
+
+ * - ``out_frequency120``
+ - ``offset``
+ - Hz
+ - Outputs the frequency offset in raw units evaluated as :math:`FTW / FM`.
+ Assuming that :math:`FM` is fixed, it is used to configure the FTW
+ register, which is a 32-bit unsigned integer.
+
+Polar modulation
+^^^^^^^^^^^^^^^^
+
+In polar mode a single 16-bit bus word carries both amplitude (high byte)
+and phase (low byte). The ``parallel_polar_amplitude`` and
+``parallel_polar_phase`` channels configure the bias applied to the low-order
+bits of the ASF and POW registers respectively:
+
+.. flat-table::
+ :header-rows: 1
+
+ * - Channel
+ - Attribute
+ - Unit
+ - Description
+
+ * - ``out_altcurrent121``
+ - ``scale``
+ - mA/LSB
+ - Full-scale amplitude resolution (read-only, fixed at :math:`I_{FS} / 2^{8}`).
+
+ * - ``out_altcurrent121``
+ - ``offset``
+ - fractional (raw units)
+ - Amplitude bias. Lower 6 bits of ASF register. Range :math:`[0, 1)`.
+
+ * - ``out_phase121``
+ - ``scale``
+ - rad/LSB
+ - Phase resolution (read-only, fixed at :math:`\pi / 2^{7}`).
+
+ * - ``out_phase121``
+ - ``offset``
+ - fractional (raw units)
+ - Phase bias. Lower 8 bits of POW register. Range :math:`[0, 1)`.
+
+Usage examples
+^^^^^^^^^^^^^^
+
+Set parallel port frequency modulation with a modulation gain of 16 and a 50 MHz
+offset:
+
+.. code-block:: bash
+
+ # f_SYSCLK = 1 GHz, FM = 16
+ # frequency scale = f_SYSCLK * FM / 2^32 = 3.725290298
+ echo 3.725290298 > /sys/bus/iio/devices/iio\:device0/out_frequency120_scale
+ # frequency offset = 50 MHz / scale = 50e6 / 13421772.8
+ echo 13421772.8 > /sys/bus/iio/devices/iio\:device0/out_frequency120_offset
+
+One should choose a frequency scale that allows all the desired frequencies
+to be represented in the 16-bit bus range, i.e.,
+:math:`scale = (f_{max} - f_{min}) / 2^{16}`.
+
+
+Digital ramp generator (DRG)
+----------------------------
+
+The DRG produces linear frequency, phase or amplitude sweeps using dedicated
+hardware. The active ramp target (destination) is selected by enabling the
+corresponding typed channel at channel number 130:
+
+- ``out_frequency130`` (label ``drg_frequency``) — ramp targets frequency
+- ``out_phase130`` (label ``drg_phase``) — ramp targets phase
+- ``out_altcurrent130`` (label ``drg_amplitude``) — ramp targets amplitude
+
+Writing ``en=1`` to one of these channels enables the DRG and switches its
+destination. Writing ``en=0`` disables the DRG if the channel is the current
+active destination; writing to an already-inactive destination is a no-op.
+
+Each destination channel also exposes a read-only ``scale`` attribute
+reporting the physical quantity per ramp register LSB, which allows converting
+raw limit codes to physical values.
+
+The six ramp channels:
+
+- ``out_frequency131`` (label ``drg_rising_frequency``)
+- ``out_frequency132`` (label ``drg_falling_frequency``)
+- ``out_phase131`` (label ``drg_rising_phase``)
+- ``out_phase132`` (label ``drg_falling_phase``)
+- ``out_altcurrent131`` (label ``drg_rising_amplitude``)
+- ``out_altcurrent132`` (label ``drg_falling_amplitude``)
+
+configure ascending and descending ramp parameters.
+
+Destination channel attributes
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. flat-table::
+ :header-rows: 1
+
+ * - Attribute
+ - Unit
+ - Description
+
+ * - ``en``
+ - boolean
+ - Enable the DRG with this channel as the active destination. Only one
+ destination can be active at a time.
+
+ * - ``scale``
+ - Hz/LSB, rad/LSB or mA/LSB
+ - Read-only. Physical quantity per raw units. Multiply a ramp
+ rising/falling channel ``raw`` value by this scale to get the physical
+ ramp target.
+
+Ramp channel attributes
+^^^^^^^^^^^^^^^^^^^^^^^
+
+.. flat-table::
+ :header-rows: 1
+
+ * - Attribute
+ - Unit
+ - Description
+
+ * - ``dwell_en``
+ - boolean
+ - Enable dwell at the ramp limit. When disabled, the ramp
+ auto-transitions at this limit without waiting for the DRCTL pin.
+ Disabling both creates a bidirectional continuous ramp (triangular
+ pattern). Other combinations create single-shot ramps at the DRCTL
+ pin transition.
+
+ * - ``raw``
+ - integer (64-bit)
+ - Ramp limit expressed as a raw DRG register code in
+ :math:`[0, 2^{32}-1]`. The physical value is ``raw * scale`` where
+ ``scale`` is read from the active destination channel.
+
+ * - ``sampling_frequency``
+ - Hz
+ - Ramp clock rate. Controlled by an integer divider; the written value
+ is adjusted to the nearest supported rate.
+
+ * - ``raw_roc``
+ - /s
+ - Rate of change. Number of register codes advanced per second, computed
+ from the hardware step size and the current ramp clock. Writing
+ requires ``sampling_frequency`` to be configured first.
+
+Usage examples
+^^^^^^^^^^^^^^
+
+Configure a frequency sweep from 40 MHz to 60 MHz with a rate of change of
+25 GHz/s:
+
+.. code-block:: bash
+
+ # Disable dwell on both limits for a bidirectional continuous ramp
+ echo 0 > /sys/bus/iio/devices/iio\:device0/out_frequency131_dwell_en
+ echo 0 > /sys/bus/iio/devices/iio\:device0/out_frequency132_dwell_en
+
+ # Set ramp rate at 250 MHz
+ echo 250000000 > /sys/bus/iio/devices/iio\:device0/out_frequency131_sampling_frequency
+ echo 250000000 > /sys/bus/iio/devices/iio\:device0/out_frequency132_sampling_frequency
+
+ # read the frequency scale to convert physical values to raw units
+ cat /sys/bus/iio/devices/iio\:device0/out_frequency130_scale
+ 0.232830643650
+
+ # 40 MHz / 0.232830643650 = 171798692
+ echo 171798692 > /sys/bus/iio/devices/iio\:device0/out_frequency131_raw
+ # 60 MHz / 0.232830643650 = 257698038
+ echo 257698038 > /sys/bus/iio/devices/iio\:device0/out_frequency132_raw
+
+ # 25 GHz/s / 0.232830643650 = 107374182402
+ echo 107374182402 > /sys/bus/iio/devices/iio\:device0/out_frequency131_raw_roc
+ echo 107374182402 > /sys/bus/iio/devices/iio\:device0/out_frequency132_raw_roc
+
+ # Enable the DRG with frequency as the destination
+ echo 1 > /sys/bus/iio/devices/iio\:device0/out_frequency130_en
+
+RAM mode
+--------
+
+The AD9910 contains a 1024 x 32-bit RAM that can be loaded with waveform data
+and played back to modulate frequency, phase, amplitude, or polar (phase +
+amplitude) parameters.
+
+RAM control channel attributes
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. flat-table::
+ :header-rows: 1
+
+ * - Attribute
+ - Unit
+ - Description
+
+ * - ``en``
+ - boolean
+ - Enable/disable RAM playback. Toggling swaps profile registers between
+ single tone and RAM configurations across all 8 profiles.
+
+ * - ``frequency``
+ - Hz
+ - Frequency tuning word used as the single tone frequency when
+ RAM destination is not ``frequency``. Range: :math:`[0, f_{SYSCLK} / 2)`.
+
+ * - ``phase``
+ - rad
+ - Phase offset word used as the single tone phase when RAM destination
+ is not ``phase``. Range: :math:`[0, 2\pi)`.
+
+ * - ``sampling_frequency``
+ - Hz
+ - RAM playback step rate of the active profile, which controls how fast
+ the address counter advances. Controlled by an integer divider; the
+ written value is adjusted to the nearest supported rate.
+
+Loading RAM data
+^^^^^^^^^^^^^^^^
+
+RAM data is loaded through the firmware upload framework. The driver registers
+a firmware upload sysfs entry named ``iio_deviceX:ram``. The firmware data
+follows a binary format (version 1) with an 80-byte header followed by data
+words. All fields are big-endian.
+
+.. flat-table:: RAM firmware header (80 bytes)
+ :header-rows: 1
+
+ * - Offset
+ - Size
+ - Field
+ - Description
+
+ * - 0
+ - 4
+ - ``magic``
+ - Magic number: ``0x00AD9910``
+
+ * - 4
+ - 2
+ - ``version``
+ - Format version: ``0x0001``
+
+ * - 6
+ - 2
+ - ``wcount``
+ - Number of 32-bit RAM data words (0--1024)
+
+ * - 8
+ - 4
+ - ``crc``
+ - CRC32 checksum over ``cfr1``, ``profiles`` and ``words``
+
+ * - 12
+ - 4
+ - ``cfr1``
+ - CFR1 register value. Only RAM-relevant bits are used:
+ bits [30:29] set data destination (00: frequency, 01: phase,
+ 10: amplitude, 11: polar); bits [20:17] set internal profile
+ control (see datasheet Table 14)
+
+ * - 16
+ - 64
+ - ``profiles[0..7]``
+ - 8 sets of 8-byte RAM profile configurations (see below)
+
+ * - 80
+ - 4 x wcount
+ - ``words[]``
+ - RAM data words in reverse order
+
+Each 8-byte profile entry contains:
+
+.. flat-table:: RAM profile entry (8 bytes)
+ :header-rows: 1
+
+ * - Bits
+ - Field
+ - Description
+
+ * - [55:40]
+ - Address step rate
+ - Controls playback speed for this profile
+
+ * - [39:30]
+ - End address
+ - Last RAM address for this profile
+
+ * - [23:14]
+ - Start address
+ - First RAM address for this profile
+
+ * - [5]
+ - No-dwell high
+ - No-dwell at high limit (ramp-up mode)
+
+ * - [3]
+ - Zero-crossing
+ - Zero-crossing enable (direct-switch mode)
+
+ * - [2:0]
+ - Operating mode
+ - 000: direct switch, 001: ramp-up, 010: bidirectional,
+ 011: bidirectional continuous, 100: ramp-up continuous
+
+Usage examples
+^^^^^^^^^^^^^^
+
+Configure RAM mode with firmware data and enable it:
+
+.. code-block:: bash
+
+ # Load RAM data via firmware upload
+ echo 1 > /sys/class/firmware/iio\:device0\:ram/loading
+ cat ad9910-ram.bin > /sys/class/firmware/iio\:device0\:ram/data
+ echo 0 > /sys/class/firmware/iio\:device0\:ram/loading
+
+ # Enable RAM mode
+ echo 1 > /sys/bus/iio/devices/iio\:device0/out_altcurrent140_en
+
+Output Shift Keying (OSK)
+-------------------------
+
+OSK controls the output amplitude envelope, allowing the output to be ramped
+on/off rather than switched abruptly.
+
+.. flat-table::
+ :header-rows: 1
+
+ * - Attribute
+ - Unit
+ - Description
+
+ * - ``en``
+ - boolean (0 or 1)
+ - Enable/disable OSK.
+
+ * - ``raw``
+ - integer
+ - Target amplitude code. 14-bit ASF field. Range: :math:`[0, 16383]`.
+ The physical output amplitude is ``raw * scale`` where ``scale`` is read
+ from the ``phy`` channel.
+
+ * - ``raw_roc``
+ - /s
+ - Amplitude ramp rate. Writing a non-zero value enables automatic OSK
+ and selects the closest hardware step size. Writing ``0`` disables
+ automatic ramping (manual control via ``raw``). Writing the maximum
+ available value enables pin-controlled immediate transition.
+
+ * - ``raw_roc_available``
+ - /s
+ - Lists the available ``raw_roc`` values based on the current
+ ``sampling_frequency``. The first value is always ``0`` (disabled) and
+ the last value corresponds to pin-controlled immediate mode.
+
+ * - ``sampling_frequency``
+ - Hz
+ - OSK ramp clock. Controlled by an integer divider; the written value
+ is adjusted to the nearest supported rate.
+
+Usage examples
+^^^^^^^^^^^^^^
+
+Enable OSK with automatic ramping:
+
+.. code-block:: bash
+
+ # Set ramp rate 1MHz
+ echo 1000000 > /sys/bus/iio/devices/iio\:device0/out_altcurrent150_sampling_frequency
+
+ # Check available rate of change values
+ cat /sys/bus/iio/devices/iio\:device0/out_altcurrent150_raw_roc_available
+ 0 1000000 2000000 4000000 8000000 16383000000
+
+ # Enable automatic OSK with a rate of change of 8000000 raw units/s
+ echo 8000000 > /sys/bus/iio/devices/iio\:device0/out_altcurrent150_raw_roc
+
+ # Enable OSK
+ echo 1 > /sys/bus/iio/devices/iio\:device0/out_altcurrent150_en
+
+Enable pin-controlled immediate OSK:
+
+.. code-block:: bash
+
+ # Enable OSK in manual mode (no ramp)
+ echo 0 > /sys/bus/iio/devices/iio\:device0/out_altcurrent150_raw_roc
+ echo 1 > /sys/bus/iio/devices/iio\:device0/out_altcurrent150_en
+
+ # Set target amplitude to full scale
+ echo 16383 > /sys/bus/iio/devices/iio\:device0/out_altcurrent150_raw
+
+Physical channel
+================
+
+The ``phy`` channel provides device-level control:
+
+.. flat-table::
+ :header-rows: 1
+
+ * - Attribute
+ - Unit
+ - Description
+
+ * - ``sampling_frequency``
+ - Hz
+ - System clock (SYSCLK) frequency. When the internal PLL is enabled
+ (via the ``adi,pll-enable`` devicetree property), configures the PLL
+ multiplier (Range: :math:`[420, 1000]` MHz). Without PLL, the reference
+ clock can only be divided by 2.
+
+ * - ``scale``
+ - mA/LSB
+ - Full-scale DAC output current per amplitude code LSB, which is evaluated
+ as :math:`I_{FS} / 2^{14}`. Shared across all ``altcurrent`` channels.
+ Setting this attribute reconfigures the auxiliary DAC full-scale code and
+ updates the effective amplitude resolution for single tone profiles,
+ DRG amplitude ramps and OSK.
+
+ * - ``powerdown``
+ - boolean (0 or 1)
+ - Software power-down. Writing 1 powers down the digital core, DAC,
+ reference clock input and auxiliary DAC simultaneously.
+
+Usage examples
+--------------
+
+Set the system clock to 1 GHz:
+
+.. code-block:: bash
+
+ echo 1000000000 > /sys/bus/iio/devices/iio\:device0/out_altcurrent100_sampling_frequency
+
+Read current system clock frequency:
+
+.. code-block:: bash
+
+ cat /sys/bus/iio/devices/iio\:device0/out_altcurrent100_sampling_frequency
+
+Power down the device:
+
+.. code-block:: bash
+
+ echo 1 > /sys/bus/iio/devices/iio\:device0/out_altcurrent100_powerdown
diff --git a/Documentation/iio/ade9000.rst b/Documentation/iio/ade9000.rst
index c9ff702a4251..f41660005223 100644
--- a/Documentation/iio/ade9000.rst
+++ b/Documentation/iio/ade9000.rst
@@ -1,24 +1,30 @@
.. SPDX-License-Identifier: GPL-2.0
-===============
-ADE9000 driver
-===============
+======================
+ADE9000/ADE9078 driver
+======================
-This driver supports Analog Device's ADE9000 energy measurement IC on SPI bus.
+This driver supports Analog Devices' ADE9000 and ADE9078 energy measurement
+ICs on SPI bus.
1. Supported devices
====================
* `ADE9000 `_
+* `ADE9078 `_
-The ADE9000 is a highly accurate, fully integrated, multiphase energy and power
-quality monitoring device. Superior analog performance and a digital signal
-processing (DSP) core enable accurate energy monitoring over a wide dynamic
-range. An integrated high end reference ensures low drift over temperature
-with a combined drift of less than ±25 ppm/°C maximum for the entire channel
-including a programmable gain amplifier (PGA) and an analog-to-digital
+The ADE9000 and ADE9078 are highly accurate, fully integrated, multiphase energy
+and power quality monitoring devices. Superior analog performance and a digital
+signal processing (DSP) core enable accurate energy monitoring over a wide
+dynamic range. An integrated high end reference ensures low drift over
+temperature with a combined drift of less than ±25 ppm/°C maximum for the entire
+channel including a programmable gain amplifier (PGA) and an analog-to-digital
converter (ADC).
+The ADE9078 does not provide the on-chip dip/swell (sag) detection available on
+the ADE9000, so the RMS voltage swell/dip events described below are only
+available on the ADE9000.
+
2. Device attributes
====================
diff --git a/Documentation/iio/adis16475.rst b/Documentation/iio/adis16475.rst
index 89a388490ab7..0e004f016199 100644
--- a/Documentation/iio/adis16475.rst
+++ b/Documentation/iio/adis16475.rst
@@ -4,7 +4,7 @@
ADIS16475 driver
================
-This driver supports Analog Device's IMUs on SPI bus.
+This driver supports Analog Devices' IMUs on SPI bus.
1. Supported devices
====================
diff --git a/Documentation/iio/adis16480.rst b/Documentation/iio/adis16480.rst
index cce5f3e01741..7c259070aaaf 100644
--- a/Documentation/iio/adis16480.rst
+++ b/Documentation/iio/adis16480.rst
@@ -4,7 +4,7 @@
ADIS16480 driver
================
-This driver supports Analog Device's IMUs on SPI bus.
+This driver supports Analog Devices' IMUs on SPI bus.
1. Supported devices
====================
diff --git a/Documentation/iio/adis16550.rst b/Documentation/iio/adis16550.rst
index c9bbc0a857b0..c0d5a975e6ca 100644
--- a/Documentation/iio/adis16550.rst
+++ b/Documentation/iio/adis16550.rst
@@ -4,7 +4,7 @@
ADIS16550 driver
================
-This driver supports Analog Device's IMUs on SPI bus.
+This driver supports Analog Devices' IMUs on SPI bus.
1. Supported devices
====================
diff --git a/Documentation/iio/adxl313.rst b/Documentation/iio/adxl313.rst
index 3641193bf647..c448f10745e7 100644
--- a/Documentation/iio/adxl313.rst
+++ b/Documentation/iio/adxl313.rst
@@ -4,7 +4,7 @@
ADXL313 driver
===============
-This driver supports Analog Device's ADXL313 on SPI/I2C bus.
+This driver supports Analog Devices' ADXL313 on SPI/I2C bus.
1. Supported devices
====================
diff --git a/Documentation/iio/adxl345.rst b/Documentation/iio/adxl345.rst
index 0aa33a852412..28c71fbd45e5 100644
--- a/Documentation/iio/adxl345.rst
+++ b/Documentation/iio/adxl345.rst
@@ -4,7 +4,7 @@
ADXL345 driver
===============
-This driver supports Analog Device's ADXL345/375 on SPI/I2C bus.
+This driver supports Analog Devices' ADXL345/375 on SPI/I2C bus.
1. Supported Devices
====================
diff --git a/Documentation/iio/adxl380.rst b/Documentation/iio/adxl380.rst
index 654d4c0e84a1..969ded211cc9 100644
--- a/Documentation/iio/adxl380.rst
+++ b/Documentation/iio/adxl380.rst
@@ -4,7 +4,7 @@
ADXL380 driver
===============
-This driver supports Analog Device's ADXL380/382 on SPI/I2C bus.
+This driver supports Analog Devices' ADXL380/382 on SPI/I2C bus.
1. Supported devices
====================
@@ -39,13 +39,13 @@ specific device folder path ``/sys/bus/iio/devices/iio:deviceX``.
+---------------------------------------------------+----------------------------------------------------------+
| in_accel_scale | Scale for the accelerometer channels. |
+---------------------------------------------------+----------------------------------------------------------+
-| in_accel_filter_high_pass_3db_frequency | Low pass filter bandwidth. |
+| in_accel_filter_high_pass_3db_frequency | High pass filter bandwidth. |
+---------------------------------------------------+----------------------------------------------------------+
-| in_accel_filter_high_pass_3db_frequency_available | Available low pass filter bandwidth configurations. |
+| in_accel_filter_high_pass_3db_frequency_available | Available high pass filter bandwidth configurations. |
+---------------------------------------------------+----------------------------------------------------------+
-| in_accel_filter_low_pass_3db_frequency | High pass filter bandwidth. |
+| in_accel_filter_low_pass_3db_frequency | Low pass filter bandwidth. |
+---------------------------------------------------+----------------------------------------------------------+
-| in_accel_filter_low_pass_3db_frequency_available | Available high pass filter bandwidth configurations. |
+| in_accel_filter_low_pass_3db_frequency_available | Available low pass filter bandwidth configurations. |
+---------------------------------------------------+----------------------------------------------------------+
| in_accel_x_calibbias | Calibration offset for the X-axis accelerometer channel. |
+---------------------------------------------------+----------------------------------------------------------+
diff --git a/Documentation/iio/index.rst b/Documentation/iio/index.rst
index b02b879b053a..d0fb32f4b80f 100644
--- a/Documentation/iio/index.rst
+++ b/Documentation/iio/index.rst
@@ -29,7 +29,9 @@ Industrial I/O Kernel Drivers
ad7380
ad7606
ad7625
+ ad7768
ad7944
+ ad9910
ade9000
adf41513
adis16475
diff --git a/MAINTAINERS b/MAINTAINERS
index 72294ddfa5b7..3cef938702da 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -640,6 +640,7 @@ F: drivers/iio/accel/adxl355_spi.c
ADXL367 THREE-AXIS DIGITAL ACCELEROMETER DRIVER
M: Marcelo Schmitt
+M: Antoniu Miclaus
L: linux-iio@vger.kernel.org
S: Supported
W: https://ez.analog.com/linux-software-drivers
@@ -1468,6 +1469,7 @@ L: linux-iio@vger.kernel.org
S: Supported
W: https://ez.analog.com/linux-software-drivers
F: Documentation/devicetree/bindings/iio/dac/adi,ad3530r.yaml
+F: Documentation/devicetree/bindings/iio/dac/adi,ad5710r.yaml
F: drivers/iio/dac/ad3530r.c
ANALOG DEVICES INC AD3552R DRIVER
@@ -1517,6 +1519,7 @@ F: drivers/iio/adc/ad4080.c
ANALOG DEVICES INC AD4130 DRIVER
M: Marcelo Schmitt
+M: Antoniu Miclaus
L: linux-iio@vger.kernel.org
S: Supported
W: https://ez.analog.com/linux-software-drivers
@@ -1571,6 +1574,14 @@ W: https://ez.analog.com/linux-software-drivers
F: Documentation/devicetree/bindings/iio/adc/adi,ad4851.yaml
F: drivers/iio/adc/ad4851.c
+ANALOG DEVICES INC AD5529R DRIVER
+M: Janani Sunil
+L: linux-iio@vger.kernel.org
+S: Supported
+W: https://ez.analog.com/linux-software-drivers
+F: Documentation/devicetree/bindings/iio/dac/adi,ad5529r.yaml
+F: drivers/iio/dac/ad5529r.c
+
ANALOG DEVICES INC AD5706R DRIVER
M: Alexis Czezar Torreno
L: linux-iio@vger.kernel.org
@@ -1622,6 +1633,7 @@ F: drivers/iio/dac/ad7293.c
ANALOG DEVICES INC AD74115 DRIVER
M: Marcelo Schmitt
+M: Antoniu Miclaus
L: linux-iio@vger.kernel.org
S: Supported
W: https://ez.analog.com/linux-software-drivers
@@ -1630,6 +1642,7 @@ F: drivers/iio/addac/ad74115.c
ANALOG DEVICES INC AD74413R DRIVER
M: Marcelo Schmitt
+M: Antoniu Miclaus
L: linux-iio@vger.kernel.org
S: Supported
W: https://ez.analog.com/linux-software-drivers
@@ -1657,6 +1670,15 @@ F: Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.yaml
F: drivers/iio/adc/ad7768-1.c
F: include/dt-bindings/iio/adc/adi,ad7768-1.h
+ANALOG DEVICES INC AD7768 DRIVER
+M: Janani Sunil
+L: linux-iio@vger.kernel.org
+S: Supported
+W: https://ez.analog.com/linux-software-drivers
+F: Documentation/devicetree/bindings/iio/adc/adi,ad7768.yaml
+F: Documentation/iio/ad7768.rst
+F: drivers/iio/adc/ad7768.c
+
ANALOG DEVICES INC AD7780 DRIVER
M: Michael Hennerich
M: Renato Lui Geh
@@ -1702,6 +1724,17 @@ W: https://ez.analog.com/linux-software-drivers
F: Documentation/devicetree/bindings/iio/dac/adi,ad9739a.yaml
F: drivers/iio/dac/ad9739a.c
+ANALOG DEVICES INC AD9910 DRIVER
+M: Rodrigo Alencar
+L: linux-iio@vger.kernel.org
+S: Supported
+W: https://ez.analog.com/linux-software-drivers
+F: Documentation/ABI/testing/debugfs-iio-ad9910
+F: Documentation/ABI/testing/sysfs-bus-iio-frequency-ad9910
+F: Documentation/devicetree/bindings/iio/frequency/adi,ad9910.yaml
+F: Documentation/iio/ad9910.rst
+F: drivers/iio/frequency/ad9910.c
+
ANALOG DEVICES INC MAX22007 DRIVER
M: Janani Sunil
L: linux-iio@vger.kernel.org
@@ -4439,6 +4472,15 @@ S: Orphan
F: Documentation/devicetree/bindings/sound/axentia,*
F: sound/soc/atmel/tse850-pcm5142.c
+AXIADO SARADC DRIVER
+M: Petar Stepanovic
+M: Akhila Kavi
+M: Prasad Bolisetty
+L: linux-iio@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/iio/adc/axiado,ax3000-saradc.yaml
+F: drivers/iio/adc/axiado_saradc.c
+
AXIS ARTPEC ARM64 SoC SUPPORT
M: Jesper Nilsson
M: Lars Persson
@@ -12697,6 +12739,7 @@ R: Nuno Sá
R: Andy Shevchenko
L: linux-iio@vger.kernel.org
S: Maintained
+Q: https://patchwork.kernel.org/project/linux-iio/list/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git
F: Documentation/ABI/testing/configfs-iio*
F: Documentation/ABI/testing/sysfs-bus-iio*
@@ -12709,6 +12752,13 @@ F: include/dt-bindings/iio/
F: include/linux/iio/
F: tools/iio/
+IIO CORE KUNIT TESTS
+M: Rodrigo Alencar
+L: linux-iio@vger.kernel.org
+S: Maintained
+F: drivers/iio/test/iio-test-channel-prefix.c
+F: drivers/iio/test/iio-test-format.c
+
IIO UNIT CONVERTER
M: Peter Rosin
L: linux-iio@vger.kernel.org
@@ -16123,6 +16173,15 @@ L: linux-iio@vger.kernel.org
S: Supported
F: drivers/iio/temperature/max30208.c
+MAXIM MAX40080 CURRENT SENSE AMPLIFIER DRIVER
+M: Ciprian Hegbeli
+M: Stefan Popa
+L: linux-iio@vger.kernel.org
+S: Supported
+W: https://ez.analog.com/linux-software-drivers
+F: Documentation/devicetree/bindings/iio/adc/adi,max40080.yaml
+F: drivers/iio/adc/max40080.c
+
MAXIM MAX7360 KEYPAD LED MFD DRIVER
M: Mathieu Dubois-Briand
S: Maintained
@@ -16294,7 +16353,7 @@ M: Ariana Lazar
L: linux-iio@vger.kernel.org
S: Supported
F: Documentation/devicetree/bindings/iio/dac/microchip,mcp47feb02.yaml
-F: drivers/iio/dac/mcp47feb02.c
+F: drivers/iio/dac/mcp47feb02*
MCP4821 DAC DRIVER
M: Anshul Dalal
@@ -27241,6 +27300,13 @@ S: Maintained
F: Documentation/devicetree/bindings/iio/adc/ti,ads1119.yaml
F: drivers/iio/adc/ti-ads1119.c
+TI ADS112C04 ADC DRIVER
+M: Kyle Hsieh
+L: linux-iio@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/iio/adc/ti,ads112c04.yaml
+F: drivers/iio/adc/ti-ads112c04.c
+
TI ADS112C14 ADC DRIVER
M: David Lechner
L: linux-iio@vger.kernel.org
@@ -29098,6 +29164,12 @@ S: Maintained
F: Documentation/devicetree/bindings/iio/light/vishay,veml6030.yaml
F: drivers/iio/light/veml6030.c
+VISHAY VEML6031X00 AMBIENT LIGHT SENSOR DRIVER
+M: Javier Carrasco
+S: Maintained
+F: Documentation/devicetree/bindings/iio/light/vishay,veml6030.yaml
+F: drivers/iio/light/veml6031x00.c
+
VISHAY VEML6046X00 RGBIR COLOR SENSOR DRIVER
M: Andreas Klinger
S: Maintained
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index 4094299e2ed8..141ac984247c 100644
--- a/drivers/iio/accel/Kconfig
+++ b/drivers/iio/accel/Kconfig
@@ -7,13 +7,14 @@
menu "Accelerometers"
config ADIS16201
- tristate "Analog Devices ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer"
+ tristate "ADIS16201 Digital Inclinometer and similar"
depends on SPI
select IIO_ADIS_LIB
select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
help
- Say Y here to build support for Analog Devices adis16201 dual-axis
- digital inclinometer and accelerometer.
+ Say Y here to build support for Analog Devices Digital Inclinometers:
+ - ADIS16201
+ - ADIS16203
To compile this driver as a module, say M here: the module will
be called adis16201.
diff --git a/drivers/iio/accel/adis16201.c b/drivers/iio/accel/adis16201.c
index ba0f97944c6d..6d5a7b696112 100644
--- a/drivers/iio/accel/adis16201.c
+++ b/drivers/iio/accel/adis16201.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer
+ * ADIS16201 Digital Inclinometer and similar
*
* Copyright 2010 Analog Devices Inc.
*/
@@ -63,6 +63,7 @@
#define ADIS16201_DIAG_STAT_REG 0x3C
#define ADIS16201_DIAG_STAT_ALARM2 BIT(9)
#define ADIS16201_DIAG_STAT_ALARM1 BIT(8)
+#define ADIS16203_DIAG_STAT_SELFTEST_FAIL_BIT 5
#define ADIS16201_DIAG_STAT_SPI_FAIL_BIT 3
#define ADIS16201_DIAG_STAT_FLASH_UPT_FAIL_BIT 2
/* Power supply above 3.625 V */
@@ -87,6 +88,21 @@ enum adis16201_scan {
ADIS16201_SCAN_TEMP,
};
+struct adis16201_chip_info {
+ const char *name;
+ const struct iio_chan_spec *arr_channels;
+ const struct adis_data *data;
+ unsigned int incli_scale_val2;
+ unsigned int read_bits_incli;
+ unsigned int num_channels;
+ u16 write_mask_incli;
+};
+
+struct adis16201_state {
+ struct adis adis;
+ const struct adis16201_chip_info *info;
+};
+
static const u8 adis16201_addresses[] = {
[ADIS16201_SCAN_ACC_X] = ADIS16201_XACCL_OFFS_REG,
[ADIS16201_SCAN_ACC_Y] = ADIS16201_YACCL_OFFS_REG,
@@ -99,7 +115,7 @@ static int adis16201_read_raw(struct iio_dev *indio_dev,
int *val, int *val2,
long mask)
{
- struct adis *st = iio_priv(indio_dev);
+ struct adis16201_state *st = iio_priv(indio_dev);
int ret;
int bits;
u8 addr;
@@ -137,7 +153,7 @@ static int adis16201_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT_PLUS_NANO;
case IIO_INCLI:
*val = 0;
- *val2 = 100000;
+ *val2 = st->info->incli_scale_val2;
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
@@ -157,13 +173,13 @@ static int adis16201_read_raw(struct iio_dev *indio_dev,
bits = 12;
break;
case IIO_INCLI:
- bits = 9;
+ bits = st->info->read_bits_incli;
break;
default:
return -EINVAL;
}
addr = adis16201_addresses[chan->scan_index];
- ret = adis_read_reg_16(st, addr, &val16);
+ ret = adis_read_reg_16(&st->adis, addr, &val16);
if (ret)
return ret;
@@ -180,41 +196,49 @@ static int adis16201_write_raw(struct iio_dev *indio_dev,
int val2,
long mask)
{
- struct adis *st = iio_priv(indio_dev);
- int m;
+ struct adis16201_state *st = iio_priv(indio_dev);
if (mask != IIO_CHAN_INFO_CALIBBIAS)
return -EINVAL;
switch (chan->type) {
case IIO_ACCEL:
- m = GENMASK(11, 0);
+ val &= GENMASK(11, 0);
break;
case IIO_INCLI:
- m = GENMASK(8, 0);
+ val &= st->info->write_mask_incli;
break;
default:
return -EINVAL;
}
- return adis_write_reg_16(st, adis16201_addresses[chan->scan_index],
- val & m);
+ return adis_write_reg_16(&st->adis, adis16201_addresses[chan->scan_index],
+ val);
}
static const struct iio_chan_spec adis16201_channels[] = {
- ADIS_SUPPLY_CHAN(ADIS16201_SUPPLY_OUT_REG, ADIS16201_SCAN_SUPPLY, 0,
- 12),
- ADIS_TEMP_CHAN(ADIS16201_TEMP_OUT_REG, ADIS16201_SCAN_TEMP, 0, 12),
ADIS_ACCEL_CHAN(X, ADIS16201_XACCL_OUT_REG, ADIS16201_SCAN_ACC_X,
BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14),
ADIS_ACCEL_CHAN(Y, ADIS16201_YACCL_OUT_REG, ADIS16201_SCAN_ACC_Y,
BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14),
- ADIS_AUX_ADC_CHAN(ADIS16201_AUX_ADC_REG, ADIS16201_SCAN_AUX_ADC, 0, 12),
ADIS_INCLI_CHAN(X, ADIS16201_XINCL_OUT_REG, ADIS16201_SCAN_INCLI_X,
BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 12),
ADIS_INCLI_CHAN(Y, ADIS16201_YINCL_OUT_REG, ADIS16201_SCAN_INCLI_Y,
BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 12),
- IIO_CHAN_SOFT_TIMESTAMP(7)
+ ADIS_SUPPLY_CHAN(ADIS16201_SUPPLY_OUT_REG, ADIS16201_SCAN_SUPPLY, 0,
+ 12),
+ ADIS_AUX_ADC_CHAN(ADIS16201_AUX_ADC_REG, ADIS16201_SCAN_AUX_ADC, 0, 12),
+ ADIS_TEMP_CHAN(ADIS16201_TEMP_OUT_REG, ADIS16201_SCAN_TEMP, 0, 12),
+ IIO_CHAN_SOFT_TIMESTAMP(7),
+};
+
+static const struct iio_chan_spec adis16203_channels[] = {
+ ADIS_INCLI_CHAN(X, ADIS16201_XINCL_OUT_REG, ADIS16201_SCAN_INCLI_X,
+ BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14),
+ ADIS_SUPPLY_CHAN(ADIS16201_SUPPLY_OUT_REG, ADIS16201_SCAN_SUPPLY, 0, 12),
+ ADIS_AUX_ADC_CHAN(ADIS16201_AUX_ADC_REG, ADIS16201_SCAN_AUX_ADC, 0, 12),
+ ADIS_TEMP_CHAN(ADIS16201_TEMP_OUT_REG, ADIS16201_SCAN_TEMP, 0, 12),
+ IIO_CHAN_SOFT_TIMESTAMP(7),
};
static const struct iio_info adis16201_info = {
@@ -224,6 +248,7 @@ static const struct iio_info adis16201_info = {
};
static const char * const adis16201_status_error_msgs[] = {
+ [ADIS16203_DIAG_STAT_SELFTEST_FAIL_BIT] = "Self test failure",
[ADIS16201_DIAG_STAT_SPI_FAIL_BIT] = "SPI failure",
[ADIS16201_DIAG_STAT_FLASH_UPT_FAIL_BIT] = "Flash update failed",
[ADIS16201_DIAG_STAT_POWER_HIGH_BIT] = "Power supply above 3.625V",
@@ -254,10 +279,49 @@ static const struct adis_data adis16201_data = {
BIT(ADIS16201_DIAG_STAT_POWER_LOW_BIT),
};
+static const struct adis_data adis16203_data = {
+ .read_delay = 20,
+ .msc_ctrl_reg = ADIS16201_MSC_CTRL_REG,
+ .glob_cmd_reg = ADIS16201_GLOB_CMD_REG,
+ .diag_stat_reg = ADIS16201_DIAG_STAT_REG,
+
+ .self_test_mask = ADIS16201_MSC_CTRL_SELF_TEST_EN,
+ .self_test_reg = ADIS16201_MSC_CTRL_REG,
+ .self_test_no_autoclear = true,
+ .timeouts = &adis16201_timeouts,
+
+ .status_error_msgs = adis16201_status_error_msgs,
+ .status_error_mask = BIT(ADIS16203_DIAG_STAT_SELFTEST_FAIL_BIT) |
+ BIT(ADIS16201_DIAG_STAT_SPI_FAIL_BIT) |
+ BIT(ADIS16201_DIAG_STAT_FLASH_UPT_FAIL_BIT) |
+ BIT(ADIS16201_DIAG_STAT_POWER_HIGH_BIT) |
+ BIT(ADIS16201_DIAG_STAT_POWER_LOW_BIT),
+};
+
+static const struct adis16201_chip_info adis16201_chip_data = {
+ .arr_channels = adis16201_channels,
+ .incli_scale_val2 = 100000,
+ .write_mask_incli = GENMASK(8, 0),
+ .read_bits_incli = 9,
+ .num_channels = ARRAY_SIZE(adis16201_channels),
+ .name = "adis16201",
+ .data = &adis16201_data,
+};
+
+static const struct adis16201_chip_info adis16203_chip_data = {
+ .arr_channels = adis16203_channels,
+ .incli_scale_val2 = 25000,
+ .write_mask_incli = GENMASK(13, 0),
+ .read_bits_incli = 14,
+ .num_channels = ARRAY_SIZE(adis16203_channels),
+ .name = "adis16203",
+ .data = &adis16203_data,
+};
+
static int adis16201_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
- struct adis *st;
+ struct adis16201_state *st;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
@@ -266,38 +330,57 @@ static int adis16201_probe(struct spi_device *spi)
st = iio_priv(indio_dev);
- indio_dev->name = spi->dev.driver->name;
+ st->info = spi_get_device_match_data(spi);
+ if (!st->info)
+ return -ENODATA;
+
+ indio_dev->name = st->info->name;
indio_dev->info = &adis16201_info;
- indio_dev->channels = adis16201_channels;
- indio_dev->num_channels = ARRAY_SIZE(adis16201_channels);
+ indio_dev->channels = st->info->arr_channels;
+ indio_dev->num_channels = st->info->num_channels;
indio_dev->modes = INDIO_DIRECT_MODE;
- ret = adis_init(st, indio_dev, spi, &adis16201_data);
+ ret = adis_init(&st->adis, indio_dev, spi, st->info->data);
if (ret)
return ret;
- ret = devm_adis_setup_buffer_and_trigger(st, indio_dev, NULL);
+ ret = devm_adis_setup_buffer_and_trigger(&st->adis, indio_dev, NULL);
if (ret)
return ret;
- ret = __adis_initial_startup(st);
+ ret = __adis_initial_startup(&st->adis);
if (ret)
return ret;
return devm_iio_device_register(&spi->dev, indio_dev);
}
+static const struct of_device_id adis16201_of_match[] = {
+ { .compatible = "adi,adis16201", .data = &adis16201_chip_data },
+ { .compatible = "adi,adis16203", .data = &adis16203_chip_data },
+ { }
+};
+MODULE_DEVICE_TABLE(of, adis16201_of_match);
+
+static const struct spi_device_id adis16201_ids[] = {
+ { .name = "adis16201", .driver_data = (kernel_ulong_t)&adis16201_chip_data },
+ { .name = "adis16203", .driver_data = (kernel_ulong_t)&adis16203_chip_data },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, adis16201_ids);
+
static struct spi_driver adis16201_driver = {
.driver = {
.name = "adis16201",
+ .of_match_table = adis16201_of_match,
},
.probe = adis16201_probe,
+ .id_table = adis16201_ids,
};
module_spi_driver(adis16201_driver);
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
-MODULE_DESCRIPTION("Analog Devices ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer");
+MODULE_DESCRIPTION("Analog Devices ADIS16201 Inclinometer and similar");
MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("spi:adis16201");
MODULE_IMPORT_NS("IIO_ADISLIB");
diff --git a/drivers/iio/accel/adxl313_spi.c b/drivers/iio/accel/adxl313_spi.c
index a61295de104f..0f0da44461f7 100644
--- a/drivers/iio/accel/adxl313_spi.c
+++ b/drivers/iio/accel/adxl313_spi.c
@@ -79,6 +79,8 @@ static int adxl313_spi_probe(struct spi_device *spi)
return ret;
chip_data = spi_get_device_match_data(spi);
+ if (!chip_data)
+ return -ENODATA;
regmap = devm_regmap_init_spi(spi,
&adxl31x_spi_regmap_config[chip_data->type]);
diff --git a/drivers/iio/accel/adxl367.c b/drivers/iio/accel/adxl367.c
index 4ff1c7a0988b..026db73057c5 100644
--- a/drivers/iio/accel/adxl367.c
+++ b/drivers/iio/accel/adxl367.c
@@ -13,6 +13,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -81,6 +82,7 @@
#define ADXL367_SAMPLES_L_MASK GENMASK(7, 0)
#define ADXL367_REG_INT1_MAP 0x2A
+#define ADXL367_REG_INT2_MAP 0x2B
#define ADXL367_INT_INACT_MASK BIT(5)
#define ADXL367_INT_ACT_MASK BIT(4)
#define ADXL367_INT_FIFO_WATERMARK_MASK BIT(2)
@@ -168,6 +170,8 @@ struct adxl367_state {
enum adxl367_odr odr;
enum adxl367_range range;
+ u8 int_map_reg;
+
unsigned int act_threshold;
unsigned int act_time_ms;
unsigned int inact_threshold;
@@ -366,8 +370,7 @@ static int adxl367_set_act_interrupt_en(struct adxl367_state *st,
{
unsigned int mask = adxl367_act_int_mask_tbl[act];
- return regmap_update_bits(st->regmap, ADXL367_REG_INT1_MAP,
- mask, en ? mask : 0);
+ return regmap_assign_bits(st->regmap, st->int_map_reg, mask, en);
}
static int adxl367_get_act_interrupt_en(struct adxl367_state *st,
@@ -378,7 +381,7 @@ static int adxl367_get_act_interrupt_en(struct adxl367_state *st,
unsigned int val;
int ret;
- ret = regmap_read(st->regmap, ADXL367_REG_INT1_MAP, &val);
+ ret = regmap_read(st->regmap, st->int_map_reg, &val);
if (ret)
return ret;
@@ -401,9 +404,8 @@ static int adxl367_set_act_en(struct adxl367_state *st,
static int adxl367_set_fifo_watermark_interrupt_en(struct adxl367_state *st,
bool en)
{
- return regmap_update_bits(st->regmap, ADXL367_REG_INT1_MAP,
- ADXL367_INT_FIFO_WATERMARK_MASK,
- en ? ADXL367_INT_FIFO_WATERMARK_MASK : 0);
+ return regmap_assign_bits(st->regmap, st->int_map_reg,
+ ADXL367_INT_FIFO_WATERMARK_MASK, en);
}
static int adxl367_get_fifo_mode(struct adxl367_state *st,
@@ -631,8 +633,7 @@ static int adxl367_set_odr(struct iio_dev *indio_dev, enum adxl367_odr odr)
static int adxl367_set_temp_adc_en(struct adxl367_state *st, unsigned int reg,
bool en)
{
- return regmap_update_bits(st->regmap, reg, ADXL367_ADC_EN_MASK,
- en ? ADXL367_ADC_EN_MASK : 0);
+ return regmap_assign_bits(st->regmap, reg, ADXL367_ADC_EN_MASK, en);
}
static int adxl367_set_temp_adc_reg_en(struct adxl367_state *st,
@@ -787,6 +788,13 @@ static bool adxl367_push_fifo_data(struct iio_dev *indio_dev, u8 status,
if (!FIELD_GET(ADXL367_STATUS_FIFO_FULL_MASK, status))
return false;
+ if (fifo_entries > ADXL367_FIFO_SIZE) {
+ dev_err_ratelimited(st->dev,
+ "FIFO entry count %u exceeds FIFO size %u\n",
+ fifo_entries, ADXL367_FIFO_SIZE);
+ return true;
+ }
+
fifo_entries -= fifo_entries % st->fifo_set_size;
ret = st->ops->read_fifo(st->context, st->fifo_buf, fifo_entries);
@@ -1426,6 +1434,36 @@ static int adxl367_setup(struct adxl367_state *st)
return adxl367_set_measure_en(st, true);
}
+static int adxl367_set_int_map_reg(struct adxl367_state *st, int irq)
+{
+ int ret;
+
+ /*
+ * Route the mappings to whichever of INT1/INT2 is named in the
+ * interrupt-names property. -EINVAL (property absent) and -ENODATA
+ * (name not listed) are not errors; anything else is.
+ */
+ ret = fwnode_irq_get_byname(dev_fwnode(st->dev), "INT1");
+ if (ret > 0) {
+ st->int_map_reg = ADXL367_REG_INT1_MAP;
+ return ret;
+ }
+ if (ret != -ENODATA && ret != -EINVAL)
+ return ret;
+
+ ret = fwnode_irq_get_byname(dev_fwnode(st->dev), "INT2");
+ if (ret > 0) {
+ st->int_map_reg = ADXL367_REG_INT2_MAP;
+ return ret;
+ }
+ if (ret != -ENODATA && ret != -EINVAL)
+ return ret;
+
+ /* No INT1/INT2 named: default to INT1 and the bus interrupt. */
+ st->int_map_reg = ADXL367_REG_INT1_MAP;
+ return irq;
+}
+
int adxl367_probe(struct device *dev, const struct adxl367_ops *ops,
void *context, struct regmap *regmap, int irq)
{
@@ -1455,6 +1493,11 @@ int adxl367_probe(struct device *dev, const struct adxl367_ops *ops,
indio_dev->info = &adxl367_info;
indio_dev->modes = INDIO_DIRECT_MODE;
+ ret = adxl367_set_int_map_reg(st, irq);
+ if (ret < 0)
+ return dev_err_probe(st->dev, ret, "Failed to get interrupt\n");
+ irq = ret;
+
ret = devm_regulator_bulk_get_enable(st->dev,
ARRAY_SIZE(regulator_names),
regulator_names);
diff --git a/drivers/iio/accel/adxl372_spi.c b/drivers/iio/accel/adxl372_spi.c
index 128e148c4e96..d54544d6df6f 100644
--- a/drivers/iio/accel/adxl372_spi.c
+++ b/drivers/iio/accel/adxl372_spi.c
@@ -25,6 +25,8 @@ static int adxl372_spi_probe(struct spi_device *spi)
struct regmap *regmap;
chip_info = spi_get_device_match_data(spi);
+ if (!chip_info)
+ return -ENODATA;
regmap = devm_regmap_init_spi(spi, &adxl372_spi_regmap_config);
if (IS_ERR(regmap))
diff --git a/drivers/iio/accel/adxl380.c b/drivers/iio/accel/adxl380.c
index 7dca5523091f..8518ee23e114 100644
--- a/drivers/iio/accel/adxl380.c
+++ b/drivers/iio/accel/adxl380.c
@@ -966,6 +966,13 @@ static irqreturn_t adxl380_irq_handler(int irq, void *p)
if (ret)
return IRQ_HANDLED;
+ if (fifo_entries > ADXL380_FIFO_SAMPLES) {
+ dev_err_ratelimited(st->dev,
+ "FIFO entry count %u exceeds FIFO size %lu\n",
+ fifo_entries, ADXL380_FIFO_SAMPLES);
+ return IRQ_HANDLED;
+ }
+
fifo_entries = rounddown(fifo_entries, st->fifo_set_size);
ret = regmap_noinc_read(st->regmap, ADXL380_FIFO_DATA, &st->fifo_buf,
sizeof(*st->fifo_buf) * fifo_entries);
diff --git a/drivers/iio/accel/adxl380_spi.c b/drivers/iio/accel/adxl380_spi.c
index ae8467f4e6c0..8ffb3a8690a6 100644
--- a/drivers/iio/accel/adxl380_spi.c
+++ b/drivers/iio/accel/adxl380_spi.c
@@ -25,6 +25,8 @@ static int adxl380_spi_probe(struct spi_device *spi)
struct regmap *regmap;
chip_data = spi_get_device_match_data(spi);
+ if (!chip_data)
+ return -ENODATA;
regmap = devm_regmap_init_spi(spi, &adxl380_spi_regmap_config);
if (IS_ERR(regmap))
diff --git a/drivers/iio/accel/bma220_spi.c b/drivers/iio/accel/bma220_spi.c
index d6c1087cc3c0..d7a95289df48 100644
--- a/drivers/iio/accel/bma220_spi.c
+++ b/drivers/iio/accel/bma220_spi.c
@@ -28,12 +28,13 @@ static const struct spi_device_id bma220_spi_id[] = {
{ .name = "bma220" },
{ }
};
+MODULE_DEVICE_TABLE(spi, bma220_spi_id);
static const struct acpi_device_id bma220_acpi_id[] = {
{ "BMA0220", 0 },
{ }
};
-MODULE_DEVICE_TABLE(spi, bma220_spi_id);
+MODULE_DEVICE_TABLE(acpi, bma220_acpi_id);
static const struct of_device_id bma220_of_spi_match[] = {
{ .compatible = "bosch,bma220" },
diff --git a/drivers/iio/accel/bma400_core.c b/drivers/iio/accel/bma400_core.c
index 7e3cff4cca91..6bc64ca87f4b 100644
--- a/drivers/iio/accel/bma400_core.c
+++ b/drivers/iio/accel/bma400_core.c
@@ -6,8 +6,6 @@
*
* TODO:
* - Support for power management
- * - Support events and interrupts
- * - Create channel for step count
* - Create channel for sensor time
*/
diff --git a/drivers/iio/accel/kionix-kx022a.c b/drivers/iio/accel/kionix-kx022a.c
index 02dd1db7a646..a3d80e4e7f1e 100644
--- a/drivers/iio/accel/kionix-kx022a.c
+++ b/drivers/iio/accel/kionix-kx022a.c
@@ -301,11 +301,10 @@ struct kx022a_data {
__le16 *fifo_buffer;
/* 3 x 16bit accel data + timestamp */
- __le16 buffer[8] __aligned(IIO_DMA_MINALIGN);
struct {
__le16 channels[3];
aligned_s64 ts;
- } scan;
+ } scan __aligned(IIO_DMA_MINALIGN);
};
static const struct iio_mount_matrix *
@@ -611,14 +610,15 @@ static int kx022a_get_axis(struct kx022a_data *data,
struct iio_chan_spec const *chan,
int *val)
{
+ __le16 *buf = &data->scan.channels[0];
int ret;
- ret = regmap_bulk_read(data->regmap, chan->address, &data->buffer[0],
- sizeof(__le16));
+ ret = regmap_bulk_read(data->regmap, chan->address,
+ buf, sizeof(*buf));
if (ret)
return ret;
- *val = (s16)le16_to_cpu(data->buffer[0]);
+ *val = (s16)le16_to_cpup(buf);
return IIO_VAL_INT;
}
@@ -809,7 +809,7 @@ static int __kx022a_fifo_flush(struct iio_dev *idev, unsigned int samples,
* the timestamps. If we are ran from IRQ, then the
* IRQF_ONESHOT has us covered - but if we are ran by the
* user-space read we need to disable the IRQ to be on a safe
- * side. We do this usng synchronous disable so that if the
+ * side. We do this using synchronous disable so that if the
* IRQ thread is being ran on other CPU we wait for it to be
* finished.
*/
@@ -864,7 +864,8 @@ static int __kx022a_fifo_flush(struct iio_dev *idev, unsigned int samples,
for_each_set_bit(bit, idev->active_scan_mask, AXIS_MAX)
chs[bit] = sam[bit];
- iio_push_to_buffers_with_timestamp(idev, &data->scan, tstamp);
+ iio_push_to_buffers_with_ts(idev, &data->scan,
+ sizeof(data->scan), tstamp);
tstamp += sample_period;
}
@@ -1029,12 +1030,13 @@ static irqreturn_t kx022a_trigger_handler(int irq, void *p)
struct kx022a_data *data = iio_priv(idev);
int ret;
- ret = regmap_bulk_read(data->regmap, data->chip_info->xout_l, data->buffer,
- KX022A_FIFO_SAMPLES_SIZE_BYTES);
+ ret = regmap_bulk_read(data->regmap, data->chip_info->xout_l,
+ data->scan.channels, KX022A_FIFO_SAMPLES_SIZE_BYTES);
if (ret < 0)
goto err_read;
- iio_push_to_buffers_with_timestamp(idev, data->buffer, data->timestamp);
+ iio_push_to_buffers_with_ts(idev, &data->scan, sizeof(data->scan),
+ data->timestamp);
err_read:
iio_trigger_notify_done(idev->trig);
diff --git a/drivers/iio/accel/kionix-kx022a.h b/drivers/iio/accel/kionix-kx022a.h
index 0ed54f584223..a2d122c1e234 100644
--- a/drivers/iio/accel/kionix-kx022a.h
+++ b/drivers/iio/accel/kionix-kx022a.h
@@ -65,7 +65,7 @@
#define KX022A_MASK_IEN BIT(5)
#define KX022A_MASK_IPOL BIT(4)
#define KX022A_IPOL_LOW 0
-#define KX022A_IPOL_HIGH KX022A_MASK_IPOL1
+#define KX022A_IPOL_HIGH KX022A_MASK_IPOL
#define KX022A_MASK_ITYP BIT(3)
#define KX022A_ITYP_PULSE KX022A_MASK_ITYP
#define KX022A_ITYP_LEVEL 0
diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c
index 166fb786425f..c6b030f64be1 100644
--- a/drivers/iio/accel/kxcjk-1013.c
+++ b/drivers/iio/accel/kxcjk-1013.c
@@ -1547,6 +1547,7 @@ static void kxcjk1013_remove(struct i2c_client *client)
iio_device_unregister(indio_dev);
+ pm_runtime_dont_use_autosuspend(&client->dev);
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c
index 7d683686dd9d..fe62a903f0e2 100644
--- a/drivers/iio/accel/mma8452.c
+++ b/drivers/iio/accel/mma8452.c
@@ -18,6 +18,8 @@
* TODO: orientation events
*/
+#include
+#include
#include
#include
#include
@@ -110,8 +112,7 @@ struct mma8452_data {
u8 data_cfg;
const struct mma_chip_info *chip_info;
int sleep_val;
- struct regulator *vdd_reg;
- struct regulator *vddio_reg;
+ struct regulator_bulk_data regs[2];
/* Ensure correct alignment of time stamp when present */
struct {
@@ -222,15 +223,15 @@ static int mma8452_drdy(struct mma8452_data *data)
static int mma8452_set_runtime_pm_state(struct i2c_client *client, bool on)
{
#ifdef CONFIG_PM
+ struct device *dev = &client->dev;
int ret;
if (on)
- ret = pm_runtime_resume_and_get(&client->dev);
+ ret = pm_runtime_resume_and_get(dev);
else
- ret = pm_runtime_put_autosuspend(&client->dev);
+ ret = pm_runtime_put_autosuspend(dev);
if (ret < 0) {
- dev_err(&client->dev,
- "failed to change power state to %d\n", on);
+ dev_err(dev, "failed to change power state to %d\n", on);
return ret;
}
@@ -495,14 +496,14 @@ static int mma8452_read_raw(struct iio_dev *indio_dev,
int i, ret;
switch (mask) {
- case IIO_CHAN_INFO_RAW:
- if (!iio_device_claim_direct(indio_dev))
+ case IIO_CHAN_INFO_RAW: {
+ IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim);
+ if (IIO_DEV_ACQUIRE_FAILED(claim))
return -EBUSY;
- mutex_lock(&data->lock);
+ guard(mutex)(&data->lock);
+
ret = mma8452_read(data, buffer);
- mutex_unlock(&data->lock);
- iio_device_release_direct(indio_dev);
if (ret < 0)
return ret;
@@ -511,6 +512,7 @@ static int mma8452_read_raw(struct iio_dev *indio_dev,
chan->scan_type.realbits - 1);
return IIO_VAL_INT;
+ }
case IIO_CHAN_INFO_SCALE:
i = data->data_cfg & MMA8452_DATA_CFG_FS_MASK;
*val = data->chip_info->mma_scales[i][0];
@@ -599,36 +601,30 @@ static int mma8452_change_config(struct mma8452_data *data, u8 reg, u8 val)
int ret;
int is_active;
- mutex_lock(&data->lock);
+ guard(mutex)(&data->lock);
is_active = mma8452_is_active(data);
- if (is_active < 0) {
- ret = is_active;
- goto fail;
- }
+ if (is_active < 0)
+ return is_active;
/* config can only be changed when in standby */
if (is_active > 0) {
ret = mma8452_standby(data);
if (ret < 0)
- goto fail;
+ return ret;
}
ret = i2c_smbus_write_byte_data(data->client, reg, val);
if (ret < 0)
- goto fail;
+ return ret;
if (is_active > 0) {
ret = mma8452_active(data);
if (ret < 0)
- goto fail;
+ return ret;
}
- ret = 0;
-fail:
- mutex_unlock(&data->lock);
-
- return ret;
+ return 0;
}
static int mma8452_set_power_mode(struct mma8452_data *data, u8 mode)
@@ -777,14 +773,11 @@ static int mma8452_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
- int ret;
-
- if (!iio_device_claim_direct(indio_dev))
+ IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim);
+ if (IIO_DEV_ACQUIRE_FAILED(claim))
return -EBUSY;
- ret = __mma8452_write_raw(indio_dev, chan, val, val2, mask);
- iio_device_release_direct(indio_dev);
- return ret;
+ return __mma8452_write_raw(indio_dev, chan, val, val2, mask);
}
static int mma8452_get_event_regs(struct mma8452_data *data,
@@ -1552,7 +1545,7 @@ static int mma8452_probe(struct i2c_client *client)
struct iio_dev *indio_dev;
int ret;
- indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
@@ -1562,32 +1555,21 @@ static int mma8452_probe(struct i2c_client *client)
data->chip_info = i2c_get_match_data(client);
if (!data->chip_info)
- return dev_err_probe(&client->dev, -ENODEV,
- "unknown device model\n");
+ return dev_err_probe(dev, -ENODEV, "unknown device model\n");
- ret = iio_read_mount_matrix(&client->dev, &data->orientation);
+ ret = iio_read_mount_matrix(dev, &data->orientation);
if (ret)
return ret;
- data->vdd_reg = devm_regulator_get(&client->dev, "vdd");
- if (IS_ERR(data->vdd_reg))
- return dev_err_probe(&client->dev, PTR_ERR(data->vdd_reg),
- "failed to get VDD regulator!\n");
-
- data->vddio_reg = devm_regulator_get(&client->dev, "vddio");
- if (IS_ERR(data->vddio_reg))
- return dev_err_probe(&client->dev, PTR_ERR(data->vddio_reg),
- "failed to get VDDIO regulator!\n");
-
- ret = regulator_enable(data->vdd_reg);
+ data->regs[0].supply = "vdd";
+ data->regs[1].supply = "vddio";
+ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->regs), data->regs);
if (ret)
- return dev_err_probe(dev, ret, "failed to enable VDD regulator!\n");
+ return dev_err_probe(dev, ret, "failed to get regulators\n");
- ret = regulator_enable(data->vddio_reg);
- if (ret) {
- dev_err_probe(dev, ret, "failed to enable VDDIO regulator!\n");
- goto disable_regulator_vdd;
- }
+ ret = regulator_bulk_enable(ARRAY_SIZE(data->regs), data->regs);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to enable regulators\n");
ret = i2c_smbus_read_byte_data(client, MMA8452_WHO_AM_I);
if (ret < 0)
@@ -1608,7 +1590,7 @@ static int mma8452_probe(struct i2c_client *client)
goto disable_regulators;
}
- dev_info(&client->dev, "registering %s accelerometer; ID 0x%x\n",
+ dev_info(dev, "registering %s accelerometer; ID 0x%x\n",
data->chip_info->name, data->chip_info->chip_id);
i2c_set_clientdata(client, indio_dev);
@@ -1641,10 +1623,10 @@ static int mma8452_probe(struct i2c_client *client)
if (client->irq) {
int irq2;
- irq2 = fwnode_irq_get_byname(dev_fwnode(&client->dev), "INT2");
+ irq2 = fwnode_irq_get_byname(dev_fwnode(dev), "INT2");
if (irq2 == client->irq) {
- dev_dbg(&client->dev, "using interrupt line INT2\n");
+ dev_dbg(dev, "using interrupt line INT2\n");
} else {
ret = i2c_smbus_write_byte_data(client,
MMA8452_CTRL_REG5,
@@ -1652,7 +1634,7 @@ static int mma8452_probe(struct i2c_client *client)
if (ret < 0)
goto disable_regulators;
- dev_dbg(&client->dev, "using interrupt line INT1\n");
+ dev_dbg(dev, "using interrupt line INT1\n");
}
ret = i2c_smbus_write_byte_data(client,
@@ -1689,14 +1671,13 @@ static int mma8452_probe(struct i2c_client *client)
goto buffer_cleanup;
}
- ret = pm_runtime_set_active(&client->dev);
+ ret = pm_runtime_set_active(dev);
if (ret < 0)
goto free_irq;
- pm_runtime_enable(&client->dev);
- pm_runtime_set_autosuspend_delay(&client->dev,
- MMA8452_AUTO_SUSPEND_DELAY_MS);
- pm_runtime_use_autosuspend(&client->dev);
+ pm_runtime_enable(dev);
+ pm_runtime_set_autosuspend_delay(dev, MMA8452_AUTO_SUSPEND_DELAY_MS);
+ pm_runtime_use_autosuspend(dev);
ret = iio_device_register(indio_dev);
if (ret < 0)
@@ -1722,10 +1703,7 @@ static int mma8452_probe(struct i2c_client *client)
mma8452_trigger_cleanup(indio_dev);
disable_regulators:
- regulator_disable(data->vddio_reg);
-
-disable_regulator_vdd:
- regulator_disable(data->vdd_reg);
+ regulator_bulk_disable(ARRAY_SIZE(data->regs), data->regs);
return ret;
}
@@ -1734,11 +1712,12 @@ static void mma8452_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct mma8452_data *data = iio_priv(indio_dev);
+ struct device *dev = &client->dev;
iio_device_unregister(indio_dev);
- pm_runtime_disable(&client->dev);
- pm_runtime_set_suspended(&client->dev);
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
if (client->irq)
free_irq(client->irq, indio_dev);
@@ -1747,8 +1726,7 @@ static void mma8452_remove(struct i2c_client *client)
mma8452_trigger_cleanup(indio_dev);
mma8452_standby(iio_priv(indio_dev));
- regulator_disable(data->vddio_reg);
- regulator_disable(data->vdd_reg);
+ regulator_bulk_disable(ARRAY_SIZE(data->regs), data->regs);
}
#ifdef CONFIG_PM
@@ -1758,23 +1736,16 @@ static int mma8452_runtime_suspend(struct device *dev)
struct mma8452_data *data = iio_priv(indio_dev);
int ret;
- mutex_lock(&data->lock);
- ret = mma8452_standby(data);
- mutex_unlock(&data->lock);
+ scoped_guard(mutex, &data->lock)
+ ret = mma8452_standby(data);
if (ret < 0) {
- dev_err(&data->client->dev, "powering off device failed\n");
+ dev_err(dev, "powering off device failed\n");
return -EAGAIN;
}
- ret = regulator_disable(data->vddio_reg);
+ ret = regulator_bulk_disable(ARRAY_SIZE(data->regs), data->regs);
if (ret) {
- dev_err(dev, "failed to disable VDDIO regulator\n");
- return ret;
- }
-
- ret = regulator_disable(data->vdd_reg);
- if (ret) {
- dev_err(dev, "failed to disable VDD regulator\n");
+ dev_err(dev, "failed to disable regulators\n");
return ret;
}
@@ -1787,16 +1758,9 @@ static int mma8452_runtime_resume(struct device *dev)
struct mma8452_data *data = iio_priv(indio_dev);
int ret, sleep_val;
- ret = regulator_enable(data->vdd_reg);
+ ret = regulator_bulk_enable(ARRAY_SIZE(data->regs), data->regs);
if (ret) {
- dev_err(dev, "failed to enable VDD regulator\n");
- return ret;
- }
-
- ret = regulator_enable(data->vddio_reg);
- if (ret) {
- dev_err(dev, "failed to enable VDDIO regulator\n");
- regulator_disable(data->vdd_reg);
+ dev_err(dev, "failed to enable regulators\n");
return ret;
}
@@ -1814,8 +1778,7 @@ static int mma8452_runtime_resume(struct device *dev)
return 0;
runtime_resume_failed:
- regulator_disable(data->vddio_reg);
- regulator_disable(data->vdd_reg);
+ regulator_bulk_disable(ARRAY_SIZE(data->regs), data->regs);
return ret;
}
diff --git a/drivers/iio/accel/mma9551.c b/drivers/iio/accel/mma9551.c
index 7e01427fd9c4..182f488edab1 100644
--- a/drivers/iio/accel/mma9551.c
+++ b/drivers/iio/accel/mma9551.c
@@ -500,6 +500,7 @@ static void mma9551_remove(struct i2c_client *client)
iio_device_unregister(indio_dev);
+ pm_runtime_dont_use_autosuspend(&client->dev);
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c
index 8e7aaac89d47..5a36d415a837 100644
--- a/drivers/iio/accel/mma9553.c
+++ b/drivers/iio/accel/mma9553.c
@@ -1136,6 +1136,7 @@ static void mma9553_remove(struct i2c_client *client)
iio_device_unregister(indio_dev);
+ pm_runtime_dont_use_autosuspend(&client->dev);
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
diff --git a/drivers/iio/accel/sca3000.c b/drivers/iio/accel/sca3000.c
index a92a563f6a4b..0d5ed244a663 100644
--- a/drivers/iio/accel/sca3000.c
+++ b/drivers/iio/accel/sca3000.c
@@ -1462,6 +1462,8 @@ static int sca3000_probe(struct spi_device *spi)
st->us = spi;
mutex_init(&st->lock);
st->info = spi_get_device_match_data(spi);
+ if (!st->info)
+ return -ENODATA;
indio_dev->name = st->info->name;
indio_dev->info = &sca3000_info;
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 415e519ad4eb..a802d8ee4dd9 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -105,7 +105,7 @@ config AD4080
called ad4080.
config AD4130
- tristate "Analog Device AD4130 ADC Driver"
+ tristate "Analog Devices AD4130 ADC Driver"
depends on SPI
depends on GPIOLIB
select IIO_BUFFER
@@ -121,7 +121,7 @@ config AD4130
called ad4130.
config AD4134
- tristate "Analog Device AD4134 ADC Driver"
+ tristate "Analog Devices AD4134 ADC Driver"
depends on SPI
select REGMAP_SPI
select CRC8
@@ -133,7 +133,7 @@ config AD4134
called ad4134_spi.
config AD4170_4
- tristate "Analog Device AD4170-4 ADC Driver"
+ tristate "Analog Devices AD4170-4 ADC Driver"
depends on SPI
select REGMAP_SPI
select IIO_BUFFER
@@ -164,7 +164,7 @@ config AD4691
called ad4691.
config AD4695
- tristate "Analog Device AD4695 ADC Driver"
+ tristate "Analog Devices AD4695 ADC Driver"
depends on SPI
select IIO_BUFFER
select IIO_BUFFER_DMAENGINE
@@ -179,7 +179,7 @@ config AD4695
called ad4695.
config AD4851
- tristate "Analog Device AD4851 DAS Driver"
+ tristate "Analog Devices AD4851 DAS Driver"
depends on SPI
depends on PWM
select REGMAP_SPI
@@ -347,7 +347,7 @@ config AD7380
called ad7380.
config AD7405
- tristate "Analog Device AD7405 ADC Driver"
+ tristate "Analog Devices AD7405 ADC Driver"
depends on IIO_BACKEND
help
Say yes here to build support for Analog Devices AD7405, ADUM7701,
@@ -431,6 +431,21 @@ config AD7766
To compile this driver as a module, choose M here: the module will be
called ad7766.
+config AD7768
+ tristate "Analog Devices AD7768/AD7768-4 ADC driver"
+ depends on SPI
+ select REGULATOR
+ select AUXILIARY_BUS
+ select IIO_BUFFER
+ select IIO_BACKEND
+ select REGMAP
+ help
+ Say yes here to build support for Analog Devices AD7768 and AD7768-4
+ SPI analog to digital converters.
+
+ To compile this driver as a module, choose M here: the module will be
+ called ad7768.
+
config AD7768_1
tristate "Analog Devices AD7768-1 ADC driver"
depends on SPI
@@ -576,20 +591,22 @@ config AD9467
called ad9467.
config ADE9000
- tristate "Analog Devices ADE9000 Multiphase Energy, and Power Quality Monitoring IC Driver"
+ tristate "Analog Devices Multiphase Energy and Power Quality Monitoring IC Driver"
depends on SPI
select REGMAP_SPI
select IIO_BUFFER
select IIO_KFIFO_BUF
help
- Say yes here to build support for the Analog Devices ADE9000,
- a highly accurate, multiphase energy and power quality monitoring
- integrated circuit.
+ Say yes here to build support for the following Analog Devices
+ highly accurate, multiphase energy and power quality monitoring
+ integrated circuits:
+ - ADE9000
+ - ADE9078
- The device features high-precision analog-to-digital converters
+ The devices feature high-precision analog-to-digital converters
and digital signal processing to compute RMS values, power factor,
- frequency, and harmonic analysis. It supports SPI communication
- and provides buffered data output through the IIO framework.
+ frequency, and harmonic analysis. They support SPI communication
+ and provide buffered data output through the IIO framework.
To compile this driver as a module, choose M here: the module will
be called ade9000.
@@ -653,6 +670,17 @@ config AT91_SAMA5D2_ADC
To compile this driver as a module, choose M here: the module will be
called at91-sama5d2_adc.
+config AXIADO_SARADC
+ tristate "Axiado SARADC driver"
+ depends on ARCH_AXIADO || COMPILE_TEST
+ select REGMAP_MMIO
+ help
+ Say yes here to build support for the SARADC found in Axiado
+ SoCs.
+
+ To compile this driver as a module, choose M here: the module
+ will be called axiado_saradc.
+
config AXP20X_ADC
tristate "X-Powers AXP20X and AXP22X ADC driver"
depends on MFD_AXP20X
@@ -1116,6 +1144,17 @@ config MAX34408
To compile this driver as a module, choose M here: the module will be
called max34408.
+config MAX40080
+ tristate "Analog Devices MAX40080 Current Sense Amplifier"
+ depends on I2C
+ help
+ Say yes here to build support for the Analog Devices MAX40080
+ bidirectional current-sense amplifier with a 12-bit ADC and an I2C
+ interface.
+
+ To compile this driver as a module, choose M here: the module will be
+ called max40080.
+
config MAX77541_ADC
tristate "Analog Devices MAX77541 ADC driver"
depends on MFD_MAX77541
@@ -1551,6 +1590,8 @@ config RZT2H_ADC
tristate "Renesas RZ/T2H / RZ/N2H ADC driver"
depends on ARCH_RENESAS || COMPILE_TEST
select IIO_ADC_HELPER
+ select IIO_BUFFER
+ select IIO_KFIFO_BUF
help
Say yes here to build support for the ADC found in Renesas
RZ/T2H / RZ/N2H SoCs.
@@ -1801,11 +1842,14 @@ config TI_ADS1018
called ti-ads1018.
config TI_ADS1100
- tristate "Texas Instruments ADS1100 and ADS1000 ADC"
+ tristate "Texas Instruments ADS1100 and similar single channel I2C ADC"
depends on I2C
help
- If you say yes here you get support for Texas Instruments ADS1100 and
- ADS1000 ADC chips.
+ If you say yes here you get support for TI single channel I2C Analog
+ Devices.
+ * ADS1000 12-Bit, 128 SPS Analog-to-Digital Converter
+ * ADS1100 16-Bit, 128 SPS Analog-to-Digital Converter
+ * ADS1110 16-Bit, 240 SPS Analog-to-Digital Converter
This driver can also be built as a module. If so, the module will be
called ti-ads1100.
@@ -1822,6 +1866,16 @@ config TI_ADS1119
This driver can also be built as a module. If so, the module will be
called ti-ads1119.
+config TI_ADS112C04
+ tristate "Texas Instruments ADS112C04 ADC"
+ depends on I2C
+ help
+ If you say yes here you get support for Texas Instruments
+ ADS112C04 (16-bit) I2C analog to digital converters.
+
+ This driver can also be built as a module. If so, the module will be
+ called ti-ads112c04.
+
config TI_ADS112C14
tristate "Texas Instruments ADS112C14/ADS122C14"
depends on I2C
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index dcec0abb03b7..9e82c21dbd37 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_AD7606_IFACE_SPI) += ad7606_spi.o
obj-$(CONFIG_AD7606) += ad7606.o
obj-$(CONFIG_AD7625) += ad7625.o
obj-$(CONFIG_AD7766) += ad7766.o
+obj-$(CONFIG_AD7768) += ad7768.o
obj-$(CONFIG_AD7768_1) += ad7768-1.o
obj-$(CONFIG_AD7779) += ad7779.o
obj-$(CONFIG_AD7780) += ad7780.o
@@ -55,6 +56,7 @@ obj-$(CONFIG_ADI_AXI_ADC) += adi-axi-adc.o
obj-$(CONFIG_ASPEED_ADC) += aspeed_adc.o
obj-$(CONFIG_AT91_ADC) += at91_adc.o
obj-$(CONFIG_AT91_SAMA5D2_ADC) += at91-sama5d2_adc.o
+obj-$(CONFIG_AXIADO_SARADC) += axiado_saradc.o
obj-$(CONFIG_AXP20X_ADC) += axp20x_adc.o
obj-$(CONFIG_AXP288_ADC) += axp288_adc.o
obj-$(CONFIG_BCM_IPROC_ADC) += bcm_iproc_adc.o
@@ -95,6 +97,7 @@ obj-$(CONFIG_MAX1241) += max1241.o
obj-$(CONFIG_MAX1363) += max1363.o
obj-$(CONFIG_MAX14001) += max14001.o
obj-$(CONFIG_MAX34408) += max34408.o
+obj-$(CONFIG_MAX40080) += max40080.o
obj-$(CONFIG_MAX77541_ADC) += max77541-adc.o
obj-$(CONFIG_MAX9611) += max9611.o
obj-$(CONFIG_MCP320X) += mcp320x.o
@@ -155,6 +158,7 @@ obj-$(CONFIG_TI_ADS1015) += ti-ads1015.o
obj-$(CONFIG_TI_ADS1018) += ti-ads1018.o
obj-$(CONFIG_TI_ADS1100) += ti-ads1100.o
obj-$(CONFIG_TI_ADS1119) += ti-ads1119.o
+obj-$(CONFIG_TI_ADS112C04) += ti-ads112c04.o
obj-$(CONFIG_TI_ADS112C14) += ti-ads112c14.o
obj-$(CONFIG_TI_ADS124S08) += ti-ads124s08.o
obj-$(CONFIG_TI_ADS1298) += ti-ads1298.o
diff --git a/drivers/iio/adc/ad4080.c b/drivers/iio/adc/ad4080.c
index 04cd6628ebff..4ed82aa42400 100644
--- a/drivers/iio/adc/ad4080.c
+++ b/drivers/iio/adc/ad4080.c
@@ -137,6 +137,7 @@
#define AD4880_CHIP_ID 0x0059
#define AD4883_CHIP_ID 0x005B
#define AD4884_CHIP_ID 0x005C
+#define AD4885_CHIP_ID 0x005D
#define AD4080_MAX_CHANNELS 2
@@ -145,6 +146,10 @@
#define AD4080_MAX_SAMP_FREQ 40000000
#define AD4080_MIN_SAMP_FREQ 1250000
+/* debugfs direct_reg_access channel windowing: 0x0RR = ch0, 0x1RR = ch1 */
+#define AD4080_DEBUGFS_REG_CH_MSK GENMASK(15, 8)
+#define AD4080_DEBUGFS_REG_OFFSET_MSK GENMASK(7, 0)
+
enum ad4080_filter_type {
FILTER_NONE,
SINC_1,
@@ -210,11 +215,16 @@ static int ad4080_reg_access(struct iio_dev *indio_dev, unsigned int reg,
unsigned int writeval, unsigned int *readval)
{
struct ad4080_state *st = iio_priv(indio_dev);
+ unsigned int ch = FIELD_GET(AD4080_DEBUGFS_REG_CH_MSK, reg);
+ unsigned int offset = FIELD_GET(AD4080_DEBUGFS_REG_OFFSET_MSK, reg);
+
+ if (ch >= st->info->num_channels)
+ return -EINVAL;
if (readval)
- return regmap_read(st->regmap[0], reg, readval);
+ return regmap_read(st->regmap[ch], offset, readval);
- return regmap_write(st->regmap[0], reg, writeval);
+ return regmap_write(st->regmap[ch], offset, writeval);
}
static int ad4080_get_scale(struct ad4080_state *st, int *val, int *val2)
@@ -552,6 +562,11 @@ static const struct iio_chan_spec ad4884_channels[] = {
AD4880_CHANNEL_DEFINE(16, 16, 1),
};
+static const struct iio_chan_spec ad4885_channels[] = {
+ AD4880_CHANNEL_DEFINE(16, 16, 0),
+ AD4880_CHANNEL_DEFINE(16, 16, 1),
+};
+
static const struct ad4080_chip_info ad4080_chip_info = {
.name = "ad4080",
.product_id = AD4080_CHIP_ID,
@@ -672,6 +687,16 @@ static const struct ad4080_chip_info ad4884_chip_info = {
.lvds_cnv_clk_cnt_max = 2,
};
+static const struct ad4080_chip_info ad4885_chip_info = {
+ .name = "ad4885",
+ .product_id = AD4885_CHIP_ID,
+ .scale_table = ad4080_scale_table,
+ .num_scales = ARRAY_SIZE(ad4080_scale_table),
+ .num_channels = 2,
+ .channels = ad4885_channels,
+ .lvds_cnv_clk_cnt_max = 8,
+};
+
static int ad4080_setup_channel(struct ad4080_state *st, unsigned int ch)
{
struct device *dev = regmap_get_device(st->regmap[ch]);
@@ -685,7 +710,8 @@ static int ad4080_setup_channel(struct ad4080_state *st, unsigned int ch)
return ret;
ret = regmap_write(st->regmap[ch], AD4080_REG_INTERFACE_CONFIG_A,
- AD4080_INTERFACE_CONFIG_A_SDO_ENABLE);
+ AD4080_INTERFACE_CONFIG_A_SDO_ENABLE |
+ AD4080_INTERFACE_CONFIG_A_ADDR_ASC);
if (ret)
return ret;
@@ -881,6 +907,7 @@ static const struct spi_device_id ad4080_id[] = {
{ .name = "ad4880", .driver_data = (kernel_ulong_t)&ad4880_chip_info },
{ .name = "ad4883", .driver_data = (kernel_ulong_t)&ad4883_chip_info },
{ .name = "ad4884", .driver_data = (kernel_ulong_t)&ad4884_chip_info },
+ { .name = "ad4885", .driver_data = (kernel_ulong_t)&ad4885_chip_info },
{ }
};
MODULE_DEVICE_TABLE(spi, ad4080_id);
@@ -898,6 +925,7 @@ static const struct of_device_id ad4080_of_match[] = {
{ .compatible = "adi,ad4880", &ad4880_chip_info },
{ .compatible = "adi,ad4883", &ad4883_chip_info },
{ .compatible = "adi,ad4884", &ad4884_chip_info },
+ { .compatible = "adi,ad4885", &ad4885_chip_info },
{ }
};
MODULE_DEVICE_TABLE(of, ad4080_of_match);
diff --git a/drivers/iio/adc/ad4134.c b/drivers/iio/adc/ad4134.c
index 0490218bb0e9..70f80bf1825f 100644
--- a/drivers/iio/adc/ad4134.c
+++ b/drivers/iio/adc/ad4134.c
@@ -496,4 +496,3 @@ module_spi_driver(ad4134_driver);
MODULE_AUTHOR("Marcelo Schmitt ");
MODULE_DESCRIPTION("Analog Devices AD4134 SPI driver");
MODULE_LICENSE("GPL");
-MODULE_IMPORT_NS("IIO_AD4134");
diff --git a/drivers/iio/adc/ad7173.c b/drivers/iio/adc/ad7173.c
index eb47175a0528..5dd82ada79bf 100644
--- a/drivers/iio/adc/ad7173.c
+++ b/drivers/iio/adc/ad7173.c
@@ -1801,8 +1801,7 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev)
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);
+ chan_arr = devm_kcalloc(dev, sizeof(*chan_arr), st->num_channels, GFP_KERNEL);
if (!chan_arr)
return -ENOMEM;
diff --git a/drivers/iio/adc/ad7192.c b/drivers/iio/adc/ad7192.c
index d8f5886fcf69..8bd810546311 100644
--- a/drivers/iio/adc/ad7192.c
+++ b/drivers/iio/adc/ad7192.c
@@ -1406,6 +1406,9 @@ static int ad7192_probe(struct spi_device *spi)
st->int_vref_mv = ret == -ENODEV ? avdd_mv : ret / MILLI;
st->chip_info = spi_get_device_match_data(spi);
+ if (!st->chip_info)
+ return -ENODATA;
+
indio_dev->name = st->chip_info->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = st->chip_info->info;
diff --git a/drivers/iio/adc/ad7606_spi.c b/drivers/iio/adc/ad7606_spi.c
index 1ebdfb8580ab..8c479fa50a23 100644
--- a/drivers/iio/adc/ad7606_spi.c
+++ b/drivers/iio/adc/ad7606_spi.c
@@ -456,7 +456,11 @@ static const struct ad7606_bus_info ad7616_bus_info = {
static int ad7606_spi_probe(struct spi_device *spi)
{
- const struct ad7606_bus_info *bus_info = spi_get_device_match_data(spi);
+ const struct ad7606_bus_info *bus_info;
+
+ bus_info = spi_get_device_match_data(spi);
+ if (!bus_info)
+ return -ENODATA;
return ad7606_probe(&spi->dev, spi->irq, NULL,
bus_info->chip_info, bus_info->bops);
diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c
index e9060c1bbe6f..3972821c295a 100644
--- a/drivers/iio/adc/ad7768-1.c
+++ b/drivers/iio/adc/ad7768-1.c
@@ -1829,6 +1829,9 @@ static int ad7768_probe(struct spi_device *spi)
}
st->chip = spi_get_device_match_data(spi);
+ if (!st->chip)
+ return -ENODATA;
+
st->spi = spi;
st->regmap = devm_regmap_init_spi(spi, &ad7768_regmap_config);
diff --git a/drivers/iio/adc/ad7768.c b/drivers/iio/adc/ad7768.c
new file mode 100644
index 000000000000..aa2db87a1b9f
--- /dev/null
+++ b/drivers/iio/adc/ad7768.c
@@ -0,0 +1,1921 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Analog Devices AD7768 ADC driver
+ *
+ * Copyright 2018-2026 Analog Devices Inc.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#define AD7768_REG_CH_STANDBY 0x00
+
+#define AD7768_REG_CH_MODE(x) (0x01 + (x))
+#define AD7768_CH_MODE_FILTER_TYPE_MSK BIT(3)
+#define AD7768_CH_MODE_DEC_RATE_MSK GENMASK(2, 0)
+
+#define AD7768_REG_CH_MODE_SEL 0x03
+
+#define AD7768_REG_POWER_MODE 0x04
+#define AD7768_SLEEP_MODE_MSK BIT(7)
+#define AD7768_POWER_MODE_POWER_MODE_MSK GENMASK(5, 4)
+#define AD7768_POWER_MODE_POWER_MODE_LOW 0x0
+#define AD7768_POWER_MODE_POWER_MODE_MEDIAN 0x2
+#define AD7768_POWER_MODE_POWER_MODE_FAST 0x3
+#define AD7768_POWER_MODE_LVDS_ENABLE BIT(3)
+#define AD7768_POWER_MODE_MCLK_DIV_MSK GENMASK(1, 0)
+
+#define AD7768_REG_GENERAL_CONFIG 0x05
+#define AD7768_GEN_CONFIG_VCM_SEL_MSK GENMASK(1, 0)
+#define AD7768_GEN_CONFIG_VCM_PD BIT(4)
+
+#define AD7768_REG_DATA_CONTROL 0x06
+#define AD7768_DATA_CONTROL_SPI_RESET_1 0x03
+#define AD7768_DATA_CONTROL_SPI_RESET_2 0x02
+#define AD7768_DATA_CONTROL_SPI_SYNC BIT(7)
+
+#define AD7768_REG_INTERFACE_CFG 0x07
+#define AD7768_INTERFACE_CFG_CRC_SELECT_MSK GENMASK(3, 2)
+#define AD7768_INTERFACE_CFG_CRC_SELECT_4 0x1
+#define AD7768_INTERFACE_CFG_DCLK_DIV_MSK GENMASK(1, 0)
+#define AD7768_INTERFACE_CFG_DCLK_DIV_8 0x0
+#define AD7768_INTERFACE_CFG_DCLK_DIV_4 0x1
+#define AD7768_INTERFACE_CFG_DCLK_DIV_2 0x2
+#define AD7768_INTERFACE_CFG_DCLK_DIV_1 0x3
+
+#define AD7768_REG_REV_ID 0x0A
+#define AD7768_REV_ID_VAL 0x06
+
+#define AD7768_REG_GPIO_CONTROL 0x0E
+#define AD7768_GPIO_UGPIO_ENABLE BIT(7)
+#define AD7768_GPIO4_OUTPUT_ENABLE BIT(4)
+
+#define AD7768_REG_GPIO_WRITE 0x0F
+
+#define AD7768_REG_PRECHARGE_BUF1 0x11
+#define AD7768_REG_PRECHARGE_BUF2 0x12
+#define AD7768_PREBUF_POS_EN(ch) BIT((ch) * 2 + 0)
+#define AD7768_PREBUF_NEG_EN(ch) BIT((ch) * 2 + 1)
+
+#define AD7768_REG_REFP_BUF 0x13
+#define AD7768_REG_REFN_BUF 0x14
+
+#define AD7768_REG_OFFSET_BASE 0x1E
+#define AD7768_REG_GAIN_BASE 0x36
+#define AD7768_REG_PHASE_BASE 0x4E
+#define AD7768_REG_OFFSET(ch) (AD7768_REG_OFFSET_BASE + 3 * (ch))
+#define AD7768_REG_GAIN(ch) (AD7768_REG_GAIN_BASE + 3 * (ch))
+#define AD7768_REG_PHASE(ch) (AD7768_REG_PHASE_BASE + (ch))
+
+#define AD7768_REG_DIAGNOSTIC_RX 0x56
+
+#define AD7768_REG_CHOP_CTRL 0x59
+
+#define AD7768_SPI_READ_CMD BIT(15)
+#define AD7768_SPI_REG_MASK GENMASK(14, 8)
+#define AD7768_SPI_DATA_MASK GENMASK(7, 0)
+
+#define AD7768_SAMPLE_SIZE 32
+#define AD7768_MAX_DCLK_DIV 8
+#define AD7768_MIN_MCLK_FREQ_HZ (1150 * HZ_PER_KHZ)
+#define AD7768_MIN_XTAL_FREQ_HZ (8 * HZ_PER_MHZ)
+#define AD7768_MAX_MCLK_FREQ_HZ (34 * HZ_PER_MHZ)
+#define AD7768_MAX_FREQ_PER_MODE 6
+#define AD7768_MAX_CHANNEL 8
+#define AD7768_NUM_CHANNEL_MODES 2
+#define AD7768_CALIB_SIGN_BIT 23
+#define AD7768_CALIB_REG_MSK GENMASK(AD7768_CALIB_SIGN_BIT, 0)
+#define AD7768_WIDEBAND_SETTLING_SAMPLES 68
+#define AD7768_SINC5_SETTLING_SAMPLES 7
+
+enum ad7768_filter_type {
+ AD7768_FILTER_TYPE_WIDEBAND,
+ AD7768_FILTER_TYPE_SINC5,
+};
+
+enum ad7768_clock_source {
+ AD7768_CLOCK_SOURCE_MCLK,
+ AD7768_CLOCK_SOURCE_XTAL,
+ AD7768_CLOCK_SOURCE_LVDS,
+};
+
+struct ad7768_power_mode_info {
+ unsigned int mode;
+ unsigned int mclk_div;
+};
+
+static const struct ad7768_power_mode_info ad7768_power_modes[] = {
+ { .mode = AD7768_POWER_MODE_POWER_MODE_LOW, .mclk_div = 32 },
+ { .mode = AD7768_POWER_MODE_POWER_MODE_MEDIAN, .mclk_div = 8 },
+ { .mode = AD7768_POWER_MODE_POWER_MODE_FAST, .mclk_div = 4 },
+};
+
+#define AD7768_MAX_FREQS \
+ (AD7768_MAX_FREQ_PER_MODE + ARRAY_SIZE(ad7768_power_modes))
+
+struct ad7768_precharge_config {
+ bool prebufp_en;
+ bool prebufn_en;
+ bool refbufp;
+ bool refbufn;
+};
+
+struct ad7768_freq_config {
+ unsigned int freq_hz;
+ unsigned int dec_rate;
+};
+
+struct ad7768_convdelay_params {
+ unsigned int shift;
+ unsigned int max_raw;
+ u64 step_ps;
+};
+
+struct ad7768_avail_freq {
+ unsigned int n_freqs;
+ struct ad7768_freq_config freq_cfg[AD7768_MAX_FREQ_PER_MODE];
+};
+
+struct ad7768_chip_info {
+ const char *name;
+ const struct regmap_config *regmap_config;
+ const unsigned int *available_datalines;
+ unsigned int num_datalines;
+ unsigned int num_channels;
+ const u8 *chan_map;
+ u8 prebuf_split;
+};
+
+struct ad7768_state {
+ struct regmap *regmap;
+ /* Protects device register access and configuration. */
+ struct mutex lock;
+ struct clk *mclk;
+ unsigned int datalines;
+ enum ad7768_clock_source clock_source;
+ const struct ad7768_chip_info *chip_info;
+ struct ad7768_avail_freq avail_freq[ARRAY_SIZE(ad7768_power_modes)];
+ unsigned int n_freqs;
+ int freqs[AD7768_MAX_FREQS];
+ u64 ch_convdelay_ps[AD7768_MAX_CHANNEL];
+ unsigned int ch_freq[AD7768_MAX_CHANNEL];
+ unsigned int power_mode_idx;
+ enum ad7768_filter_type ch_filter[AD7768_MAX_CHANNEL];
+ struct iio_backend *back;
+ struct regulator_dev *vcm_rdev;
+ unsigned int avdd1_uV;
+ unsigned int vref_uV[2];
+
+ /* Used only in regmap_read() callback, hence guarded by regmap lock. */
+ __be16 d16 __aligned(IIO_DMA_MINALIGN);
+};
+
+static const unsigned int ad7768_vcm_voltage_table[] = {
+ 0, 1650000, 2500000, 2140000,
+};
+
+static int ad7768_vcm_list_voltage(struct regulator_dev *rdev,
+ unsigned int selector)
+{
+ struct ad7768_state *st = rdev_get_drvdata(rdev);
+
+ if (selector >= ARRAY_SIZE(ad7768_vcm_voltage_table))
+ return -EINVAL;
+
+ if (!selector)
+ return DIV_ROUND_CLOSEST(st->avdd1_uV, 2);
+
+ return ad7768_vcm_voltage_table[selector];
+}
+
+static int ad7768_vcm_enable(struct regulator_dev *rdev)
+{
+ struct ad7768_state *st = rdev_get_drvdata(rdev);
+ int ret;
+
+ ret = pm_runtime_resume_and_get(regmap_get_device(st->regmap));
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_clear_bits(st->regmap, AD7768_REG_GENERAL_CONFIG,
+ AD7768_GEN_CONFIG_VCM_PD);
+ if (ret)
+ pm_runtime_put_autosuspend(regmap_get_device(st->regmap));
+
+ return ret;
+}
+
+static int ad7768_vcm_disable(struct regulator_dev *rdev)
+{
+ struct ad7768_state *st = rdev_get_drvdata(rdev);
+ int ret;
+
+ ret = regmap_set_bits(st->regmap, AD7768_REG_GENERAL_CONFIG,
+ AD7768_GEN_CONFIG_VCM_PD);
+ if (ret)
+ return ret;
+
+ pm_runtime_put_autosuspend(regmap_get_device(st->regmap));
+
+ return 0;
+}
+
+static int ad7768_vcm_is_enabled(struct regulator_dev *rdev)
+{
+ struct ad7768_state *st = rdev_get_drvdata(rdev);
+ int ret;
+
+ PM_RUNTIME_ACQUIRE_AUTOSUSPEND(regmap_get_device(st->regmap), pm);
+ ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+ if (ret)
+ return ret;
+
+ ret = regmap_test_bits(st->regmap, AD7768_REG_GENERAL_CONFIG,
+ AD7768_GEN_CONFIG_VCM_PD);
+ if (ret < 0)
+ return ret;
+
+ return !ret;
+}
+
+static int ad7768_vcm_set_voltage_sel(struct regulator_dev *rdev,
+ unsigned int selector)
+{
+ struct ad7768_state *st = rdev_get_drvdata(rdev);
+ int ret;
+
+ PM_RUNTIME_ACQUIRE_AUTOSUSPEND(regmap_get_device(st->regmap), pm);
+ ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+ if (ret)
+ return ret;
+
+ return regmap_update_bits(st->regmap, AD7768_REG_GENERAL_CONFIG,
+ AD7768_GEN_CONFIG_VCM_SEL_MSK,
+ FIELD_PREP(AD7768_GEN_CONFIG_VCM_SEL_MSK,
+ selector));
+}
+
+static int ad7768_vcm_get_voltage_sel(struct regulator_dev *rdev)
+{
+ struct ad7768_state *st = rdev_get_drvdata(rdev);
+ unsigned int val;
+ int ret;
+
+ PM_RUNTIME_ACQUIRE_AUTOSUSPEND(regmap_get_device(st->regmap), pm);
+ ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(st->regmap, AD7768_REG_GENERAL_CONFIG, &val);
+ if (ret)
+ return ret;
+
+ return FIELD_GET(AD7768_GEN_CONFIG_VCM_SEL_MSK, val);
+}
+
+static const struct regulator_ops ad7768_vcm_ops = {
+ .enable = ad7768_vcm_enable,
+ .disable = ad7768_vcm_disable,
+ .is_enabled = ad7768_vcm_is_enabled,
+ .list_voltage = ad7768_vcm_list_voltage,
+ .set_voltage_sel = ad7768_vcm_set_voltage_sel,
+ .get_voltage_sel = ad7768_vcm_get_voltage_sel,
+};
+
+static const struct regulator_desc ad7768_vcm_desc = {
+ .name = "vcm",
+ .of_match = "vcm-output",
+ .regulators_node = "regulators",
+ .n_voltages = ARRAY_SIZE(ad7768_vcm_voltage_table),
+ .ops = &ad7768_vcm_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+};
+
+static int ad7768_register_vcm_regulator(struct device *dev,
+ struct ad7768_state *st)
+{
+ struct regulator_config config = {
+ .dev = dev,
+ .driver_data = st,
+ };
+ int ret;
+
+ /*
+ * Start with VCM disabled so each enabled state is paired with the
+ * runtime PM reference acquired by ad7768_vcm_enable().
+ */
+ ret = regmap_set_bits(st->regmap, AD7768_REG_GENERAL_CONFIG,
+ AD7768_GEN_CONFIG_VCM_PD);
+ if (ret)
+ return ret;
+
+ st->vcm_rdev = devm_regulator_register(dev, &ad7768_vcm_desc, &config);
+ return PTR_ERR_OR_ZERO(st->vcm_rdev);
+}
+
+static const unsigned int ad7768_dec_rate[AD7768_MAX_FREQ_PER_MODE] = {
+ 32, 64, 128, 256, 512, 1024,
+};
+
+static const unsigned int ad7768_available_datalines[] = {
+ 1, 2, 8,
+};
+
+static const unsigned int ad7768_4_available_datalines[] = {
+ 1, 4,
+};
+
+static const u8 ad7768_chan_map[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7,
+};
+
+static const u8 ad7768_4_chan_map[] = {
+ 0, 1, 4, 5,
+};
+
+static const char * const ad7768_supply_names[] = {
+ "avdd2", "iovdd",
+};
+
+static const char * const ad7768_vref_supply_names[][2] = {
+ { "ref1p", "ref1n" },
+ { "ref2p", "ref2n" },
+};
+
+static const char * const ad7768_clock_names[] = {
+ [AD7768_CLOCK_SOURCE_MCLK] = "mclk",
+ [AD7768_CLOCK_SOURCE_XTAL] = "xtal",
+ [AD7768_CLOCK_SOURCE_LVDS] = "lvds",
+};
+
+static u8 ad7768_channel_mask(const struct ad7768_state *st, u8 ch)
+{
+ return BIT(st->chip_info->chan_map[ch]);
+}
+
+static u8 ad7768_channel_mode_mask(const struct ad7768_state *st, u8 ch)
+{
+ /*
+ * AD7768-4 channels 2 and 3 use bits 4 and 5 for CH_x_MODE, while
+ * their CH_x_MDE_EN fields are in bits 2 and 3 and must be programmed
+ * to the same value. On AD7768, chan_map[] is an identity map, so the
+ * OR produces a single bit.
+ */
+ return BIT(ch) | ad7768_channel_mask(st, ch);
+}
+
+static u8 ad7768_all_standby_mask(const struct ad7768_state *st)
+{
+ return GENMASK(st->chip_info->num_channels - 1, 0);
+}
+
+static void ad7768_keep_xtal_channel_active(const struct ad7768_state *st,
+ unsigned long *standby_mask)
+{
+ /*
+ * Crystal excitation requires channel 4 on AD7768 or channel 2 on
+ * AD7768-4 to remain active.
+ */
+ if (st->clock_source == AD7768_CLOCK_SOURCE_XTAL)
+ __clear_bit(st->chip_info->num_channels / 2, standby_mask);
+}
+
+static unsigned int ad7768_offset_reg(const struct ad7768_state *st,
+ unsigned int ch)
+{
+ return AD7768_REG_OFFSET(st->chip_info->chan_map[ch]);
+}
+
+static unsigned int ad7768_gain_reg(const struct ad7768_state *st,
+ unsigned int ch)
+{
+ return AD7768_REG_GAIN(st->chip_info->chan_map[ch]);
+}
+
+static unsigned int ad7768_phase_reg(const struct ad7768_state *st,
+ unsigned int ch)
+{
+ return AD7768_REG_PHASE(st->chip_info->chan_map[ch]);
+}
+
+static u8 ad7768_precharge_buf1_mask(const struct ad7768_state *st, u16 val)
+{
+ return val & GENMASK(st->chip_info->prebuf_split - 1, 0);
+}
+
+static u8 ad7768_precharge_buf2_mask(const struct ad7768_state *st, u16 val)
+{
+ unsigned int split = st->chip_info->prebuf_split;
+
+ return field_get(GENMASK(2 * split - 1, split), val);
+}
+
+static int ad7768_regmap_read(void *context, const void *reg_buf,
+ size_t reg_size, void *val_buf, size_t val_size)
+{
+ struct ad7768_state *st = spi_get_drvdata(context);
+ struct spi_device *spi = context;
+ struct spi_transfer t[] = {
+ {
+ .tx_buf = &st->d16,
+ .len = sizeof(st->d16),
+ .cs_change = 1,
+ }, {
+ /*
+ * Register responses are delayed by one CS frame. While
+ * receiving the response to this read, the device also
+ * decodes another command on SDI. Repeat the read
+ * command to avoid sending an unspecified dummy
+ * command.
+ */
+ .tx_buf = &st->d16,
+ .rx_buf = &st->d16,
+ .len = sizeof(st->d16),
+ },
+ };
+ u8 *data_val = val_buf;
+ unsigned int reg;
+ int ret;
+
+ reg = *(const u8 *)reg_buf;
+
+ st->d16 = be16_replace_bits(cpu_to_be16(AD7768_SPI_READ_CMD), reg,
+ AD7768_SPI_REG_MASK);
+
+ ret = spi_sync_transfer(spi, t, ARRAY_SIZE(t));
+ if (ret)
+ return ret;
+
+ *data_val = be16_get_bits(st->d16, AD7768_SPI_DATA_MASK);
+
+ return 0;
+}
+
+static int ad7768_regmap_write(void *spi, const void *data, size_t count)
+{
+ return spi_write(spi, data, count);
+}
+
+static const struct regmap_bus ad7768_regmap_bus = {
+ .read = ad7768_regmap_read,
+ .write = ad7768_regmap_write,
+ .reg_format_endian_default = REGMAP_ENDIAN_BIG,
+ .val_format_endian_default = REGMAP_ENDIAN_BIG,
+};
+
+static bool ad7768_readable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case AD7768_REG_CH_STANDBY ... AD7768_REG_REV_ID:
+ case AD7768_REG_GPIO_CONTROL ... AD7768_REG_REFN_BUF:
+ case AD7768_REG_OFFSET(0) ... AD7768_REG_OFFSET(7) + 2:
+ case AD7768_REG_GAIN(0) ... AD7768_REG_GAIN(7) + 2:
+ case AD7768_REG_PHASE(0) ... AD7768_REG_PHASE(7):
+ case AD7768_REG_DIAGNOSTIC_RX ... AD7768_REG_CHOP_CTRL:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool ad7768_4_readable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case AD7768_REG_CH_STANDBY ... AD7768_REG_REV_ID:
+ case AD7768_REG_GPIO_CONTROL ... AD7768_REG_REFN_BUF:
+ case AD7768_REG_OFFSET(0) ... AD7768_REG_OFFSET(1) + 2:
+ case AD7768_REG_OFFSET(4) ... AD7768_REG_OFFSET(5) + 2:
+ case AD7768_REG_GAIN(0) ... AD7768_REG_GAIN(1) + 2:
+ case AD7768_REG_GAIN(4) ... AD7768_REG_GAIN(5) + 2:
+ case AD7768_REG_PHASE(0) ... AD7768_REG_PHASE(1):
+ case AD7768_REG_PHASE(4) ... AD7768_REG_PHASE(5):
+ case AD7768_REG_DIAGNOSTIC_RX ... AD7768_REG_CHOP_CTRL:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config ad7768_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = AD7768_REG_CHOP_CTRL,
+ /*
+ * Regmap bulk transfers use one starting address, while each register
+ * access requires a separate 16-bit SPI frame and reads use an off-frame
+ * response. Split bulk transfers into individual register accesses.
+ */
+ .use_single_read = true,
+ .use_single_write = true,
+ .readable_reg = ad7768_readable_reg,
+};
+
+static const struct regmap_config ad7768_4_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = AD7768_REG_CHOP_CTRL,
+ /*
+ * Regmap bulk transfers use one starting address, while each register
+ * access requires a separate 16-bit SPI frame and reads use an off-frame
+ * response. Split bulk transfers into individual register accesses. Do
+ * not use a register cache because some readable registers report live
+ * hardware state.
+ */
+ .use_single_read = true,
+ .use_single_write = true,
+ .readable_reg = ad7768_4_readable_reg,
+};
+
+static unsigned int ad7768_get_calib_reg_base(struct ad7768_state *st,
+ const struct iio_chan_spec *chan,
+ bool is_gain)
+{
+ if (is_gain)
+ return ad7768_gain_reg(st, chan->channel);
+
+ return ad7768_offset_reg(st, chan->channel);
+}
+
+static int ad7768_read_calib_value(struct ad7768_state *st,
+ unsigned int base_reg, bool is_signed,
+ int *val)
+{
+ unsigned int regval;
+ u8 data[3];
+ int ret;
+
+ PM_RUNTIME_ACQUIRE_AUTOSUSPEND(regmap_get_device(st->regmap), pm);
+ ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+ if (ret)
+ return ret;
+
+ guard(mutex)(&st->lock);
+
+ ret = regmap_bulk_read(st->regmap, base_reg, data, sizeof(data));
+ if (ret)
+ return ret;
+
+ regval = get_unaligned_be24(data);
+ *val = is_signed ? sign_extend32(regval, AD7768_CALIB_SIGN_BIT) : regval;
+
+ return 0;
+}
+
+static int ad7768_write_calib_value(struct ad7768_state *st,
+ unsigned int base_reg, bool is_signed,
+ int val)
+{
+ u8 data[3];
+ int ret;
+
+ if (is_signed &&
+ val != sign_extend32(val, AD7768_CALIB_SIGN_BIT))
+ return -EINVAL;
+
+ if (!is_signed && (val < 0 || val > AD7768_CALIB_REG_MSK))
+ return -EINVAL;
+
+ put_unaligned_be24(val, data);
+
+ PM_RUNTIME_ACQUIRE_AUTOSUSPEND(regmap_get_device(st->regmap), pm);
+ ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+ if (ret)
+ return ret;
+
+ guard(mutex)(&st->lock);
+
+ return regmap_bulk_write(st->regmap, base_reg, data, sizeof(data));
+}
+
+static int ad7768_reg_access(struct iio_dev *indio_dev,
+ unsigned int reg,
+ unsigned int writeval,
+ unsigned int *readval)
+{
+ struct ad7768_state *st = iio_priv(indio_dev);
+ int ret;
+
+ PM_RUNTIME_ACQUIRE_AUTOSUSPEND(regmap_get_device(st->regmap), pm);
+ ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+ if (ret)
+ return ret;
+
+ if (readval)
+ return regmap_read(st->regmap, reg, readval);
+
+ return regmap_write(st->regmap, reg, writeval);
+}
+
+static int ad7768_sync(struct ad7768_state *st)
+{
+ int ret;
+
+ ret = regmap_clear_bits(st->regmap, AD7768_REG_DATA_CONTROL,
+ AD7768_DATA_CONTROL_SPI_SYNC);
+ if (ret)
+ return ret;
+
+ return regmap_set_bits(st->regmap, AD7768_REG_DATA_CONTROL,
+ AD7768_DATA_CONTROL_SPI_SYNC);
+}
+
+static int ad7768_set_power_mode(struct ad7768_state *st,
+ unsigned int mode_idx)
+{
+ const struct ad7768_power_mode_info *mode_info;
+ int ret;
+
+ mode_info = &ad7768_power_modes[mode_idx];
+ ret = regmap_update_bits(st->regmap, AD7768_REG_POWER_MODE,
+ AD7768_POWER_MODE_POWER_MODE_MSK |
+ AD7768_POWER_MODE_MCLK_DIV_MSK,
+ FIELD_PREP(AD7768_POWER_MODE_POWER_MODE_MSK,
+ mode_info->mode) |
+ FIELD_PREP(AD7768_POWER_MODE_MCLK_DIV_MSK,
+ mode_info->mode));
+ if (ret)
+ return ret;
+
+ ret = ad7768_sync(st);
+ if (ret)
+ return ret;
+
+ st->power_mode_idx = mode_idx;
+
+ return 0;
+}
+
+static const struct ad7768_freq_config *
+ad7768_find_freq_config(const struct ad7768_state *st,
+ unsigned int mode_idx, unsigned int freq)
+{
+ const struct ad7768_avail_freq *avail_freq = &st->avail_freq[mode_idx];
+
+ for (unsigned int i = 0; i < avail_freq->n_freqs; i++) {
+ if (freq == avail_freq->freq_cfg[i].freq_hz)
+ return &avail_freq->freq_cfg[i];
+ }
+
+ return NULL;
+}
+
+static int ad7768_set_clk_divs(struct ad7768_state *st, unsigned int freq)
+{
+ const struct ad7768_freq_config *freq_cfg;
+ unsigned int mclk, dclk, dclk_div;
+ unsigned int chan_per_doutx;
+ unsigned int dclk_div_reg;
+
+ freq_cfg = ad7768_find_freq_config(st, st->power_mode_idx, freq);
+ if (!freq_cfg)
+ return -EINVAL;
+
+ mclk = clk_get_rate(st->mclk);
+ chan_per_doutx = st->chip_info->num_channels / st->datalines;
+ if (!chan_per_doutx)
+ return -EINVAL;
+
+ dclk = freq_cfg->freq_hz * AD7768_SAMPLE_SIZE * chan_per_doutx;
+ if (dclk > mclk)
+ return -EINVAL;
+
+ dclk_div = DIV_ROUND_CLOSEST(mclk, dclk);
+
+ /* Set the divider to the next-lowest supported power of two. */
+ dclk_div = rounddown_pow_of_two(min(dclk_div, AD7768_MAX_DCLK_DIV));
+
+ switch (dclk_div) {
+ case 1:
+ dclk_div_reg = AD7768_INTERFACE_CFG_DCLK_DIV_1;
+ break;
+ case 2:
+ dclk_div_reg = AD7768_INTERFACE_CFG_DCLK_DIV_2;
+ break;
+ case 4:
+ dclk_div_reg = AD7768_INTERFACE_CFG_DCLK_DIV_4;
+ break;
+ case 8:
+ dclk_div_reg = AD7768_INTERFACE_CFG_DCLK_DIV_8;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return regmap_update_bits(st->regmap, AD7768_REG_INTERFACE_CFG,
+ AD7768_INTERFACE_CFG_DCLK_DIV_MSK,
+ FIELD_PREP(AD7768_INTERFACE_CFG_DCLK_DIV_MSK,
+ dclk_div_reg));
+}
+
+static int ad7768_set_mode_decimation(struct ad7768_state *st,
+ unsigned int freq, unsigned int mode)
+{
+ const struct ad7768_freq_config *freq_cfg;
+
+ freq_cfg = ad7768_find_freq_config(st, st->power_mode_idx, freq);
+ if (!freq_cfg)
+ return -EINVAL;
+
+ return regmap_update_bits(st->regmap, AD7768_REG_CH_MODE(mode),
+ AD7768_CH_MODE_DEC_RATE_MSK,
+ FIELD_PREP(AD7768_CH_MODE_DEC_RATE_MSK,
+ freq_cfg->dec_rate));
+}
+
+static int ad7768_set_lowest_noise_mode(struct ad7768_state *st,
+ const unsigned long *scan_mask)
+{
+ unsigned int mode_idx = ARRAY_SIZE(ad7768_power_modes);
+
+ /*
+ * The output data rate ranges overlap between the power modes. At a
+ * common ODR, the faster mode has lower noise, so prefer the fastest
+ * mode that supports every enabled channel.
+ */
+ while (mode_idx--) {
+ unsigned int channel;
+
+ for_each_set_bit(channel, scan_mask, st->chip_info->num_channels) {
+ if (!ad7768_find_freq_config(st, mode_idx,
+ st->ch_freq[channel]))
+ break;
+ }
+
+ /* All enabled channels support their requested frequency. */
+ if (channel == st->chip_info->num_channels)
+ return ad7768_set_power_mode(st, mode_idx);
+ }
+
+ return -EINVAL;
+}
+
+static bool ad7768_freq_supported_in_any_mode(const struct ad7768_state *st,
+ unsigned int freq)
+{
+ for (unsigned int mode_idx = 0;
+ mode_idx < ARRAY_SIZE(ad7768_power_modes); mode_idx++) {
+ if (ad7768_find_freq_config(st, mode_idx, freq))
+ return true;
+ }
+
+ return false;
+}
+
+static int ad7768_set_sampling_freq(struct iio_dev *indio_dev,
+ unsigned int freq, unsigned int channel)
+{
+ struct ad7768_state *st = iio_priv(indio_dev);
+
+ if (!freq || !ad7768_freq_supported_in_any_mode(st, freq))
+ return -EINVAL;
+
+ guard(mutex)(&st->lock);
+ st->ch_freq[channel] = freq;
+
+ return 0;
+}
+
+static int ad7768_set_filter_mode(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ unsigned int mode)
+{
+ struct ad7768_state *st = iio_priv(indio_dev);
+
+ IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim);
+ if (IIO_DEV_ACQUIRE_FAILED(claim))
+ return -EBUSY;
+
+ guard(mutex)(&st->lock);
+ st->ch_filter[chan->channel] = mode;
+
+ return 0;
+}
+
+static int ad7768_get_filter_mode(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan)
+{
+ struct ad7768_state *st = iio_priv(indio_dev);
+
+ guard(mutex)(&st->lock);
+
+ return st->ch_filter[chan->channel];
+}
+
+static const char *const ad7768_filter_types[] = {
+ [AD7768_FILTER_TYPE_WIDEBAND] = "wideband",
+ [AD7768_FILTER_TYPE_SINC5] = "sinc5",
+};
+
+static const struct iio_enum ad7768_filter_types_enum = {
+ .items = ad7768_filter_types,
+ .num_items = ARRAY_SIZE(ad7768_filter_types),
+ .set = ad7768_set_filter_mode,
+ .get = ad7768_get_filter_mode,
+};
+
+static struct iio_chan_spec_ext_info ad7768_ext_info[] = {
+ IIO_ENUM("filter_type", IIO_SEPARATE, &ad7768_filter_types_enum),
+ IIO_ENUM_AVAILABLE("filter_type", IIO_SEPARATE, &ad7768_filter_types_enum),
+ { }
+};
+
+static int ad7768_find_matching_mode(const bool *mode_used,
+ const unsigned int *mode_freq,
+ const enum ad7768_filter_type *mode_filter,
+ unsigned int freq,
+ enum ad7768_filter_type filter)
+{
+ for (unsigned int mode = 0; mode < AD7768_NUM_CHANNEL_MODES; mode++) {
+ if (!mode_used[mode] ||
+ (mode_freq[mode] == freq && mode_filter[mode] == filter))
+ return mode;
+ }
+
+ return -EINVAL;
+}
+
+static int ad7768_get_convdelay_params(struct ad7768_state *st, unsigned int ch,
+ struct ad7768_convdelay_params *params)
+{
+ const struct ad7768_freq_config *freq_cfg;
+ unsigned int dec_rate;
+ unsigned int mclk_div;
+ unsigned long mclk;
+ u64 mult;
+
+ freq_cfg = ad7768_find_freq_config(st, st->power_mode_idx,
+ st->ch_freq[ch]);
+ if (!freq_cfg)
+ return -EINVAL;
+
+ dec_rate = ad7768_dec_rate[freq_cfg->dec_rate];
+ switch (dec_rate) {
+ case 32:
+ params->shift = 3;
+ params->max_raw = 31;
+ mult = 1;
+ break;
+ case 64:
+ params->shift = 2;
+ params->max_raw = 63;
+ mult = 1;
+ break;
+ case 128:
+ params->shift = 1;
+ params->max_raw = 127;
+ mult = 1;
+ break;
+ case 256:
+ params->shift = 0;
+ params->max_raw = 255;
+ mult = 1;
+ break;
+ case 512:
+ params->shift = 0;
+ params->max_raw = 255;
+ mult = 2;
+ break;
+ case 1024:
+ params->shift = 0;
+ params->max_raw = 255;
+ mult = 4;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ mclk = clk_get_rate(st->mclk);
+ if (!mclk || mclk > U32_MAX)
+ return -EINVAL;
+
+ mclk_div = ad7768_power_modes[st->power_mode_idx].mclk_div;
+ params->step_ps =
+ DIV_ROUND_CLOSEST_ULL(mult * PSEC_PER_SEC * mclk_div, (u32)mclk);
+ if (params->step_ps > U32_MAX)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int ad7768_set_channel_convdelay(struct ad7768_state *st,
+ unsigned int ch)
+{
+ u64 delay_ps = st->ch_convdelay_ps[ch];
+ struct ad7768_convdelay_params params;
+ u64 max_delay_ps;
+ u64 raw;
+ int ret;
+
+ ret = ad7768_get_convdelay_params(st, ch, ¶ms);
+ if (ret)
+ return ret;
+
+ /*
+ * Validate the requested delay before rounding so an out-of-range value
+ * cannot round down into the valid range. Then verify that the rounded
+ * value fits in the hardware register.
+ */
+ max_delay_ps = (u64)params.max_raw * params.step_ps;
+ if (delay_ps > max_delay_ps)
+ return -EINVAL;
+
+ raw = DIV_ROUND_CLOSEST_ULL(delay_ps, (u32)params.step_ps);
+ if (raw > params.max_raw)
+ return -EINVAL;
+
+ return regmap_write(st->regmap, ad7768_phase_reg(st, ch),
+ raw << params.shift);
+}
+
+static void ad7768_filter_wait(const unsigned int *mode_freq,
+ const enum ad7768_filter_type *mode_filter,
+ const bool *mode_used)
+{
+ unsigned int t_settle_us = 0;
+
+ for (unsigned int mode = 0; mode < AD7768_NUM_CHANNEL_MODES; mode++) {
+ unsigned int t_mode_us;
+ u8 settling_samples;
+
+ if (!mode_used[mode] || !mode_freq[mode])
+ continue;
+
+ if (mode_filter[mode] == AD7768_FILTER_TYPE_SINC5)
+ settling_samples = AD7768_SINC5_SETTLING_SAMPLES;
+ else
+ settling_samples = AD7768_WIDEBAND_SETTLING_SAMPLES;
+
+ t_mode_us = DIV_ROUND_UP(settling_samples * USEC_PER_SEC,
+ mode_freq[mode]);
+ t_settle_us = max(t_settle_us, t_mode_us);
+ }
+
+ if (t_settle_us)
+ fsleep(t_settle_us);
+}
+
+static int ad7768_apply_channel_modes(struct iio_dev *indio_dev,
+ const unsigned long *scan_mask)
+{
+ enum ad7768_filter_type mode_filter[AD7768_NUM_CHANNEL_MODES] = { };
+ unsigned int mode_freq[AD7768_NUM_CHANNEL_MODES] = { };
+ bool mode_used[AD7768_NUM_CHANNEL_MODES] = { };
+ struct ad7768_state *st = iio_priv(indio_dev);
+ struct device *dev = indio_dev->dev.parent;
+ unsigned long channel_mask;
+ unsigned long standby_mask;
+ unsigned int max_freq;
+ unsigned int c;
+ int ret;
+
+ guard(mutex)(&st->lock);
+
+ ret = ad7768_set_lowest_noise_mode(st, scan_mask);
+ if (ret == -EINVAL)
+ return dev_err_probe(dev, ret,
+ "No power mode supports all ODRs\n");
+ if (ret)
+ return ret;
+
+ channel_mask = ad7768_all_standby_mask(st);
+ standby_mask = channel_mask & ~*scan_mask;
+ ad7768_keep_xtal_channel_active(st, &standby_mask);
+
+ for_each_set_bit(c, scan_mask, st->chip_info->num_channels) {
+ unsigned int mask;
+ int mode;
+
+ mode = ad7768_find_matching_mode(mode_used, mode_freq,
+ mode_filter, st->ch_freq[c],
+ st->ch_filter[c]);
+ if (mode < 0)
+ return dev_err_probe(dev, -EINVAL,
+ "Over %d channel modes required\n",
+ AD7768_NUM_CHANNEL_MODES);
+
+ mode_freq[mode] = st->ch_freq[c];
+ mode_filter[mode] = st->ch_filter[c];
+ mode_used[mode] = true;
+
+ mask = ad7768_channel_mode_mask(st, c);
+ ret = regmap_assign_bits(st->regmap, AD7768_REG_CH_MODE_SEL,
+ mask, mode);
+ if (ret)
+ return ret;
+ }
+
+ ret = regmap_update_bits(st->regmap, AD7768_REG_CH_STANDBY,
+ channel_mask, standby_mask);
+ if (ret)
+ return ret;
+
+ max_freq = 0;
+ for (unsigned int mode = 0; mode < AD7768_NUM_CHANNEL_MODES; mode++) {
+ if (!mode_used[mode])
+ continue;
+
+ ret = ad7768_set_mode_decimation(st, mode_freq[mode], mode);
+ if (ret)
+ return ret;
+
+ ret = regmap_assign_bits(st->regmap, AD7768_REG_CH_MODE(mode),
+ AD7768_CH_MODE_FILTER_TYPE_MSK,
+ mode_filter[mode]);
+ if (ret)
+ return ret;
+
+ max_freq = max(max_freq, mode_freq[mode]);
+ }
+
+ for_each_set_bit(c, scan_mask, st->chip_info->num_channels) {
+ ret = ad7768_set_channel_convdelay(st, c);
+ if (ret == -EINVAL)
+ return dev_err_probe(regmap_get_device(st->regmap), ret,
+ "Invalid conversion delay for channel %u\n",
+ c);
+ if (ret)
+ return ret;
+ }
+
+ ret = ad7768_set_clk_divs(st, max_freq);
+ if (ret)
+ return ret;
+
+ ret = ad7768_sync(st);
+ if (ret)
+ return ret;
+
+ /* Apply a filter settling time (datasheet Tables 28 and 29). */
+ ad7768_filter_wait(mode_freq, mode_filter, mode_used);
+
+ return 0;
+}
+
+static int ad7768_update_scan_mode(struct iio_dev *indio_dev,
+ const unsigned long *scan_mask)
+{
+ struct ad7768_state *st = iio_priv(indio_dev);
+ int ret;
+
+ ret = ad7768_apply_channel_modes(indio_dev, scan_mask);
+ if (ret)
+ return ret;
+
+ for (unsigned int ch = 0; ch < st->chip_info->num_channels; ch++) {
+ if (test_bit(ch, scan_mask))
+ ret = iio_backend_chan_enable(st->back, ch);
+ else
+ ret = iio_backend_chan_disable(st->back, ch);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct ad7768_chip_info ad7768_chip_info = {
+ .name = "ad7768",
+ .num_channels = 8,
+ .regmap_config = &ad7768_regmap_config,
+ .available_datalines = ad7768_available_datalines,
+ .num_datalines = ARRAY_SIZE(ad7768_available_datalines),
+ .chan_map = ad7768_chan_map,
+ .prebuf_split = 8,
+};
+
+static const struct ad7768_chip_info ad7768_4_chip_info = {
+ .name = "ad7768-4",
+ .num_channels = 4,
+ .regmap_config = &ad7768_4_regmap_config,
+ .available_datalines = ad7768_4_available_datalines,
+ .num_datalines = ARRAY_SIZE(ad7768_4_available_datalines),
+ .chan_map = ad7768_4_chan_map,
+ .prebuf_split = 4,
+};
+
+static int ad7768_buffer_preenable(struct iio_dev *indio_dev)
+{
+ struct ad7768_state *st = iio_priv(indio_dev);
+
+ return pm_runtime_resume_and_get(regmap_get_device(st->regmap));
+}
+
+static int ad7768_buffer_postdisable(struct iio_dev *indio_dev)
+{
+ struct ad7768_state *st = iio_priv(indio_dev);
+
+ pm_runtime_put_autosuspend(regmap_get_device(st->regmap));
+
+ return 0;
+}
+
+static const struct iio_buffer_setup_ops ad7768_buffer_ops = {
+ .preenable = ad7768_buffer_preenable,
+ .postdisable = ad7768_buffer_postdisable,
+};
+
+static int ad7768_read_scale(struct ad7768_state *st,
+ const struct iio_chan_spec *chan,
+ int *val, int *val2)
+{
+ unsigned int vref_idx;
+
+ vref_idx = chan->channel >= st->chip_info->num_channels / 2;
+ *val = 2 * st->vref_uV[vref_idx] / (MICRO / MILLI);
+ *val2 = chan->scan_type.realbits;
+
+ return IIO_VAL_FRACTIONAL_LOG2;
+}
+
+static int ad7768_read_raw(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ int *val, int *val2, long info)
+{
+ struct ad7768_state *st = iio_priv(indio_dev);
+ int ret;
+
+ switch (info) {
+ case IIO_CHAN_INFO_SCALE:
+ return ad7768_read_scale(st, chan, val, val2);
+ case IIO_CHAN_INFO_SAMP_FREQ: {
+ guard(mutex)(&st->lock);
+ *val = st->ch_freq[chan->channel];
+
+ return IIO_VAL_INT;
+ }
+
+ case IIO_CHAN_INFO_CALIBBIAS:
+ case IIO_CHAN_INFO_CALIBSCALE: {
+ bool is_gain = info == IIO_CHAN_INFO_CALIBSCALE;
+ unsigned int base_reg;
+
+ base_reg = ad7768_get_calib_reg_base(st, chan, is_gain);
+ ret = ad7768_read_calib_value(st, base_reg, !is_gain, val);
+ if (ret)
+ return ret;
+
+ return IIO_VAL_INT;
+ }
+ case IIO_CHAN_INFO_CONVDELAY: {
+ guard(mutex)(&st->lock);
+ iio_val_s64_decompose(st->ch_convdelay_ps[chan->channel],
+ val, val2);
+
+ return IIO_VAL_DECIMAL64_PICO;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad7768_write_raw_get_fmt(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, long info)
+{
+ switch (info) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ case IIO_CHAN_INFO_CALIBBIAS:
+ case IIO_CHAN_INFO_CALIBSCALE:
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_CONVDELAY:
+ return IIO_VAL_DECIMAL64_PICO;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad7768_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long info)
+{
+ struct ad7768_state *st = iio_priv(indio_dev);
+ unsigned int base_reg;
+ s64 delay_ps;
+
+ IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim);
+ if (IIO_DEV_ACQUIRE_FAILED(claim))
+ return -EBUSY;
+
+ switch (info) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ return ad7768_set_sampling_freq(indio_dev, val, chan->channel);
+ case IIO_CHAN_INFO_CALIBBIAS:
+ base_reg = ad7768_get_calib_reg_base(st, chan, false);
+ return ad7768_write_calib_value(st, base_reg, true, val);
+ case IIO_CHAN_INFO_CALIBSCALE:
+ base_reg = ad7768_get_calib_reg_base(st, chan, true);
+ return ad7768_write_calib_value(st, base_reg, false, val);
+ case IIO_CHAN_INFO_CONVDELAY: {
+ delay_ps = iio_val_s64_compose(val, val2);
+ if (delay_ps < 0)
+ return -EINVAL;
+
+ guard(mutex)(&st->lock);
+ st->ch_convdelay_ps[chan->channel] = delay_ps;
+ return 0;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad7768_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long info)
+{
+ struct ad7768_state *st = iio_priv(indio_dev);
+
+ if (info != IIO_CHAN_INFO_SAMP_FREQ)
+ return -EINVAL;
+
+ *vals = st->freqs;
+ *type = IIO_VAL_INT;
+ *length = st->n_freqs;
+
+ return IIO_AVAIL_LIST;
+}
+
+static const struct iio_info ad7768_info = {
+ .debugfs_reg_access = ad7768_reg_access,
+ .read_raw = ad7768_read_raw,
+ .write_raw_get_fmt = ad7768_write_raw_get_fmt,
+ .write_raw = ad7768_write_raw,
+ .read_avail = ad7768_read_avail,
+ .update_scan_mode = ad7768_update_scan_mode,
+};
+
+static int ad7768_gpio_adev_init(struct ad7768_state *st)
+{
+ struct device *dev = regmap_get_device(st->regmap);
+ struct spi_device *spi = to_spi_device(dev);
+ struct auxiliary_device *adev;
+ int id;
+
+ if (!device_property_read_bool(dev, "gpio-controller"))
+ return 0;
+
+ /*
+ * Use the SPI bus number and chip select to derive a stable per-device
+ * ID.
+ */
+ id = (spi->controller->bus_num << 8) | spi_get_chipselect(spi, 0);
+ adev = __devm_auxiliary_device_create(dev, KBUILD_MODNAME, "gpio",
+ NULL, id);
+ if (!adev)
+ return dev_err_probe(dev, -ENODEV,
+ "Failed to create GPIO auxiliary device\n");
+
+ return 0;
+}
+
+static int ad7768_configure_precharge_buffers(struct iio_dev *indio_dev,
+ struct ad7768_precharge_config *precharge_cfg)
+{
+ struct ad7768_state *st = iio_priv(indio_dev);
+ u8 prebuf1_val, prebuf2_val;
+ u16 prebuf_mask = 0;
+ u8 refbufp_val = 0;
+ u8 refbufn_val = 0;
+ int ret;
+
+ for (unsigned int ch = 0; ch < indio_dev->num_channels; ch++) {
+ u8 channel = indio_dev->channels[ch].channel;
+
+ if (precharge_cfg[channel].prebufp_en)
+ prebuf_mask |= AD7768_PREBUF_POS_EN(channel);
+
+ if (precharge_cfg[channel].prebufn_en)
+ prebuf_mask |= AD7768_PREBUF_NEG_EN(channel);
+
+ if (precharge_cfg[channel].refbufp)
+ refbufp_val |= ad7768_channel_mask(st, channel);
+
+ if (precharge_cfg[channel].refbufn)
+ refbufn_val |= ad7768_channel_mask(st, channel);
+ }
+
+ prebuf1_val = ad7768_precharge_buf1_mask(st, ~prebuf_mask);
+ prebuf2_val = ad7768_precharge_buf2_mask(st, ~prebuf_mask);
+
+ ret = regmap_write(st->regmap, AD7768_REG_PRECHARGE_BUF1, prebuf1_val);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(st->regmap, AD7768_REG_PRECHARGE_BUF2, prebuf2_val);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(st->regmap, AD7768_REG_REFP_BUF, refbufp_val);
+ if (ret)
+ return ret;
+
+ return regmap_write(st->regmap, AD7768_REG_REFN_BUF, refbufn_val);
+}
+
+static void ad7768_set_available_sampling_freqs(struct ad7768_state *st)
+{
+ unsigned int n_power_modes = ARRAY_SIZE(ad7768_power_modes);
+ unsigned int mclk = clk_get_rate(st->mclk);
+
+ for (unsigned int mode_idx = 0; mode_idx < n_power_modes; mode_idx++) {
+ unsigned int dec = ARRAY_SIZE(ad7768_dec_rate);
+ struct ad7768_avail_freq *avail_freq;
+ unsigned int div;
+
+ avail_freq = &st->avail_freq[mode_idx];
+ div = ad7768_power_modes[mode_idx].mclk_div;
+ while (dec--) {
+ struct ad7768_freq_config *freq_cfg;
+
+ freq_cfg = &avail_freq->freq_cfg[avail_freq->n_freqs++];
+ freq_cfg->dec_rate = dec;
+ freq_cfg->freq_hz = mclk / (ad7768_dec_rate[dec] * div);
+ }
+ }
+
+ /* One DOUT line cannot carry the AD7768 fast-mode x32 output rate. */
+ if (st->datalines == 1 &&
+ st->chip_info->num_channels == AD7768_MAX_CHANNEL)
+ st->avail_freq[n_power_modes - 1].n_freqs--;
+
+ for (unsigned int mode_idx = 0; mode_idx < n_power_modes; mode_idx++) {
+ const struct ad7768_avail_freq *avail_freq;
+
+ avail_freq = &st->avail_freq[mode_idx];
+ for (unsigned int i = 0; i < avail_freq->n_freqs; i++) {
+ unsigned int freq = avail_freq->freq_cfg[i].freq_hz;
+
+ if (st->n_freqs && st->freqs[st->n_freqs - 1] >= freq)
+ continue;
+
+ st->freqs[st->n_freqs++] = freq;
+ }
+ }
+}
+
+static int ad7768_init_sampling_freqs(struct ad7768_state *st)
+{
+ const struct ad7768_avail_freq *avail_freq;
+ unsigned int default_freq;
+ int ret;
+
+ ret = ad7768_set_power_mode(st, ARRAY_SIZE(ad7768_power_modes) - 1);
+ if (ret)
+ return ret;
+
+ avail_freq = &st->avail_freq[st->power_mode_idx];
+ default_freq = avail_freq->freq_cfg[avail_freq->n_freqs - 1].freq_hz;
+ for (unsigned int channel = 0;
+ channel < st->chip_info->num_channels; channel++) {
+ st->ch_freq[channel] = default_freq;
+ st->ch_filter[channel] = AD7768_FILTER_TYPE_WIDEBAND;
+ }
+
+ return 0;
+}
+
+static int ad7768_parse_config(struct iio_dev *indio_dev,
+ struct device *dev)
+{
+ struct ad7768_precharge_config precharge_cfg[AD7768_MAX_CHANNEL] = { };
+ struct ad7768_state *st = iio_priv(indio_dev);
+ const unsigned int *available_datalines;
+ const char *propname;
+ bool datalines_valid = false;
+ struct iio_chan_spec *chan;
+ unsigned int num_channels;
+ unsigned long standby_mask;
+ unsigned int len;
+ int chan_idx = 0;
+ int ret;
+
+ propname = "adi,data-lines-number";
+ num_channels = device_get_named_child_node_count(dev, "channel");
+ if (num_channels == 0)
+ return dev_err_probe(dev, -ENOENT, "No channel specified\n");
+ if (num_channels > st->chip_info->num_channels)
+ return dev_err_probe(dev, -ENOSPC, "Invalid number of channels\n");
+
+ chan = devm_kcalloc(dev, num_channels, sizeof(*chan), GFP_KERNEL);
+ if (!chan)
+ return -ENOMEM;
+
+ indio_dev->channels = chan;
+ indio_dev->num_channels = num_channels;
+
+ standby_mask = ad7768_all_standby_mask(st);
+ ad7768_keep_xtal_channel_active(st, &standby_mask);
+
+ ret = regmap_write(st->regmap, AD7768_REG_CH_STANDBY, standby_mask);
+ if (ret)
+ return ret;
+
+ device_for_each_named_child_node_scoped(dev, child, "channel") {
+ u32 channel;
+
+ ret = fwnode_property_read_u32(child, "reg", &channel);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to parse reg of %pfwP\n",
+ child);
+
+ if (channel >= st->chip_info->num_channels)
+ return dev_err_probe(dev, -ECHRNG,
+ "Invalid channel %u in firmware\n",
+ channel);
+
+ ret = regmap_clear_bits(st->regmap, AD7768_REG_CH_STANDBY,
+ BIT(channel));
+ if (ret)
+ return ret;
+
+ precharge_cfg[channel].prebufp_en =
+ fwnode_property_read_bool(child, "adi,prechargebuf-pos-enable");
+ precharge_cfg[channel].prebufn_en =
+ fwnode_property_read_bool(child, "adi,prechargebuf-neg-enable");
+ precharge_cfg[channel].refbufp =
+ fwnode_property_read_bool(child, "adi,refbuf-pos-enable");
+ precharge_cfg[channel].refbufn =
+ fwnode_property_read_bool(child, "adi,refbuf-neg-enable");
+
+ chan[chan_idx++] = (struct iio_chan_spec) {
+ .type = IIO_VOLTAGE,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_CALIBBIAS) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE) |
+ BIT(IIO_CHAN_INFO_CONVDELAY) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ .info_mask_separate_available =
+ BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ .indexed = 1,
+ .channel = channel,
+ .scan_index = channel,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 24,
+ .storagebits = 32,
+ },
+ .ext_info = ad7768_ext_info,
+ };
+ }
+
+ ret = ad7768_configure_precharge_buffers(indio_dev, precharge_cfg);
+ if (ret)
+ return ret;
+
+ available_datalines = st->chip_info->available_datalines;
+ len = st->chip_info->num_datalines;
+ if (device_property_present(dev, propname)) {
+ ret = device_property_read_u32(dev, propname, &st->datalines);
+ if (ret)
+ return dev_err_probe(dev, ret, "Invalid %s property\n",
+ propname);
+ } else {
+ st->datalines = available_datalines[len - 1];
+ }
+
+ for (unsigned int i = 0; i < len; i++) {
+ if (available_datalines[i] == st->datalines) {
+ datalines_valid = true;
+ break;
+ }
+ }
+
+ if (!datalines_valid)
+ return dev_err_probe(dev, -EINVAL,
+ "Invalid %s %u for %s\n", propname,
+ st->datalines, st->chip_info->name);
+
+ ad7768_set_available_sampling_freqs(st);
+
+ ret = ad7768_init_sampling_freqs(st);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to set power mode\n");
+
+ return 0;
+}
+
+static int ad7768_reset(struct ad7768_state *st)
+{
+ struct device *dev = regmap_get_device(st->regmap);
+ struct reset_control *reset_ctrl;
+ unsigned long reset_low_us;
+ unsigned long mclk;
+ int ret;
+
+ reset_ctrl = devm_reset_control_get_optional_exclusive(dev, NULL);
+ if (IS_ERR(reset_ctrl))
+ return PTR_ERR(reset_ctrl);
+
+ if (reset_ctrl) {
+ mclk = clk_get_rate(st->mclk);
+ if (!mclk)
+ return -EINVAL;
+
+ /*
+ * Minimum RESET low pulse width: 2 x tMCLK
+ * (datasheet Table 1).
+ */
+ reset_low_us = DIV_ROUND_UP_ULL(2ULL * USEC_PER_SEC, mclk);
+
+ ret = reset_control_assert(reset_ctrl);
+ if (ret)
+ return ret;
+
+ fsleep(max(1UL, reset_low_us));
+
+ ret = reset_control_deassert(reset_ctrl);
+ if (ret)
+ return ret;
+ } else {
+ ret = regmap_write(st->regmap, AD7768_REG_DATA_CONTROL,
+ AD7768_DATA_CONTROL_SPI_RESET_1);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(st->regmap, AD7768_REG_DATA_CONTROL,
+ AD7768_DATA_CONTROL_SPI_RESET_2);
+ if (ret)
+ return ret;
+ }
+
+ /* ADC start-up time after reset: 1.66 ms max (datasheet Table 1) */
+ fsleep(1660);
+
+ return 0;
+}
+
+static void ad7768_disable_clk(void *clk)
+{
+ clk_disable_unprepare(clk);
+}
+
+static int ad7768_configure_xtal_clock(struct ad7768_state *st)
+{
+ int ret;
+
+ ret = regmap_set_bits(st->regmap, AD7768_REG_GPIO_WRITE, BIT(4));
+ if (ret)
+ return ret;
+
+ return regmap_set_bits(st->regmap, AD7768_REG_GPIO_CONTROL,
+ AD7768_GPIO_UGPIO_ENABLE |
+ AD7768_GPIO4_OUTPUT_ENABLE);
+}
+
+static int ad7768_enable_lvds_clock(struct ad7768_state *st)
+{
+ struct device *dev = regmap_get_device(st->regmap);
+ int ret;
+
+ ret = regmap_clear_bits(st->regmap, AD7768_REG_GPIO_WRITE, BIT(4));
+ if (ret)
+ return ret;
+
+ ret = regmap_set_bits(st->regmap, AD7768_REG_GPIO_CONTROL,
+ AD7768_GPIO_UGPIO_ENABLE |
+ AD7768_GPIO4_OUTPUT_ENABLE);
+ if (ret)
+ return ret;
+
+ ret = regmap_set_bits(st->regmap, AD7768_REG_POWER_MODE,
+ AD7768_POWER_MODE_LVDS_ENABLE);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(st->mclk);
+ if (ret)
+ return ret;
+
+ return devm_add_action_or_reset(dev, ad7768_disable_clk, st->mclk);
+}
+
+static int ad7768_get_enable_vref(struct device *dev, unsigned int index)
+{
+ const char * const *supply = ad7768_vref_supply_names[index];
+ int refp_uV;
+ int refn_uV;
+
+ refp_uV = devm_regulator_get_enable_read_voltage(dev, supply[0]);
+ if (refp_uV < 0)
+ return dev_err_probe(dev, refp_uV,
+ "Failed to get %s supply voltage\n", supply[0]);
+
+ refn_uV = devm_regulator_get_enable_read_voltage(dev, supply[1]);
+ if (refn_uV == -ENODEV)
+ refn_uV = 0;
+ else if (refn_uV < 0)
+ return dev_err_probe(dev, refn_uV,
+ "Failed to get %s supply voltage\n", supply[1]);
+
+ if (refp_uV <= refn_uV)
+ return dev_err_probe(dev, -EINVAL,
+ "Invalid reference %u voltage\n", index + 1);
+
+ return refp_uV - refn_uV;
+}
+
+static int ad7768_enter_sleep(struct ad7768_state *st)
+{
+ return regmap_set_bits(st->regmap, AD7768_REG_POWER_MODE,
+ AD7768_SLEEP_MODE_MSK);
+}
+
+static void ad7768_power_off(void *data)
+{
+ struct ad7768_state *st = data;
+ struct device *dev = regmap_get_device(st->regmap);
+ int ret;
+
+ ret = ad7768_enter_sleep(st);
+ if (ret)
+ dev_err(dev, "Failed to put device to sleep\n");
+}
+
+static int ad7768_validate_mclk_rate(struct device *dev,
+ const struct ad7768_state *st)
+{
+ unsigned long min_rate = AD7768_MIN_MCLK_FREQ_HZ;
+ unsigned long rate = clk_get_rate(st->mclk);
+
+ if (st->clock_source == AD7768_CLOCK_SOURCE_XTAL)
+ min_rate = AD7768_MIN_XTAL_FREQ_HZ;
+
+ if (rate < min_rate || rate > AD7768_MAX_MCLK_FREQ_HZ)
+ return dev_err_probe(dev, -EINVAL,
+ "MCLK rate %lu Hz outside %lu-%lu Hz\n",
+ rate, min_rate, AD7768_MAX_MCLK_FREQ_HZ);
+
+ return 0;
+}
+
+static int ad7768_probe(struct spi_device *spi)
+{
+ unsigned int spi_readback, rev_id;
+ struct device *dev = &spi->dev;
+ struct iio_dev *indio_dev;
+ struct ad7768_state *st;
+ const char *clock_name;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+ spi_set_drvdata(spi, st);
+
+ ret = devm_mutex_init(dev, &st->lock);
+ if (ret)
+ return ret;
+
+ st->chip_info = spi_get_device_match_data(spi);
+ if (!st->chip_info)
+ return dev_err_probe(dev, -ENODATA, "Failed to get match data\n");
+
+ ret = devm_regulator_get_enable_optional(dev, "avss");
+ if (ret == -ENODEV) {
+ /* AVSS may be connected directly to ground instead of a regulator. */
+ } else if (ret) {
+ return dev_err_probe(dev, ret, "Failed to enable AVSS supply\n");
+ }
+
+ ret = devm_regulator_get_enable_read_voltage(dev, "avdd1");
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "Failed to enable AVDD1 supply\n");
+
+ st->avdd1_uV = ret;
+
+ ret = devm_regulator_bulk_get_enable(dev,
+ ARRAY_SIZE(ad7768_supply_names),
+ ad7768_supply_names);
+ if (ret)
+ return ret;
+
+ for (unsigned int i = 0; i < ARRAY_SIZE(ad7768_vref_supply_names); i++) {
+ ret = ad7768_get_enable_vref(dev, i);
+ if (ret < 0)
+ return ret;
+
+ st->vref_uV[i] = ret;
+ }
+
+ ret = device_property_match_property_string(dev, "clock-names",
+ ad7768_clock_names,
+ ARRAY_SIZE(ad7768_clock_names));
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Invalid clock source\n");
+
+ st->clock_source = ret;
+ clock_name = ad7768_clock_names[st->clock_source];
+
+ /*
+ * The device must start on its internal clock. Keep the LVDS clock
+ * disabled until GPIO4 is driven low and the LVDS input is enabled in
+ * the power mode register.
+ */
+ switch (st->clock_source) {
+ case AD7768_CLOCK_SOURCE_MCLK:
+ case AD7768_CLOCK_SOURCE_XTAL:
+ st->mclk = devm_clk_get_enabled(dev, clock_name);
+ break;
+ case AD7768_CLOCK_SOURCE_LVDS:
+ st->mclk = devm_clk_get(dev, clock_name);
+ break;
+ }
+
+ if (IS_ERR(st->mclk))
+ return dev_err_probe(dev, PTR_ERR(st->mclk),
+ "Failed to get master clock\n");
+
+ ret = ad7768_validate_mclk_rate(dev, st);
+ if (ret)
+ return ret;
+
+ st->regmap = devm_regmap_init(dev, &ad7768_regmap_bus, spi,
+ st->chip_info->regmap_config);
+ if (IS_ERR(st->regmap))
+ return PTR_ERR(st->regmap);
+
+ ret = ad7768_reset(st);
+ if (ret)
+ return ret;
+
+ /* Discard the reset response with a dummy SPI register read. */
+ ret = regmap_read(st->regmap, AD7768_REG_REV_ID, &spi_readback);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(st->regmap, AD7768_REG_REV_ID, &rev_id);
+ if (ret)
+ return ret;
+
+ if (rev_id != AD7768_REV_ID_VAL)
+ dev_info(dev, "Unexpected revision ID 0x%02x\n", rev_id);
+
+ switch (st->clock_source) {
+ case AD7768_CLOCK_SOURCE_MCLK:
+ break;
+ case AD7768_CLOCK_SOURCE_XTAL:
+ ret = ad7768_configure_xtal_clock(st);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to configure crystal clock\n");
+ break;
+ case AD7768_CLOCK_SOURCE_LVDS:
+ ret = ad7768_enable_lvds_clock(st);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to enable LVDS clock\n");
+ break;
+ }
+
+ ret = devm_add_action_or_reset(dev, ad7768_power_off, st);
+ if (ret)
+ return ret;
+
+ ret = ad7768_parse_config(indio_dev, dev);
+ if (ret)
+ return ret;
+
+ /*
+ * Hardware supports CRC every 4 or 16 samples; the backend supports only
+ * 4-sample CRC.
+ */
+ ret = regmap_update_bits(st->regmap, AD7768_REG_INTERFACE_CFG,
+ AD7768_INTERFACE_CFG_CRC_SELECT_MSK,
+ FIELD_PREP(AD7768_INTERFACE_CFG_CRC_SELECT_MSK,
+ AD7768_INTERFACE_CFG_CRC_SELECT_4));
+ if (ret)
+ return ret;
+
+ indio_dev->name = st->chip_info->name;
+ indio_dev->info = &ad7768_info;
+ indio_dev->setup_ops = &ad7768_buffer_ops;
+
+ st->back = devm_iio_backend_get(dev, NULL);
+ if (IS_ERR(st->back))
+ return PTR_ERR(st->back);
+
+ ret = devm_iio_backend_request_buffer(dev, st->back, indio_dev);
+ if (ret)
+ return ret;
+
+ ret = iio_backend_num_lanes_set(st->back, st->datalines);
+ if (ret)
+ return ret;
+
+ ret = iio_backend_crc_enable(st->back);
+ if (ret)
+ return ret;
+
+ ret = devm_iio_backend_enable(dev, st->back);
+ if (ret)
+ return ret;
+
+ pm_runtime_set_autosuspend_delay(dev, 2000);
+ pm_runtime_use_autosuspend(dev);
+ ret = devm_pm_runtime_set_active_enabled(dev);
+ if (ret)
+ return ret;
+
+ ret = ad7768_register_vcm_regulator(dev, st);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to register VCM regulator\n");
+
+ ret = ad7768_gpio_adev_init(st);
+ if (ret)
+ return ret;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static int ad7768_runtime_suspend(struct device *dev)
+{
+ struct ad7768_state *st = dev_get_drvdata(dev);
+
+ return ad7768_enter_sleep(st);
+}
+
+static int ad7768_runtime_resume(struct device *dev)
+{
+ struct ad7768_state *st = dev_get_drvdata(dev);
+ int ret;
+
+ ret = regmap_clear_bits(st->regmap, AD7768_REG_POWER_MODE,
+ AD7768_SLEEP_MODE_MSK);
+ if (ret)
+ return ret;
+
+ /*
+ * The datasheet does not specify a wake-up time. Allow 20 ms for the
+ * ADC and digital clocks to restart.
+ */
+ fsleep(20 * USEC_PER_MSEC);
+
+ return 0;
+}
+
+static DEFINE_RUNTIME_DEV_PM_OPS(ad7768_pm_ops, ad7768_runtime_suspend,
+ ad7768_runtime_resume, NULL);
+
+static const struct of_device_id ad7768_of_match[] = {
+ { .compatible = "adi,ad7768", .data = &ad7768_chip_info },
+ { .compatible = "adi,ad7768-4", .data = &ad7768_4_chip_info },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ad7768_of_match);
+
+static const struct spi_device_id ad7768_spi_id[] = {
+ { .name = "ad7768", .driver_data = (kernel_ulong_t)&ad7768_chip_info },
+ { .name = "ad7768-4", .driver_data = (kernel_ulong_t)&ad7768_4_chip_info },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, ad7768_spi_id);
+
+static struct spi_driver ad7768_driver = {
+ .probe = ad7768_probe,
+ .driver = {
+ .name = "ad7768",
+ .of_match_table = ad7768_of_match,
+ .pm = pm_ptr(&ad7768_pm_ops),
+ },
+ .id_table = ad7768_spi_id,
+};
+module_spi_driver(ad7768_driver);
+
+MODULE_AUTHOR("Stefan Popa ");
+MODULE_AUTHOR("Janani Sunil ");
+MODULE_DESCRIPTION("Analog Devices AD7768 ADC driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_BACKEND");
diff --git a/drivers/iio/adc/ade9000.c b/drivers/iio/adc/ade9000.c
index c6c3ea953fea..fd1362a98052 100644
--- a/drivers/iio/adc/ade9000.c
+++ b/drivers/iio/adc/ade9000.c
@@ -242,14 +242,6 @@
#define ADE9000_LAST_PAGE_BIT BIT(15)
#define ADE9000_MIDDLE_PAGE_BIT BIT(7)
-/*
- * Full scale Codes referred from Datasheet. Respective digital codes are
- * produced when ADC inputs are at full scale.
- */
-#define ADE9000_RMS_FULL_SCALE_CODES 52866837
-#define ADE9000_WATT_FULL_SCALE_CODES 20694066
-#define ADE9000_PCF_FULL_SCALE_CODES 74770000
-
/* Phase and channel definitions */
#define ADE9000_PHASE_A_NR 0
#define ADE9000_PHASE_B_NR 1
@@ -290,7 +282,29 @@ enum ade9000_wfb_cfg {
#define ADE9000_ADDR_ADJUST(addr, chan) \
(((chan) == 0 ? 0 : (chan) == 1 ? 2 : 4) << 4 | (addr))
+/**
+ * struct ade9000_chip_info - part-specific configuration
+ * @name: IIO device name reported to userspace
+ * @channels: channel specification for this part
+ * @num_channels: number of entries in @channels
+ * @rms_full_scale_codes: digital code produced at full-scale RMS input
+ * @watt_full_scale_codes: digital code produced at full-scale power input
+ * @pcf_full_scale_codes: digital code produced at full-scale xI_PCF/xV_PCF input
+ *
+ * The full-scale codes are taken from the respective datasheets and are used to
+ * derive the IIO scale of the raw measurement channels.
+ */
+struct ade9000_chip_info {
+ const char *name;
+ const struct iio_chan_spec *channels;
+ unsigned int num_channels;
+ unsigned int rms_full_scale_codes;
+ unsigned int watt_full_scale_codes;
+ unsigned int pcf_full_scale_codes;
+};
+
struct ade9000_state {
+ const struct ade9000_chip_info *info;
struct completion reset_completion;
struct mutex lock; /* Protects SPI transactions */
u8 wf_src;
@@ -488,6 +502,7 @@ static const struct iio_chan_spec_ext_info ade9000_ext_info[] = {
.scan_index = -1 \
}
+/* With swell/dip (sag) events - ADE9000 only */
#define ADE9000_ALTVOLTAGE_RMS_CHANNEL(num) { \
.type = IIO_ALTVOLTAGE, \
.channel = num, \
@@ -503,6 +518,20 @@ static const struct iio_chan_spec_ext_info ade9000_ext_info[] = {
.scan_index = -1 \
}
+/* Without swell/dip events - parts lacking DIP_LVL/SWELL_LVL hardware */
+#define ADE9000_ALTVOLTAGE_RMS_CHANNEL_NO_EVENTS(num) { \
+ .type = IIO_ALTVOLTAGE, \
+ .channel = num, \
+ .address = ADE9000_ADDR_ADJUST(ADE9000_REG_AVRMS, num), \
+ .channel2 = IIO_MOD_RMS, \
+ .modified = 1, \
+ .indexed = 1, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_CALIBBIAS), \
+ .scan_index = -1 \
+}
+
#define ADE9000_POWER_ACTIVE_CHANNEL(num) { \
.type = IIO_POWER, \
.channel = num, \
@@ -584,43 +613,82 @@ static const struct iio_chan_spec_ext_info ade9000_ext_info[] = {
.scan_index = -1 \
}
-static const struct iio_chan_spec ade9000_channels[] = {
- /* Phase A channels */
- ADE9000_CURRENT_CHANNEL(ADE9000_PHASE_A_NR),
- ADE9000_VOLTAGE_CHANNEL(ADE9000_PHASE_A_NR),
- ADE9000_ALTCURRENT_RMS_CHANNEL(ADE9000_PHASE_A_NR),
- ADE9000_ALTVOLTAGE_RMS_CHANNEL(ADE9000_PHASE_A_NR),
- ADE9000_POWER_ACTIVE_CHANNEL(ADE9000_PHASE_A_NR),
- ADE9000_POWER_REACTIVE_CHANNEL(ADE9000_PHASE_A_NR),
- ADE9000_POWER_APPARENT_CHANNEL(ADE9000_PHASE_A_NR),
- ADE9000_ENERGY_ACTIVE_CHANNEL(ADE9000_PHASE_A_NR, ADE9000_REG_AWATTHR_LO),
- ADE9000_ENERGY_APPARENT_CHANNEL(ADE9000_PHASE_A_NR, ADE9000_REG_AVAHR_LO),
- ADE9000_ENERGY_REACTIVE_CHANNEL(ADE9000_PHASE_A_NR, ADE9000_REG_AFVARHR_LO),
- ADE9000_POWER_FACTOR_CHANNEL(ADE9000_PHASE_A_NR),
- /* Phase B channels */
- ADE9000_CURRENT_CHANNEL(ADE9000_PHASE_B_NR),
- ADE9000_VOLTAGE_CHANNEL(ADE9000_PHASE_B_NR),
- ADE9000_ALTCURRENT_RMS_CHANNEL(ADE9000_PHASE_B_NR),
- ADE9000_ALTVOLTAGE_RMS_CHANNEL(ADE9000_PHASE_B_NR),
- ADE9000_POWER_ACTIVE_CHANNEL(ADE9000_PHASE_B_NR),
- ADE9000_POWER_REACTIVE_CHANNEL(ADE9000_PHASE_B_NR),
- ADE9000_POWER_APPARENT_CHANNEL(ADE9000_PHASE_B_NR),
- ADE9000_ENERGY_ACTIVE_CHANNEL(ADE9000_PHASE_B_NR, ADE9000_REG_BWATTHR_LO),
- ADE9000_ENERGY_APPARENT_CHANNEL(ADE9000_PHASE_B_NR, ADE9000_REG_BVAHR_LO),
- ADE9000_ENERGY_REACTIVE_CHANNEL(ADE9000_PHASE_B_NR, ADE9000_REG_BFVARHR_LO),
- ADE9000_POWER_FACTOR_CHANNEL(ADE9000_PHASE_B_NR),
- /* Phase C channels */
- ADE9000_CURRENT_CHANNEL(ADE9000_PHASE_C_NR),
- ADE9000_VOLTAGE_CHANNEL(ADE9000_PHASE_C_NR),
- ADE9000_ALTCURRENT_RMS_CHANNEL(ADE9000_PHASE_C_NR),
- ADE9000_ALTVOLTAGE_RMS_CHANNEL(ADE9000_PHASE_C_NR),
- ADE9000_POWER_ACTIVE_CHANNEL(ADE9000_PHASE_C_NR),
- ADE9000_POWER_REACTIVE_CHANNEL(ADE9000_PHASE_C_NR),
- ADE9000_POWER_APPARENT_CHANNEL(ADE9000_PHASE_C_NR),
- ADE9000_ENERGY_ACTIVE_CHANNEL(ADE9000_PHASE_C_NR, ADE9000_REG_CWATTHR_LO),
- ADE9000_ENERGY_APPARENT_CHANNEL(ADE9000_PHASE_C_NR, ADE9000_REG_CVAHR_LO),
- ADE9000_ENERGY_REACTIVE_CHANNEL(ADE9000_PHASE_C_NR, ADE9000_REG_CFVARHR_LO),
- ADE9000_POWER_FACTOR_CHANNEL(ADE9000_PHASE_C_NR),
+/*
+ * Declare a full channel array. @altvoltage_rms picks the RMS voltage channel
+ * variant so parts without dip/swell hardware (e.g. ADE9078) omit those events.
+ */
+#define ADE9000_DECLARE_CHANNELS(_name, altvoltage_rms) \
+ static const struct iio_chan_spec _name[] = { \
+ /* Phase A channels */ \
+ ADE9000_CURRENT_CHANNEL(ADE9000_PHASE_A_NR), \
+ ADE9000_VOLTAGE_CHANNEL(ADE9000_PHASE_A_NR), \
+ ADE9000_ALTCURRENT_RMS_CHANNEL(ADE9000_PHASE_A_NR), \
+ altvoltage_rms(ADE9000_PHASE_A_NR), \
+ ADE9000_POWER_ACTIVE_CHANNEL(ADE9000_PHASE_A_NR), \
+ ADE9000_POWER_REACTIVE_CHANNEL(ADE9000_PHASE_A_NR), \
+ ADE9000_POWER_APPARENT_CHANNEL(ADE9000_PHASE_A_NR), \
+ ADE9000_ENERGY_ACTIVE_CHANNEL(ADE9000_PHASE_A_NR, \
+ ADE9000_REG_AWATTHR_LO), \
+ ADE9000_ENERGY_APPARENT_CHANNEL(ADE9000_PHASE_A_NR, \
+ ADE9000_REG_AVAHR_LO), \
+ ADE9000_ENERGY_REACTIVE_CHANNEL(ADE9000_PHASE_A_NR, \
+ ADE9000_REG_AFVARHR_LO), \
+ ADE9000_POWER_FACTOR_CHANNEL(ADE9000_PHASE_A_NR), \
+ /* Phase B channels */ \
+ ADE9000_CURRENT_CHANNEL(ADE9000_PHASE_B_NR), \
+ ADE9000_VOLTAGE_CHANNEL(ADE9000_PHASE_B_NR), \
+ ADE9000_ALTCURRENT_RMS_CHANNEL(ADE9000_PHASE_B_NR), \
+ altvoltage_rms(ADE9000_PHASE_B_NR), \
+ ADE9000_POWER_ACTIVE_CHANNEL(ADE9000_PHASE_B_NR), \
+ ADE9000_POWER_REACTIVE_CHANNEL(ADE9000_PHASE_B_NR), \
+ ADE9000_POWER_APPARENT_CHANNEL(ADE9000_PHASE_B_NR), \
+ ADE9000_ENERGY_ACTIVE_CHANNEL(ADE9000_PHASE_B_NR, \
+ ADE9000_REG_BWATTHR_LO), \
+ ADE9000_ENERGY_APPARENT_CHANNEL(ADE9000_PHASE_B_NR, \
+ ADE9000_REG_BVAHR_LO), \
+ ADE9000_ENERGY_REACTIVE_CHANNEL(ADE9000_PHASE_B_NR, \
+ ADE9000_REG_BFVARHR_LO), \
+ ADE9000_POWER_FACTOR_CHANNEL(ADE9000_PHASE_B_NR), \
+ /* Phase C channels */ \
+ ADE9000_CURRENT_CHANNEL(ADE9000_PHASE_C_NR), \
+ ADE9000_VOLTAGE_CHANNEL(ADE9000_PHASE_C_NR), \
+ ADE9000_ALTCURRENT_RMS_CHANNEL(ADE9000_PHASE_C_NR), \
+ altvoltage_rms(ADE9000_PHASE_C_NR), \
+ ADE9000_POWER_ACTIVE_CHANNEL(ADE9000_PHASE_C_NR), \
+ ADE9000_POWER_REACTIVE_CHANNEL(ADE9000_PHASE_C_NR), \
+ ADE9000_POWER_APPARENT_CHANNEL(ADE9000_PHASE_C_NR), \
+ ADE9000_ENERGY_ACTIVE_CHANNEL(ADE9000_PHASE_C_NR, \
+ ADE9000_REG_CWATTHR_LO), \
+ ADE9000_ENERGY_APPARENT_CHANNEL(ADE9000_PHASE_C_NR, \
+ ADE9000_REG_CVAHR_LO), \
+ ADE9000_ENERGY_REACTIVE_CHANNEL(ADE9000_PHASE_C_NR, \
+ ADE9000_REG_CFVARHR_LO), \
+ ADE9000_POWER_FACTOR_CHANNEL(ADE9000_PHASE_C_NR), \
+ }
+
+ADE9000_DECLARE_CHANNELS(ade9000_channels, ADE9000_ALTVOLTAGE_RMS_CHANNEL);
+ADE9000_DECLARE_CHANNELS(ade9078_channels, ADE9000_ALTVOLTAGE_RMS_CHANNEL_NO_EVENTS);
+
+/*
+ * Full-scale codes referred from the respective datasheets. These are the
+ * digital codes produced when the ADC inputs are at full scale.
+ */
+static const struct ade9000_chip_info ade9000_chip_info = {
+ .name = "ade9000",
+ .channels = ade9000_channels,
+ .num_channels = ARRAY_SIZE(ade9000_channels),
+ .rms_full_scale_codes = 52866837,
+ .watt_full_scale_codes = 20694066,
+ .pcf_full_scale_codes = 74770000,
+};
+
+static const struct ade9000_chip_info ade9078_chip_info = {
+ .name = "ade9078",
+ .channels = ade9078_channels,
+ .num_channels = ARRAY_SIZE(ade9078_channels),
+ .rms_full_scale_codes = 52866837,
+ .watt_full_scale_codes = 20823646,
+ .pcf_full_scale_codes = 74680000,
};
static const struct reg_sequence ade9000_initialization_sequence[] = {
@@ -1064,7 +1132,7 @@ static int ade9000_read_raw(struct iio_dev *indio_dev,
case ADE9000_REG_CI_PCF:
case ADE9000_REG_CV_PCF:
*val = 1;
- *val2 = ADE9000_PCF_FULL_SCALE_CODES;
+ *val2 = st->info->pcf_full_scale_codes;
return IIO_VAL_FRACTIONAL;
case ADE9000_REG_AIRMS:
case ADE9000_REG_AVRMS:
@@ -1073,14 +1141,14 @@ static int ade9000_read_raw(struct iio_dev *indio_dev,
case ADE9000_REG_CIRMS:
case ADE9000_REG_CVRMS:
*val = 1;
- *val2 = ADE9000_RMS_FULL_SCALE_CODES;
+ *val2 = st->info->rms_full_scale_codes;
return IIO_VAL_FRACTIONAL;
default:
return -EINVAL;
}
case IIO_POWER:
*val = 1;
- *val2 = ADE9000_WATT_FULL_SCALE_CODES;
+ *val2 = st->info->watt_full_scale_codes;
return IIO_VAL_FRACTIONAL;
default:
break;
@@ -1692,6 +1760,10 @@ static int ade9000_probe(struct spi_device *spi)
st = iio_priv(indio_dev);
+ st->info = spi_get_device_match_data(spi);
+ if (!st->info)
+ return -ENODEV;
+
regmap = devm_regmap_init(dev, NULL, st, &ade9000_regmap_config);
if (IS_ERR(regmap))
return dev_err_probe(dev, PTR_ERR(regmap), "Unable to allocate ADE9000 regmap");
@@ -1726,7 +1798,7 @@ static int ade9000_probe(struct spi_device *spi)
if (ret)
return ret;
- indio_dev->name = "ade9000";
+ indio_dev->name = st->info->name;
indio_dev->info = &ade9000_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->setup_ops = &ade9000_buffer_ops;
@@ -1736,8 +1808,8 @@ static int ade9000_probe(struct spi_device *spi)
return dev_err_probe(&spi->dev, ret,
"Failed to get and enable vdd regulator\n");
- indio_dev->channels = ade9000_channels;
- indio_dev->num_channels = ARRAY_SIZE(ade9000_channels);
+ indio_dev->channels = st->info->channels;
+ indio_dev->num_channels = st->info->num_channels;
ret = devm_iio_kfifo_buffer_setup(dev, indio_dev,
&ade9000_buffer_ops);
@@ -1768,13 +1840,15 @@ static int ade9000_probe(struct spi_device *spi)
};
static const struct spi_device_id ade9000_id[] = {
- { .name = "ade9000" },
+ { .name = "ade9000", .driver_data = (kernel_ulong_t)&ade9000_chip_info },
+ { .name = "ade9078", .driver_data = (kernel_ulong_t)&ade9078_chip_info },
{ }
};
MODULE_DEVICE_TABLE(spi, ade9000_id);
static const struct of_device_id ade9000_of_match[] = {
- { .compatible = "adi,ade9000" },
+ { .compatible = "adi,ade9000", .data = &ade9000_chip_info },
+ { .compatible = "adi,ade9078", .data = &ade9078_chip_info },
{ }
};
MODULE_DEVICE_TABLE(of, ade9000_of_match);
diff --git a/drivers/iio/adc/adi-axi-adc.c b/drivers/iio/adc/adi-axi-adc.c
index 589f03618ecf..8b7c45d51dbe 100644
--- a/drivers/iio/adc/adi-axi-adc.c
+++ b/drivers/iio/adc/adi-axi-adc.c
@@ -47,6 +47,9 @@
#define ADI_AXI_ADC_CTRL_DDR_EDGESEL_MASK BIT(1)
#define ADI_AXI_ADC_REG_CNTRL_3 0x004c
+/* Bit 8 is common to all AXI ADC cores; bits 7-0 are per-HDL-project. */
+#define ADI_AXI_ADC_CNTRL_3_CRC_EN_MASK BIT(8)
+
#define AXI_AD485X_CNTRL_3_OS_EN_MSK BIT(2)
#define AXI_AD485X_CNTRL_3_PACKET_FORMAT_MSK GENMASK(1, 0)
#define AXI_AD485X_PACKET_FORMAT_20BIT 0x0
@@ -596,6 +599,22 @@ static int axi_adc_reg_access(struct iio_backend *back, unsigned int reg,
return regmap_write(st->regmap, reg, writeval);
}
+static int axi_adc_crc_enable(struct iio_backend *back)
+{
+ struct adi_axi_adc_state *st = iio_backend_get_priv(back);
+
+ return regmap_set_bits(st->regmap, ADI_AXI_ADC_REG_CNTRL_3,
+ ADI_AXI_ADC_CNTRL_3_CRC_EN_MASK);
+}
+
+static int axi_adc_crc_disable(struct iio_backend *back)
+{
+ struct adi_axi_adc_state *st = iio_backend_get_priv(back);
+
+ return regmap_clear_bits(st->regmap, ADI_AXI_ADC_REG_CNTRL_3,
+ ADI_AXI_ADC_CNTRL_3_CRC_EN_MASK);
+}
+
static const struct regmap_config axi_adc_regmap_config = {
.val_bits = 32,
.reg_bits = 32,
@@ -644,6 +663,8 @@ static const struct iio_backend_ops adi_axi_adc_ops = {
.num_lanes_set = axi_adc_num_lanes_set,
.debugfs_reg_access = iio_backend_debugfs_ptr(axi_adc_reg_access),
.debugfs_print_chan_status = iio_backend_debugfs_ptr(axi_adc_debugfs_print_chan_status),
+ .crc_enable = axi_adc_crc_enable,
+ .crc_disable = axi_adc_crc_disable,
};
static const struct iio_backend_info adi_axi_adc_generic = {
@@ -714,6 +735,10 @@ static int adi_axi_adc_probe(struct platform_device *pdev)
if (!st)
return -ENOMEM;
+ ret = devm_mutex_init(dev, &st->lock);
+ if (ret)
+ return ret;
+
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return PTR_ERR(base);
diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c
index e8a5285bb6d4..78081cbfde5e 100644
--- a/drivers/iio/adc/at91-sama5d2_adc.c
+++ b/drivers/iio/adc/at91-sama5d2_adc.c
@@ -2016,6 +2016,8 @@ static void at91_adc_dma_init(struct at91_adc_state *st)
unsigned int pages = DIV_ROUND_UP(AT91_HWFIFO_MAX_SIZE *
sample_size * 2, PAGE_SIZE);
+ struct device *dma_dev;
+
if (st->dma_st.dma_chan)
return;
@@ -2026,7 +2028,8 @@ static void at91_adc_dma_init(struct at91_adc_state *st)
goto dma_exit;
}
- st->dma_st.rx_buf = dma_alloc_coherent(st->dma_st.dma_chan->device->dev,
+ dma_dev = dmaengine_get_dma_device(st->dma_st.dma_chan);
+ st->dma_st.rx_buf = dma_alloc_coherent(dma_dev,
pages * PAGE_SIZE,
&st->dma_st.rx_dma_buf,
GFP_KERNEL);
@@ -2054,7 +2057,7 @@ static void at91_adc_dma_init(struct at91_adc_state *st)
return;
dma_free_area:
- dma_free_coherent(st->dma_st.dma_chan->device->dev, pages * PAGE_SIZE,
+ dma_free_coherent(dma_dev, pages * PAGE_SIZE,
st->dma_st.rx_buf, st->dma_st.rx_dma_buf);
dma_chan_disable:
dma_release_channel(st->dma_st.dma_chan);
@@ -2078,7 +2081,7 @@ static void at91_adc_dma_disable(struct at91_adc_state *st)
/* wait for all transactions to be terminated first*/
dmaengine_terminate_sync(st->dma_st.dma_chan);
- dma_free_coherent(st->dma_st.dma_chan->device->dev, pages * PAGE_SIZE,
+ dma_free_coherent(dmaengine_get_dma_device(st->dma_st.dma_chan), pages * PAGE_SIZE,
st->dma_st.rx_buf, st->dma_st.rx_dma_buf);
dma_release_channel(st->dma_st.dma_chan);
st->dma_st.dma_chan = NULL;
@@ -2487,6 +2490,7 @@ static void at91_adc_remove(struct platform_device *pdev)
pm_runtime_disable(st->dev);
pm_runtime_set_suspended(st->dev);
+ pm_runtime_dont_use_autosuspend(st->dev);
clk_disable_unprepare(st->per_clk);
regulator_disable(st->vref);
diff --git a/drivers/iio/adc/axiado_saradc.c b/drivers/iio/adc/axiado_saradc.c
new file mode 100644
index 000000000000..699ee31616fc
--- /dev/null
+++ b/drivers/iio/adc/axiado_saradc.c
@@ -0,0 +1,277 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2021-2026 Axiado Corporation
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+/* Register offsets */
+#define AX_SARADC_GLOBAL_CTRL_REG 0x0004
+#define AX_SARADC_MANUAL_CTRL_REG 0x0008
+#define AX_SARADC_DOUT_REG 0x001C
+
+/* GLOBAL_CTRL register fields */
+#define AX_SARADC_GLOBAL_CTRL_CH_EN_MASK GENMASK(31, 16)
+#define AX_SARADC_GLOBAL_CTRL_SAMPLE_MASK GENMASK(6, 5)
+#define AX_SARADC_GLOBAL_CTRL_MODE_MASK GENMASK(4, 3)
+#define AX_SARADC_GLOBAL_CTRL_PD BIT(2)
+#define AX_SARADC_GLOBAL_CTRL_ENABLE BIT(0)
+
+/* GLOBAL_CTRL SAMPLE_MASK field value: 0 selects 16 samples. */
+#define AX_SARADC_GLOBAL_CTRL_SAMPLE_16 0
+
+/* GLOBAL_CTRL MODE_MASK field value: 1 selects manual mode. */
+#define AX_SARADC_GLOBAL_CTRL_MODE_MANUAL 1
+
+/* MANUAL_CTRL register fields */
+#define AX_SARADC_MANUAL_CTRL_ENABLE BIT(0)
+#define AX_SARADC_MANUAL_CTRL_CH_SEL_MASK GENMASK(4, 1)
+
+#define AX_RESOLUTION_BITS 10
+#define AX_SARADC_CONV_CYCLES 13
+#define AX_SARADC_CONV_DELAY_MARGIN_US 10
+
+struct axiado_saradc {
+ struct regmap *regmap;
+ struct mutex lock; /* Serializes ADC conversions. */
+ unsigned long clk_rate;
+ int vref_uV;
+};
+
+/*
+ * Registers contain transient control, status, and conversion data,
+ * so accesses must always go directly to hardware.
+ */
+static const struct regmap_config axiado_saradc_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = AX_SARADC_DOUT_REG,
+ .val_format_endian = REGMAP_ENDIAN_LITTLE,
+};
+
+static int axiado_saradc_conversion(struct axiado_saradc *info,
+ struct iio_chan_spec const *chan, int *val)
+{
+ unsigned long usecs;
+ unsigned int regval;
+ int ret;
+
+ guard(mutex)(&info->lock);
+
+ /* Select the channel to be used and trigger conversion. */
+ ret = regmap_write(info->regmap, AX_SARADC_MANUAL_CTRL_REG,
+ AX_SARADC_MANUAL_CTRL_ENABLE |
+ FIELD_PREP(AX_SARADC_MANUAL_CTRL_CH_SEL_MASK, chan->channel));
+ if (ret)
+ return ret;
+
+ /* Hardware requires 13 conversion cycles at clk_rate. */
+ usecs = DIV_ROUND_UP(AX_SARADC_CONV_CYCLES * USEC_PER_SEC, info->clk_rate);
+ fsleep(usecs + AX_SARADC_CONV_DELAY_MARGIN_US);
+
+ ret = regmap_read(info->regmap, AX_SARADC_DOUT_REG, ®val);
+
+ /* Best effort to stop manual conversion. */
+ regmap_write(info->regmap, AX_SARADC_MANUAL_CTRL_REG, 0);
+
+ if (ret)
+ return ret;
+
+ *val = regval & GENMASK(AX_RESOLUTION_BITS - 1, 0);
+
+ return 0;
+}
+
+static int axiado_saradc_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct axiado_saradc *info = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = axiado_saradc_conversion(info, chan, val);
+ if (ret)
+ return ret;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ *val = info->vref_uV / (MICRO / MILLI);
+ *val2 = AX_RESOLUTION_BITS;
+ return IIO_VAL_FRACTIONAL_LOG2;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info axiado_saradc_iio_info = {
+ .read_raw = axiado_saradc_read_raw,
+};
+
+struct axiado_saradc_soc_data {
+ const char *name;
+ unsigned int num_channels;
+};
+
+static const struct axiado_saradc_soc_data ax3000_saradc_data = {
+ .name = "ax3000_saradc",
+ .num_channels = 16,
+};
+
+static const struct axiado_saradc_soc_data ax3005_saradc_data = {
+ .name = "ax3005_saradc",
+ .num_channels = 8,
+};
+
+#define AX_SARADC_CH(_index) \
+ { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = (_index), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .datasheet_name = "adc" #_index, \
+ }
+
+static const struct iio_chan_spec axiado_saradc_iio_channels[] = {
+ AX_SARADC_CH(0),
+ AX_SARADC_CH(1),
+ AX_SARADC_CH(2),
+ AX_SARADC_CH(3),
+ AX_SARADC_CH(4),
+ AX_SARADC_CH(5),
+ AX_SARADC_CH(6),
+ AX_SARADC_CH(7),
+ AX_SARADC_CH(8),
+ AX_SARADC_CH(9),
+ AX_SARADC_CH(10),
+ AX_SARADC_CH(11),
+ AX_SARADC_CH(12),
+ AX_SARADC_CH(13),
+ AX_SARADC_CH(14),
+ AX_SARADC_CH(15),
+};
+
+static void axiado_saradc_disable(void *map)
+{
+ regmap_write(map, AX_SARADC_GLOBAL_CTRL_REG, AX_SARADC_GLOBAL_CTRL_PD);
+}
+
+static int axiado_saradc_probe(struct platform_device *pdev)
+{
+ const struct axiado_saradc_soc_data *soc_data;
+ struct device *dev = &pdev->dev;
+ struct axiado_saradc *info;
+ struct iio_dev *indio_dev;
+ void __iomem *regs;
+ struct regmap *map;
+ struct clk *clk;
+ u32 regval;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*info));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ info = iio_priv(indio_dev);
+
+ regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+
+ map = devm_regmap_init_mmio(dev, regs, &axiado_saradc_regmap_config);
+ if (IS_ERR(map))
+ return PTR_ERR(map);
+ info->regmap = map;
+
+ clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ info->clk_rate = clk_get_rate(clk);
+ if (!info->clk_rate)
+ return dev_err_probe(dev, -EINVAL, "invalid clock rate\n");
+
+ ret = devm_regulator_get_enable_read_voltage(dev, "vref");
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed to get vref voltage\n");
+
+ info->vref_uV = ret;
+
+ soc_data = device_get_match_data(dev);
+ if (!soc_data)
+ return dev_err_probe(dev, -ENODATA, "failed to get match data\n");
+
+ ret = devm_mutex_init(dev, &info->lock);
+ if (ret)
+ return ret;
+
+ regval = FIELD_PREP(AX_SARADC_GLOBAL_CTRL_CH_EN_MASK,
+ GENMASK(soc_data->num_channels - 1, 0)) |
+ FIELD_PREP(AX_SARADC_GLOBAL_CTRL_SAMPLE_MASK,
+ AX_SARADC_GLOBAL_CTRL_SAMPLE_16) |
+ FIELD_PREP(AX_SARADC_GLOBAL_CTRL_MODE_MASK,
+ AX_SARADC_GLOBAL_CTRL_MODE_MANUAL) |
+ AX_SARADC_GLOBAL_CTRL_ENABLE;
+
+ ret = regmap_write(map, AX_SARADC_GLOBAL_CTRL_REG, regval);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(dev, axiado_saradc_disable, map);
+ if (ret)
+ return ret;
+
+ indio_dev->name = soc_data->name;
+ indio_dev->info = &axiado_saradc_iio_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = axiado_saradc_iio_channels;
+ indio_dev->num_channels = soc_data->num_channels;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct of_device_id axiado_saradc_match[] = {
+ {
+ .compatible = "axiado,ax3000-saradc",
+ .data = &ax3000_saradc_data,
+ },
+ {
+ .compatible = "axiado,ax3005-saradc",
+ .data = &ax3005_saradc_data,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, axiado_saradc_match);
+
+static struct platform_driver axiado_saradc_driver = {
+ .driver = {
+ .name = "axiado-saradc",
+ .of_match_table = axiado_saradc_match,
+ },
+ .probe = axiado_saradc_probe,
+};
+module_platform_driver(axiado_saradc_driver);
+
+MODULE_AUTHOR("Axiado Corporation");
+MODULE_DESCRIPTION("Axiado SARADC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/adc/bcm_iproc_adc.c b/drivers/iio/adc/bcm_iproc_adc.c
index cf4738b16e62..ca81e0edd24d 100644
--- a/drivers/iio/adc/bcm_iproc_adc.c
+++ b/drivers/iio/adc/bcm_iproc_adc.c
@@ -3,14 +3,18 @@
* Copyright 2016 Broadcom
*/
-#include
-#include
+#include
+#include
#include
-#include
-#include
+#include
#include
#include
+#include
+#include
+#include
#include
+#include
+#include
#include
@@ -106,7 +110,6 @@ do { \
struct iproc_adc_priv {
struct regmap *regmap;
- struct clk *adc_clk;
struct mutex mutex;
int irqno;
int chan_val;
@@ -448,6 +451,11 @@ static void iproc_adc_disable(struct iio_dev *indio_dev)
}
}
+static void iproc_adc_disable_action(void *indio_dev)
+{
+ iproc_adc_disable(indio_dev);
+}
+
static int iproc_adc_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
@@ -506,35 +514,31 @@ static int iproc_adc_probe(struct platform_device *pdev)
{
struct iproc_adc_priv *adc_priv;
struct iio_dev *indio_dev = NULL;
+ struct device *dev = &pdev->dev;
+ struct clk *adc_clk;
int ret;
- indio_dev = devm_iio_device_alloc(&pdev->dev,
- sizeof(*adc_priv));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*adc_priv));
if (!indio_dev)
return -ENOMEM;
adc_priv = iio_priv(indio_dev);
- platform_set_drvdata(pdev, indio_dev);
- mutex_init(&adc_priv->mutex);
+ ret = devm_mutex_init(dev, &adc_priv->mutex);
+ if (ret)
+ return ret;
init_completion(&adc_priv->completion);
adc_priv->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
"adc-syscon");
- if (IS_ERR(adc_priv->regmap)) {
- dev_err(&pdev->dev, "failed to get handle for tsc syscon\n");
- ret = PTR_ERR(adc_priv->regmap);
- return ret;
- }
+ if (IS_ERR(adc_priv->regmap))
+ return dev_err_probe(dev, PTR_ERR(adc_priv->regmap),
+ "failed to get handle for tsc syscon\n");
- adc_priv->adc_clk = devm_clk_get(&pdev->dev, "tsc_clk");
- if (IS_ERR(adc_priv->adc_clk)) {
- dev_err(&pdev->dev,
- "failed getting clock tsc_clk\n");
- ret = PTR_ERR(adc_priv->adc_clk);
- return ret;
- }
+ adc_clk = devm_clk_get_enabled(dev, "tsc_clk");
+ if (IS_ERR(adc_clk))
+ return dev_err_probe(dev, PTR_ERR(adc_clk), "failed to enable clock\n");
adc_priv->irqno = platform_get_irq(pdev, 0);
if (adc_priv->irqno < 0)
@@ -542,32 +546,23 @@ static int iproc_adc_probe(struct platform_device *pdev)
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;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to write IPROC_REGCTL2\n");
- ret = devm_request_threaded_irq(&pdev->dev, adc_priv->irqno,
+ ret = devm_request_threaded_irq(dev, adc_priv->irqno,
iproc_adc_interrupt_handler,
iproc_adc_interrupt_thread,
IRQF_SHARED, "iproc-adc", indio_dev);
- if (ret) {
- dev_err(&pdev->dev, "request_irq error %d\n", ret);
+ if (ret)
return ret;
- }
-
- ret = clk_prepare_enable(adc_priv->adc_clk);
- if (ret) {
- dev_err(&pdev->dev,
- "clk_prepare_enable failed %d\n", ret);
- return ret;
- }
ret = iproc_adc_enable(indio_dev);
- if (ret) {
- dev_err(&pdev->dev, "failed to enable adc %d\n", ret);
- goto err_adc_enable;
- }
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(dev, iproc_adc_disable_action, indio_dev);
+ if (ret)
+ return ret;
indio_dev->name = "iproc-static-adc";
indio_dev->info = &iproc_adc_iio_info;
@@ -575,30 +570,7 @@ static int iproc_adc_probe(struct platform_device *pdev)
indio_dev->channels = iproc_adc_iio_channels;
indio_dev->num_channels = ARRAY_SIZE(iproc_adc_iio_channels);
- ret = iio_device_register(indio_dev);
- if (ret) {
- dev_err(&pdev->dev, "iio_device_register failed:err %d\n", ret);
- goto err_clk;
- }
-
- return 0;
-
-err_clk:
- iproc_adc_disable(indio_dev);
-err_adc_enable:
- clk_disable_unprepare(adc_priv->adc_clk);
-
- return ret;
-}
-
-static void iproc_adc_remove(struct platform_device *pdev)
-{
- struct iio_dev *indio_dev = platform_get_drvdata(pdev);
- struct iproc_adc_priv *adc_priv = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
- iproc_adc_disable(indio_dev);
- clk_disable_unprepare(adc_priv->adc_clk);
+ return devm_iio_device_register(dev, indio_dev);
}
static const struct of_device_id iproc_adc_of_match[] = {
@@ -609,7 +581,6 @@ MODULE_DEVICE_TABLE(of, iproc_adc_of_match);
static struct platform_driver iproc_adc_driver = {
.probe = iproc_adc_probe,
- .remove = iproc_adc_remove,
.driver = {
.name = "iproc-static-adc",
.of_match_table = iproc_adc_of_match,
diff --git a/drivers/iio/adc/ltc2497-core.c b/drivers/iio/adc/ltc2497-core.c
index 2dc5c7044269..a6e34da83b81 100644
--- a/drivers/iio/adc/ltc2497-core.c
+++ b/drivers/iio/adc/ltc2497-core.c
@@ -9,9 +9,11 @@
#include
#include
#include
+#include
#include
#include
#include
+#include
#include "ltc2497.h"
@@ -19,24 +21,54 @@
#define LTC2497_DIFF 0
#define LTC2497_SIGN BIT(3)
-static int ltc2497core_wait_conv(struct ltc2497core_driverdata *ddata)
+/*
+ * Output-rate modes, indexed by ltc2497core_driverdata.speed_2x
+ * (0 = 1x, the power-on default; 1 = 2x, LTC2499 only). The advertised
+ * sampling_frequency and the conversion-time budget are two views of the same
+ * mode, so they are kept in lock-step here.
+ */
+static const int ltc2497core_samp_freq_avail[] = {
+ 6, 800000, /* 1x: ~6.8 Hz (1 / t_CONV_1 typ 146.9ms) */
+ 13, 600000, /* 2x: ~13.6 Hz (1 / t_CONV_2 typ 73.6ms) */
+};
+
+static const unsigned int ltc2497core_conv_time_ms_tbl[] = {
+ LTC2497_CONV_TIME_1X_MS, /* 1x */
+ LTC2499_CONV_TIME_2X_MS, /* 2x */
+};
+
+static unsigned int ltc2497core_conv_time_ms(struct ltc2497core_driverdata *ddata,
+ u8 address)
+{
+ /*
+ * SPD is ignored by the part during a temperature measurement: it
+ * always converts at 1x, so budget the 1x time regardless of the
+ * selected voltage-channel mode.
+ */
+ if (address == LTC2497_TEMP_ADDR)
+ return ltc2497core_conv_time_ms_tbl[0];
+
+ return ltc2497core_conv_time_ms_tbl[ddata->speed_2x];
+}
+
+static int ltc2497core_wait_conv(struct ltc2497core_driverdata *ddata,
+ unsigned int conv_time_ms)
{
s64 time_elapsed;
time_elapsed = ktime_ms_delta(ktime_get(), ddata->time_prev);
- if (time_elapsed < LTC2497_CONVERSION_TIME_MS) {
+ if (time_elapsed < conv_time_ms) {
/* delay if conversion time not passed
* since last read or write
*/
- if (msleep_interruptible(
- LTC2497_CONVERSION_TIME_MS - time_elapsed))
+ if (msleep_interruptible(conv_time_ms - time_elapsed))
return -ERESTARTSYS;
return 0;
}
- if (time_elapsed - LTC2497_CONVERSION_TIME_MS <= 0) {
+ if (time_elapsed - conv_time_ms <= 0) {
/* We're in automatic mode -
* so the last reading is still not outdated
*/
@@ -48,9 +80,18 @@ static int ltc2497core_wait_conv(struct ltc2497core_driverdata *ddata)
static int ltc2497core_read(struct ltc2497core_driverdata *ddata, u8 address, int *val)
{
+ unsigned int conv_time_ms = ltc2497core_conv_time_ms(ddata, address);
int ret;
- ret = ltc2497core_wait_conv(ddata);
+ /*
+ * Wait for the conversion currently in flight, whose duration was fixed
+ * by the mode active when it was started (ddata->conv_time_prev). This
+ * can be longer than the freshly selected mode's time - e.g. a 1x
+ * conversion is still running when the first 2x read arrives after a
+ * sampling_frequency change - and reprogramming the device before it
+ * finishes would be NACKed (-EIO).
+ */
+ ret = ltc2497core_wait_conv(ddata, ddata->conv_time_prev);
if (ret < 0)
return ret;
@@ -60,7 +101,17 @@ static int ltc2497core_read(struct ltc2497core_driverdata *ddata, u8 address, in
return ret;
ddata->addr_prev = address;
- if (msleep_interruptible(LTC2497_CONVERSION_TIME_MS))
+ /*
+ * The reprogram above starts a conversion in the new mode.
+ * Record its start time and duration before sleeping, so that if
+ * msleep_interruptible() is interrupted the conversion state is
+ * already consistent: the next retry then waits only the time
+ * remaining from the real start instead of from a stale
+ * time_prev, which would let it reprogram/read too early.
+ */
+ ddata->time_prev = ktime_get();
+ ddata->conv_time_prev = conv_time_ms;
+ if (msleep_interruptible(conv_time_ms))
return -ERESTARTSYS;
}
@@ -69,6 +120,8 @@ static int ltc2497core_read(struct ltc2497core_driverdata *ddata, u8 address, in
return ret;
ddata->time_prev = ktime_get();
+ /* The read above auto-starts the next conversion in the current mode. */
+ ddata->conv_time_prev = conv_time_ms;
return ret;
}
@@ -95,74 +148,209 @@ static int ltc2497core_read_raw(struct iio_dev *indio_dev,
if (ret < 0)
return ret;
- *val = ret / 1000;
- *val2 = ddata->chip_info->resolution + 1;
+ switch (chan->type) {
+ case IIO_TEMP:
+ /*
+ * raw is normalised to 2^(resolution + 1), i.e.
+ * raw = 2 * DATAOUT24, so the PTAT scale (datasheet
+ * Vref / 1570 per Kelvin) doubles its denominator and,
+ * in m°C, becomes Vref_uV / 3140000.
+ */
+ *val = ret;
+ *val2 = 3140000;
+ return IIO_VAL_FRACTIONAL;
+ case IIO_VOLTAGE:
+ *val = ret / (MICRO / MILLI);
+ *val2 = ddata->chip_info->resolution + 1;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ default:
+ return -EINVAL;
+ }
- return IIO_VAL_FRACTIONAL_LOG2;
+ case IIO_CHAN_INFO_OFFSET:
+ switch (chan->type) {
+ case IIO_TEMP:
+ ret = regulator_get_voltage(ddata->ref);
+ if (ret < 0)
+ return ret;
+ if (ret == 0)
+ return -EINVAL;
+ /*
+ * 0 °C == 273.15 K must map to raw + offset such that
+ * (raw + offset) * scale == 0 m°C, i.e.
+ * offset = -273150 / scale
+ * = -273150 * 3140000 / Vref_uV
+ * Computed in 64-bit to avoid overflow.
+ */
+ *val = div_s64(ABSOLUTE_ZERO_MILLICELSIUS * 3140000LL, ret);
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ /*
+ * Only advertised on the voltage channels of parts with a speed
+ * mode; the sampling frequency is a property of the selected 1x/2x
+ * mode, not of an individual conversion.
+ */
+ mutex_lock(&ddata->lock);
+ *val = ltc2497core_samp_freq_avail[ddata->speed_2x * 2];
+ *val2 = ltc2497core_samp_freq_avail[ddata->speed_2x * 2 + 1];
+ mutex_unlock(&ddata->lock);
+
+ return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
}
-#define LTC2497_CHAN(_chan, _addr, _ds_name) { \
+static int ltc2497core_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_SAMP_FREQ:
+ *vals = ltc2497core_samp_freq_avail;
+ *type = IIO_VAL_INT_PLUS_MICRO;
+ *length = ARRAY_SIZE(ltc2497core_samp_freq_avail);
+ return IIO_AVAIL_LIST;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ltc2497core_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct ltc2497core_driverdata *ddata = iio_priv(indio_dev);
+ unsigned int i;
+ bool speed_2x;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ /* Match the (val, val2) pair against the advertised rates. */
+ for (i = 0; i < ARRAY_SIZE(ltc2497core_samp_freq_avail); i += 2) {
+ if (val == ltc2497core_samp_freq_avail[i] &&
+ val2 == ltc2497core_samp_freq_avail[i + 1])
+ break;
+ }
+ if (i == ARRAY_SIZE(ltc2497core_samp_freq_avail))
+ return -EINVAL;
+
+ speed_2x = i / 2;
+
+ mutex_lock(&ddata->lock);
+ ddata->speed_2x = speed_2x;
+ /*
+ * The new speed only takes effect once the second command byte
+ * is reprogrammed, so force the next read to reprogram rather
+ * than reuse the value already latched for this address.
+ * LTC2497_CONFIG_DEFAULT is not a valid channel/temperature
+ * address, so it is a safe re-arm sentinel (as used at probe).
+ *
+ * A conversion started under the old speed may still be in
+ * flight; its own duration (conv_time_prev), not the new mode's,
+ * still gates the next reprogram, so the timing state is left
+ * untouched here.
+ */
+ ddata->addr_prev = LTC2497_CONFIG_DEFAULT;
+ mutex_unlock(&ddata->lock);
+
+ return 0;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+#define LTC2497_CHAN(_chan, _addr, _ds_name, _extra_mask) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = (_chan), \
.address = (_addr | (_chan / 2) | ((_chan & 1) ? LTC2497_SIGN : 0)), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
- .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | (_extra_mask), \
+ .info_mask_shared_by_type_available = (_extra_mask), \
.datasheet_name = (_ds_name), \
}
-#define LTC2497_CHAN_DIFF(_chan, _addr) { \
+#define LTC2497_CHAN_DIFF(_chan, _addr, _extra_mask) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = (_chan) * 2 + ((_addr) & LTC2497_SIGN ? 1 : 0), \
.channel2 = (_chan) * 2 + ((_addr) & LTC2497_SIGN ? 0 : 1),\
.address = (_addr | _chan), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
- .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | (_extra_mask), \
+ .info_mask_shared_by_type_available = (_extra_mask), \
.differential = 1, \
}
-static const struct iio_chan_spec ltc2497core_channel[] = {
- LTC2497_CHAN(0, LTC2497_SGL, "CH0"),
- LTC2497_CHAN(1, LTC2497_SGL, "CH1"),
- LTC2497_CHAN(2, LTC2497_SGL, "CH2"),
- LTC2497_CHAN(3, LTC2497_SGL, "CH3"),
- LTC2497_CHAN(4, LTC2497_SGL, "CH4"),
- LTC2497_CHAN(5, LTC2497_SGL, "CH5"),
- LTC2497_CHAN(6, LTC2497_SGL, "CH6"),
- LTC2497_CHAN(7, LTC2497_SGL, "CH7"),
- LTC2497_CHAN(8, LTC2497_SGL, "CH8"),
- LTC2497_CHAN(9, LTC2497_SGL, "CH9"),
- LTC2497_CHAN(10, LTC2497_SGL, "CH10"),
- LTC2497_CHAN(11, LTC2497_SGL, "CH11"),
- LTC2497_CHAN(12, LTC2497_SGL, "CH12"),
- LTC2497_CHAN(13, LTC2497_SGL, "CH13"),
- LTC2497_CHAN(14, LTC2497_SGL, "CH14"),
- LTC2497_CHAN(15, LTC2497_SGL, "CH15"),
- LTC2497_CHAN_DIFF(0, LTC2497_DIFF),
- LTC2497_CHAN_DIFF(1, LTC2497_DIFF),
- LTC2497_CHAN_DIFF(2, LTC2497_DIFF),
- LTC2497_CHAN_DIFF(3, LTC2497_DIFF),
- LTC2497_CHAN_DIFF(4, LTC2497_DIFF),
- LTC2497_CHAN_DIFF(5, LTC2497_DIFF),
- LTC2497_CHAN_DIFF(6, LTC2497_DIFF),
- LTC2497_CHAN_DIFF(7, LTC2497_DIFF),
- LTC2497_CHAN_DIFF(0, LTC2497_DIFF | LTC2497_SIGN),
- LTC2497_CHAN_DIFF(1, LTC2497_DIFF | LTC2497_SIGN),
- LTC2497_CHAN_DIFF(2, LTC2497_DIFF | LTC2497_SIGN),
- LTC2497_CHAN_DIFF(3, LTC2497_DIFF | LTC2497_SIGN),
- LTC2497_CHAN_DIFF(4, LTC2497_DIFF | LTC2497_SIGN),
- LTC2497_CHAN_DIFF(5, LTC2497_DIFF | LTC2497_SIGN),
- LTC2497_CHAN_DIFF(6, LTC2497_DIFF | LTC2497_SIGN),
- LTC2497_CHAN_DIFF(7, LTC2497_DIFF | LTC2497_SIGN),
-};
+/*
+ * SPD is ignored by the part during a temperature measurement, so the
+ * temperature channel carries no sampling-frequency attribute.
+ */
+#define LTC2497_TEMP_CHANNEL { \
+ .type = IIO_TEMP, \
+ .address = LTC2497_TEMP_ADDR, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_OFFSET), \
+}
+
+/*
+ * Parts with a speed mode advertise sampling_frequency on their voltage
+ * channels; the two tables are otherwise identical.
+ */
+#define LTC2497_DEFINE_CHANNELS(_name, _extra_mask) \
+static const struct iio_chan_spec _name[] = { \
+ LTC2497_CHAN(0, LTC2497_SGL, "CH0", _extra_mask), \
+ LTC2497_CHAN(1, LTC2497_SGL, "CH1", _extra_mask), \
+ LTC2497_CHAN(2, LTC2497_SGL, "CH2", _extra_mask), \
+ LTC2497_CHAN(3, LTC2497_SGL, "CH3", _extra_mask), \
+ LTC2497_CHAN(4, LTC2497_SGL, "CH4", _extra_mask), \
+ LTC2497_CHAN(5, LTC2497_SGL, "CH5", _extra_mask), \
+ LTC2497_CHAN(6, LTC2497_SGL, "CH6", _extra_mask), \
+ LTC2497_CHAN(7, LTC2497_SGL, "CH7", _extra_mask), \
+ LTC2497_CHAN(8, LTC2497_SGL, "CH8", _extra_mask), \
+ LTC2497_CHAN(9, LTC2497_SGL, "CH9", _extra_mask), \
+ LTC2497_CHAN(10, LTC2497_SGL, "CH10", _extra_mask), \
+ LTC2497_CHAN(11, LTC2497_SGL, "CH11", _extra_mask), \
+ LTC2497_CHAN(12, LTC2497_SGL, "CH12", _extra_mask), \
+ LTC2497_CHAN(13, LTC2497_SGL, "CH13", _extra_mask), \
+ LTC2497_CHAN(14, LTC2497_SGL, "CH14", _extra_mask), \
+ LTC2497_CHAN(15, LTC2497_SGL, "CH15", _extra_mask), \
+ LTC2497_CHAN_DIFF(0, LTC2497_DIFF, _extra_mask), \
+ LTC2497_CHAN_DIFF(1, LTC2497_DIFF, _extra_mask), \
+ LTC2497_CHAN_DIFF(2, LTC2497_DIFF, _extra_mask), \
+ LTC2497_CHAN_DIFF(3, LTC2497_DIFF, _extra_mask), \
+ LTC2497_CHAN_DIFF(4, LTC2497_DIFF, _extra_mask), \
+ LTC2497_CHAN_DIFF(5, LTC2497_DIFF, _extra_mask), \
+ LTC2497_CHAN_DIFF(6, LTC2497_DIFF, _extra_mask), \
+ LTC2497_CHAN_DIFF(7, LTC2497_DIFF, _extra_mask), \
+ LTC2497_CHAN_DIFF(0, LTC2497_DIFF | LTC2497_SIGN, _extra_mask), \
+ LTC2497_CHAN_DIFF(1, LTC2497_DIFF | LTC2497_SIGN, _extra_mask), \
+ LTC2497_CHAN_DIFF(2, LTC2497_DIFF | LTC2497_SIGN, _extra_mask), \
+ LTC2497_CHAN_DIFF(3, LTC2497_DIFF | LTC2497_SIGN, _extra_mask), \
+ LTC2497_CHAN_DIFF(4, LTC2497_DIFF | LTC2497_SIGN, _extra_mask), \
+ LTC2497_CHAN_DIFF(5, LTC2497_DIFF | LTC2497_SIGN, _extra_mask), \
+ LTC2497_CHAN_DIFF(6, LTC2497_DIFF | LTC2497_SIGN, _extra_mask), \
+ LTC2497_CHAN_DIFF(7, LTC2497_DIFF | LTC2497_SIGN, _extra_mask), \
+ LTC2497_TEMP_CHANNEL, \
+}
+
+LTC2497_DEFINE_CHANNELS(ltc2497core_channel, 0);
+LTC2497_DEFINE_CHANNELS(ltc2497core_channel_samp_freq, BIT(IIO_CHAN_INFO_SAMP_FREQ));
static const struct iio_info ltc2497core_info = {
.read_raw = ltc2497core_read_raw,
+ .read_avail = ltc2497core_read_avail,
+ .write_raw = ltc2497core_write_raw,
};
int ltc2497core_probe(struct device *dev, struct iio_dev *indio_dev)
@@ -182,8 +370,15 @@ int ltc2497core_probe(struct device *dev, struct iio_dev *indio_dev)
indio_dev->info = <c2497core_info;
indio_dev->modes = INDIO_DIRECT_MODE;
- indio_dev->channels = ltc2497core_channel;
- indio_dev->num_channels = ARRAY_SIZE(ltc2497core_channel);
+ if (ddata->chip_info->has_speed_mode)
+ indio_dev->channels = ltc2497core_channel_samp_freq;
+ else
+ indio_dev->channels = ltc2497core_channel;
+ /* Only the ltc2499 has a temperature channel; it is the last entry. */
+ if (ddata->chip_info->has_temp)
+ indio_dev->num_channels = ARRAY_SIZE(ltc2497core_channel);
+ else
+ indio_dev->num_channels = ARRAY_SIZE(ltc2497core_channel) - 1;
ret = ddata->result_and_measure(ddata, LTC2497_CONFIG_DEFAULT, NULL);
if (ret < 0)
@@ -209,6 +404,8 @@ int ltc2497core_probe(struct device *dev, struct iio_dev *indio_dev)
ddata->addr_prev = LTC2497_CONFIG_DEFAULT;
ddata->time_prev = ktime_get();
+ /* Power-on default mode is 1x; a conversion is already in flight. */
+ ddata->conv_time_prev = LTC2497_CONV_TIME_1X_MS;
mutex_init(&ddata->lock);
diff --git a/drivers/iio/adc/ltc2497.c b/drivers/iio/adc/ltc2497.c
index c1668b5a351e..15458d4e21a1 100644
--- a/drivers/iio/adc/ltc2497.c
+++ b/drivers/iio/adc/ltc2497.c
@@ -84,6 +84,46 @@ static int ltc2497_result_and_measure(struct ltc2497core_driverdata *ddata,
return 0;
}
+ /*
+ * Parts with a second config byte (LTC2499: internal PTAT sensor and/or
+ * the 2x speed mode) latch their converter configuration from that byte
+ * and only re-evaluate it when EN2 is set; a single byte, or a second
+ * byte with EN2 = 0, means "keep previous". A one-byte channel select
+ * therefore cannot pull the device back out of temperature mode, so a
+ * voltage read after a temperature read would keep returning the PTAT
+ * result. Always drive the second byte with EN2 set on these parts:
+ * - temperature read: IM = 1 (SPD is ignored by the part in
+ * temperature mode and is left 0 here);
+ * - voltage read: IM = 0 (external input), plus SPD when 2x is
+ * selected.
+ * FA = FB = 0 keeps the power-on simultaneous 50/60Hz rejection, whose
+ * worst-case conversion time the driver's wait already covers.
+ *
+ * The byte could be skipped while the latched configuration is already
+ * the one wanted; it is sent on every conversion for simplicity.
+ */
+ if (ddata->chip_info->has_temp || ddata->chip_info->has_speed_mode) {
+ u8 cmd[2];
+
+ if (address == LTC2497_TEMP_ADDR) {
+ cmd[0] = LTC2497_ENABLE | LTC2497_CONFIG_DEFAULT;
+ cmd[1] = LTC2499_EN2 | LTC2499_IM;
+ } else {
+ cmd[0] = LTC2497_ENABLE | address;
+ cmd[1] = LTC2499_EN2;
+ if (ddata->speed_2x)
+ cmd[1] |= LTC2499_SPD;
+ }
+
+ ret = i2c_master_send(st->client, cmd, sizeof(cmd));
+ if (ret < 0) {
+ dev_err(&st->client->dev, "i2c transfer failed: %pe\n",
+ ERR_PTR(ret));
+ return ret;
+ }
+ return 0;
+ }
+
ret = i2c_smbus_write_byte(st->client,
LTC2497_ENABLE | address);
if (ret)
@@ -137,6 +177,8 @@ static const struct ltc2497_chip_info ltc2497_info[] = {
[TYPE_LTC2499] = {
.resolution = 24,
.name = "ltc2499",
+ .has_temp = true,
+ .has_speed_mode = true,
},
};
diff --git a/drivers/iio/adc/ltc2497.h b/drivers/iio/adc/ltc2497.h
index 64e81c95a3dd..cee9a2f50b82 100644
--- a/drivers/iio/adc/ltc2497.h
+++ b/drivers/iio/adc/ltc2497.h
@@ -2,11 +2,35 @@
#define LTC2497_ENABLE 0xA0
#define LTC2497_CONFIG_DEFAULT LTC2497_ENABLE
-#define LTC2497_CONVERSION_TIME_MS 150ULL
+
+/*
+ * Conversion-time bounds used to gate reads. Each value is the datasheet
+ * t_CONV maximum, rounded UP to the next whole millisecond.
+ *
+ * The 2x mode (LTC2499_SPD, LTC2499 only) disables the offset auto-calibration
+ * to roughly double the output rate; adding the 2x wait time is what makes the
+ * SPD control actually faster.
+ */
+#define LTC2497_CONV_TIME_1X_MS 150ULL /* ceil(t_CONV_1 simult. max 149.9) */
+#define LTC2499_CONV_TIME_2X_MS 76ULL /* ceil(t_CONV_2 simult. max 75.1) */
+
+/*
+ * Sentinel passed as `address` to result_and_measure() to request a
+ * temperature conversion instead of a voltage channel. Valid channel
+ * addresses fit in 5 bits (0x00–0x1F), so 0xFF is unambiguous.
+ */
+#define LTC2497_TEMP_ADDR 0xFF
+
+/* Second config-byte bits (LTC2499 / LTC2493 only) */
+#define LTC2499_EN2 BIT(7) /* enable second config byte */
+#define LTC2499_IM BIT(6) /* 1 = measure internal temp sensor */
+#define LTC2499_SPD BIT(3) /* 1 = 2x output rate (offset cal off) */
struct ltc2497_chip_info {
- u32 resolution;
const char *name;
+ u32 resolution;
+ bool has_temp;
+ bool has_speed_mode; /* SPD bit in the 2nd config byte (LTC2499/LTC2493) */
};
struct ltc2497core_driverdata {
@@ -16,6 +40,9 @@ struct ltc2497core_driverdata {
struct mutex lock;
const struct ltc2497_chip_info *chip_info;
u8 addr_prev;
+ bool speed_2x; /* SPD: false = 1x (default), true = 2x */
+ /* Conversion time (ms) of the conversion currently in flight. */
+ unsigned int conv_time_prev;
int (*result_and_measure)(struct ltc2497core_driverdata *ddata,
u8 address, int *val);
};
diff --git a/drivers/iio/adc/max11205.c b/drivers/iio/adc/max11205.c
index 63b6561dcf47..53ac2f4f383e 100644
--- a/drivers/iio/adc/max11205.c
+++ b/drivers/iio/adc/max11205.c
@@ -117,6 +117,8 @@ static int max11205_probe(struct spi_device *spi)
ad_sd_init(&st->sd, indio_dev, spi, &max11205_sigma_delta_info);
st->chip_info = spi_get_device_match_data(spi);
+ if (!st->chip_info)
+ return -ENODATA;
indio_dev->name = st->chip_info->name;
indio_dev->modes = INDIO_DIRECT_MODE;
diff --git a/drivers/iio/adc/max14001.c b/drivers/iio/adc/max14001.c
index 58adeac62dde..7694fbb6a9fd 100644
--- a/drivers/iio/adc/max14001.c
+++ b/drivers/iio/adc/max14001.c
@@ -366,6 +366,7 @@ static const struct spi_device_id max14001_id_table[] = {
{ .name = "max14002", .driver_data = (kernel_ulong_t)&max14002_chip_info },
{ }
};
+MODULE_DEVICE_TABLE(spi, max14001_id_table);
static const struct of_device_id max14001_of_match[] = {
{ .compatible = "adi,max14001", .data = &max14001_chip_info },
diff --git a/drivers/iio/adc/max40080.c b/drivers/iio/adc/max40080.c
new file mode 100644
index 000000000000..c6946eb6ff5b
--- /dev/null
+++ b/drivers/iio/adc/max40080.c
@@ -0,0 +1,574 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * MAX40080 Digital Current-Sense Amplifier driver
+ *
+ * Copyright 2026 Analog Devices, Inc.
+ *
+ * Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/MAX40080.pdf
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+
+#define MAX40080_REG_CFG 0x00
+#define MAX40080_CFG_MODE_MSK GENMASK(2, 0)
+#define MAX40080_CFG_PEC_EN_MSK BIT(5)
+#define MAX40080_CFG_RANGE_MSK BIT(6)
+#define MAX40080_CFG_FILTER_MSK GENMASK(14, 12)
+
+#define MAX40080_REG_FIFO_CFG 0x0A
+#define MAX40080_FIFO_CFG_STORE_IV_MSK GENMASK(1, 0)
+
+#define MAX40080_REG_IV 0x10
+/* Current is a 13-bit two's-complement value (magnitude + sign bit). */
+#define MAX40080_IV_I_MSK GENMASK(12, 0)
+#define MAX40080_IV_I_SIGN_BIT 12
+#define MAX40080_IV_V_MAG_MSK GENMASK(27, 16)
+#define MAX40080_IV_VALID_MSK BIT(31)
+
+/* CFG.mode field values. */
+#define MAX40080_CFG_MODE_STDBY 0x00
+#define MAX40080_CFG_MODE_SINGLE 0x02
+
+/* CFG.range field values. */
+#define MAX40080_CFG_RANGE_50mV 0
+#define MAX40080_CFG_RANGE_10mV 1
+
+/* FIFO_CFG.store_iv field values. */
+#define MAX40080_FIFO_CFG_STORE_IV 0x02
+
+#define MAX40080_ADC_RES_BITS 12
+#define MAX40080_INTER_VREF_mV 1250
+#define MAX40080_V_BUFF_GAIN 30
+#define MAX40080_CSA_50mV_GAIN 25
+#define MAX40080_CSA_10mV_GAIN 125
+
+/*
+ * The RANGE field (CFG bit 6) selects one of two current-sense full-scale
+ * ranges (the MAX40080 supports exactly two: +/-50 mV and +/-10 mV). Indexed
+ * by the CFG.range field value.
+ */
+static const int max40080_csa_gain[] = {
+ [MAX40080_CFG_RANGE_50mV] = MAX40080_CSA_50mV_GAIN,
+ [MAX40080_CFG_RANGE_10mV] = MAX40080_CSA_10mV_GAIN,
+};
+
+struct max40080_state {
+ struct i2c_client *client;
+ /* Serializes read-modify-write access to the CFG register. */
+ struct mutex lock;
+ u32 shunt_resistor_uOhm;
+ /* Cached configuration: the selected RANGE index and oversampling ratio. */
+ unsigned int range;
+ int oversampling_ratio;
+ /*
+ * Precomputed current scale (mA per code) for each RANGE setting, as
+ * {integer, nano} pairs for IIO_VAL_INT_PLUS_NANO. The range is
+ * selected by writing the corresponding scale.
+ */
+ int current_scale[2][2];
+};
+
+static const int max40080_oversampling_avail[] = { 1, 8, 16, 32, 64, 128 };
+
+static int max40080_update_bits(struct max40080_state *st, u8 reg,
+ u16 mask, u16 val)
+{
+ int tmp;
+
+ tmp = i2c_smbus_read_word_data(st->client, reg);
+ if (tmp < 0)
+ return tmp;
+
+ tmp = (tmp & ~mask) | (val & mask);
+
+ return i2c_smbus_write_word_data(st->client, reg, tmp);
+}
+
+/*
+ * In single-measurement mode the device sits idle until it receives an SMBus
+ * Quick Command, then performs exactly one current and one voltage conversion
+ * and returns to idle. Triggering on demand this way (rather than running the
+ * FIFO continuously in active mode) means each read returns a fresh, coherent
+ * current/voltage pair instead of the oldest queued FIFO entry.
+ */
+static int max40080_trigger_measurement(struct max40080_state *st)
+{
+ return i2c_smbus_xfer(st->client->adapter, st->client->addr,
+ st->client->flags, I2C_SMBUS_WRITE, 0,
+ I2C_SMBUS_QUICK, NULL);
+}
+
+/*
+ * A single measurement holds the matched current/voltage pair in one 32-bit
+ * word (MAX40080_REG_IV). Reading all four bytes in one transaction returns
+ * both from the same conversion; reading the separate current (0x0C) and
+ * voltage (0x0E) registers would decorrelate the two channels.
+ *
+ * Unlike the word accesses used elsewhere, this is a plain I2C block read: the
+ * SMBus layer does not append or verify a PEC byte for it even when PEC is
+ * otherwise enabled for the device, so this transfer is not PEC protected.
+ */
+static int max40080_read_iv_once(struct max40080_state *st, u32 *iv)
+{
+ __le32 buf = 0;
+ int ret;
+
+ ret = i2c_smbus_read_i2c_block_data(st->client, MAX40080_REG_IV,
+ sizeof(buf), (u8 *)&buf);
+ if (ret < 0)
+ return ret;
+
+ *iv = le32_to_cpu(buf);
+
+ return 0;
+}
+
+static int max40080_read_iv(struct max40080_state *st, u32 *iv)
+{
+ u32 tmp = 0;
+ int ret, io_ret;
+
+ guard(mutex)(&st->lock);
+
+ ret = max40080_trigger_measurement(st);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Wait for the conversion to complete by polling the FIFO valid bit
+ * (or bail out on an I2C error). Polling the device's own status makes
+ * this independent of the actual conversion time, which varies with the
+ * oversampling ratio and the bus speed. The timeout is only a safety
+ * ceiling: the worst case is the maximum 128x averaging on both the
+ * current and voltage channels at the slowest 15 ksps base rate plus
+ * the inter-channel switching time, i.e. roughly 20 ms; 50 ms leaves
+ * ample margin.
+ */
+ ret = read_poll_timeout(max40080_read_iv_once, io_ret,
+ io_ret || (tmp & MAX40080_IV_VALID_MSK),
+ 500, 50 * USEC_PER_MSEC, false, st, &tmp);
+ if (io_ret)
+ return io_ret;
+
+ /*
+ * Propagate the last-read value even on timeout so the caller can
+ * inspect it for debugging.
+ */
+ *iv = tmp;
+
+ return ret;
+}
+
+static int max40080_get_current(struct max40080_state *st, int *val)
+{
+ u32 iv;
+ int ret;
+
+ ret = max40080_read_iv(st, &iv);
+ if (ret)
+ return ret;
+
+ *val = sign_extend32(FIELD_GET(MAX40080_IV_I_MSK, iv),
+ MAX40080_IV_I_SIGN_BIT);
+
+ return 0;
+}
+
+static int max40080_get_voltage(struct max40080_state *st, int *val)
+{
+ u32 iv;
+ int ret;
+
+ ret = max40080_read_iv(st, &iv);
+ if (ret)
+ return ret;
+
+ *val = FIELD_GET(MAX40080_IV_V_MAG_MSK, iv);
+
+ return 0;
+}
+
+static int max40080_set_range(struct max40080_state *st, unsigned int range)
+{
+ int ret;
+
+ ret = max40080_update_bits(st, MAX40080_REG_CFG, MAX40080_CFG_RANGE_MSK,
+ FIELD_PREP(MAX40080_CFG_RANGE_MSK, range));
+ if (ret)
+ return ret;
+
+ WRITE_ONCE(st->range, range);
+
+ return 0;
+}
+
+/*
+ * Precompute the current scale (mA per code) for each RANGE setting as
+ * {integer, nano} pairs. The shunt drop for a full-scale code is
+ * Vref[mV] / (BIT(ADC_RES_BITS) * gain)
+ * and current = Vshunt / Rshunt, so with Rshunt in micro-ohms the scale in
+ * mA/code is
+ * Vref[mV] * NANO * MICRO / (BIT(ADC_RES_BITS) * gain * Rshunt[uOhm])
+ * expressed as an integer part plus a nano fractional part.
+ */
+static void max40080_calc_current_scale(struct max40080_state *st)
+{
+ u64 numerator, denominator;
+ u32 rem;
+
+ for (unsigned int i = 0; i < ARRAY_SIZE(max40080_csa_gain); i++) {
+ numerator = (u64)MAX40080_INTER_VREF_mV * NANO * MICRO;
+ denominator = BIT_ULL(MAX40080_ADC_RES_BITS) * max40080_csa_gain[i] *
+ st->shunt_resistor_uOhm;
+ numerator = div64_u64(numerator, denominator);
+ st->current_scale[i][0] = div_u64_rem(numerator, NANO, &rem);
+ st->current_scale[i][1] = rem;
+ }
+}
+
+/*
+ * max40080_oversampling_avail[] is ordered so that its index is the FILTER
+ * field value (index 0 = no averaging, index 1 = 8x, ...). Return that index
+ * for an exact match, or -EINVAL for a value that is not on the list.
+ */
+static int max40080_oversampling_to_filter(int val)
+{
+ for (unsigned int i = 0; i < ARRAY_SIZE(max40080_oversampling_avail); i++) {
+ if (max40080_oversampling_avail[i] == val)
+ return i;
+ }
+
+ return -EINVAL;
+}
+
+static int max40080_set_oversampling_ratio(struct max40080_state *st, int val)
+{
+ int filter;
+ int ret;
+
+ filter = max40080_oversampling_to_filter(val);
+ if (filter < 0)
+ return filter;
+
+ ret = max40080_update_bits(st, MAX40080_REG_CFG, MAX40080_CFG_FILTER_MSK,
+ FIELD_PREP(MAX40080_CFG_FILTER_MSK, filter));
+ if (ret)
+ return ret;
+
+ WRITE_ONCE(st->oversampling_ratio, val);
+
+ return 0;
+}
+
+static int max40080_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct max40080_state *st = iio_priv(indio_dev);
+ unsigned int range;
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ if (chan->type == IIO_CURRENT) {
+ ret = max40080_get_current(st, val);
+ if (ret)
+ return ret;
+ } else if (chan->type == IIO_VOLTAGE) {
+ ret = max40080_get_voltage(st, val);
+ if (ret)
+ return ret;
+ }
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ if (chan->type == IIO_CURRENT) {
+ /*
+ * The selectable current-sense range is exposed through
+ * scale: each RANGE setting has its own precomputed
+ * mA-per-code value. Userspace picks the range by
+ * writing the matching scale.
+ *
+ * Use READ_ONCE to ensure the compiler reads st->range
+ * exactly once, so val and val2 come from the same
+ * setting even if a concurrent write changes st->range.
+ */
+ range = READ_ONCE(st->range);
+ *val = st->current_scale[range][0];
+ *val2 = st->current_scale[range][1];
+ return IIO_VAL_INT_PLUS_NANO;
+ }
+ /* voltage[mV] = raw * Vref[mV] * buffer_gain / BIT(ADC_RES_BITS) */
+ *val = MAX40080_INTER_VREF_mV * MAX40080_V_BUFF_GAIN;
+ *val2 = MAX40080_ADC_RES_BITS;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ *val = READ_ONCE(st->oversampling_ratio);
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int max40080_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct max40080_state *st = iio_priv(indio_dev);
+
+ guard(mutex)(&st->lock);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ /* Only the current channel has a selectable range/scale. */
+ if (chan->type != IIO_CURRENT)
+ return -EINVAL;
+
+ for (unsigned int i = 0; i < ARRAY_SIZE(max40080_csa_gain); i++) {
+ if (val == st->current_scale[i][0] &&
+ val2 == st->current_scale[i][1])
+ return max40080_set_range(st, i);
+ }
+
+ return -EINVAL;
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ return max40080_set_oversampling_ratio(st, val);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int max40080_write_raw_get_fmt(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ long mask)
+{
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ return IIO_VAL_INT_PLUS_NANO;
+ default:
+ return IIO_VAL_INT;
+ }
+}
+
+static int max40080_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long info)
+{
+ struct max40080_state *st = iio_priv(indio_dev);
+
+ switch (info) {
+ case IIO_CHAN_INFO_SCALE:
+ if (chan->type != IIO_CURRENT)
+ return -EINVAL;
+
+ *vals = (int *)st->current_scale;
+ *length = ARRAY_SIZE(max40080_csa_gain) * 2;
+ *type = IIO_VAL_INT_PLUS_NANO;
+ return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ *vals = max40080_oversampling_avail;
+ *length = ARRAY_SIZE(max40080_oversampling_avail);
+ *type = IIO_VAL_INT;
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int max40080_reg_access(struct iio_dev *indio_dev, unsigned int reg,
+ unsigned int write_val, unsigned int *read_val)
+{
+ struct max40080_state *st = iio_priv(indio_dev);
+ int val;
+
+ if (read_val) {
+ val = i2c_smbus_read_word_data(st->client, reg);
+ if (val < 0)
+ return val;
+
+ *read_val = val;
+
+ return 0;
+ }
+
+ return i2c_smbus_write_word_data(st->client, reg, write_val);
+}
+
+static const struct iio_info max40080_info = {
+ .read_raw = max40080_read_raw,
+ .write_raw = max40080_write_raw,
+ .write_raw_get_fmt = max40080_write_raw_get_fmt,
+ .read_avail = max40080_read_avail,
+ .debugfs_reg_access = &max40080_reg_access,
+};
+
+static const struct iio_chan_spec max40080_channels[] = {
+ {
+ .type = IIO_CURRENT,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ .info_mask_separate_available = BIT(IIO_CHAN_INFO_SCALE),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_all_available =
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ },
+ {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_all_available =
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ },
+};
+
+/*
+ * Configure the device from the cached state. The device powers up in standby
+ * with PEC enabled (CFG POR = 0x0060), so PEC is kept enabled throughout.
+ */
+static int max40080_init(struct max40080_state *st)
+{
+ u16 fifo_cfg, cfg;
+ int ret, filter;
+
+ filter = max40080_oversampling_to_filter(st->oversampling_ratio);
+ if (filter < 0)
+ return filter;
+
+ /*
+ * Put the device in standby before (re)configuring the FIFO: the FIFO
+ * configuration register can only be written while the device is not
+ * converting.
+ */
+ cfg = FIELD_PREP(MAX40080_CFG_MODE_MSK, MAX40080_CFG_MODE_STDBY) |
+ FIELD_PREP(MAX40080_CFG_PEC_EN_MSK, 1);
+ ret = i2c_smbus_write_word_data(st->client, MAX40080_REG_CFG, cfg);
+ if (ret)
+ return ret;
+
+ /* Store a matched current+voltage pair per conversion. */
+ fifo_cfg = FIELD_PREP(MAX40080_FIFO_CFG_STORE_IV_MSK, MAX40080_FIFO_CFG_STORE_IV);
+ ret = i2c_smbus_write_word_data(st->client, MAX40080_REG_FIFO_CFG,
+ fifo_cfg);
+ if (ret)
+ return ret;
+
+ /*
+ * Use single-measurement mode: the device stays idle and converts once
+ * per SMBus Quick Command (see max40080_trigger_measurement()), so each
+ * read returns a fresh sample rather than a queued FIFO entry.
+ */
+ cfg = FIELD_PREP(MAX40080_CFG_MODE_MSK, MAX40080_CFG_MODE_SINGLE) |
+ FIELD_PREP(MAX40080_CFG_PEC_EN_MSK, 1) |
+ FIELD_PREP(MAX40080_CFG_RANGE_MSK, st->range) |
+ FIELD_PREP(MAX40080_CFG_FILTER_MSK, filter);
+
+ return i2c_smbus_write_word_data(st->client, MAX40080_REG_CFG, cfg);
+}
+
+static int max40080_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ const char *propname;
+ struct iio_dev *indio_dev;
+ struct max40080_state *st;
+ int ret;
+
+ /*
+ * The device powers up with PEC enabled (CFG POR = 0x0060) and rejects
+ * unprotected transactions, so PEC support is mandatory, along with
+ * word access, the I2C block read used for the current/voltage pair,
+ * and the Quick Command used to trigger a conversion.
+ */
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_I2C_BLOCK |
+ I2C_FUNC_SMBUS_QUICK |
+ I2C_FUNC_SMBUS_PEC))
+ return -EOPNOTSUPP;
+
+ client->flags |= I2C_CLIENT_PEC;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+ st->client = client;
+
+ ret = devm_mutex_init(dev, &st->lock);
+ if (ret)
+ return ret;
+
+ propname = "shunt-resistor-micro-ohms";
+ ret = device_property_read_u32(dev, propname, &st->shunt_resistor_uOhm);
+ if (ret)
+ return dev_err_probe(dev, ret, "can't read %s\n", propname);
+ if (!st->shunt_resistor_uOhm)
+ return dev_err_probe(dev, -EINVAL, "%s must be non-zero\n", propname);
+
+ max40080_calc_current_scale(st);
+
+ /* Defaults: 50 mV range, no averaging. */
+ st->range = MAX40080_CFG_RANGE_50mV;
+ st->oversampling_ratio = 1;
+
+ indio_dev->name = "max40080";
+ indio_dev->info = &max40080_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = max40080_channels;
+ indio_dev->num_channels = ARRAY_SIZE(max40080_channels);
+
+ ret = max40080_init(st);
+ if (ret)
+ return ret;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct i2c_device_id max40080_i2c_ids[] = {
+ { .name = "max40080" },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, max40080_i2c_ids);
+
+static const struct of_device_id max40080_of_match[] = {
+ { .compatible = "adi,max40080" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, max40080_of_match);
+
+static struct i2c_driver max40080_driver = {
+ .driver = {
+ .name = "max40080",
+ .of_match_table = max40080_of_match,
+ },
+ .probe = max40080_probe,
+ .id_table = max40080_i2c_ids,
+};
+module_i2c_driver(max40080_driver);
+
+MODULE_AUTHOR("Ciprian Hegbeli ");
+MODULE_AUTHOR("Stefan Popa ");
+MODULE_DESCRIPTION("Analog Devices MAX40080 current-sense amplifier driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/adc/mcp3911.c b/drivers/iio/adc/mcp3911.c
index 797424f59f74..90167930f913 100644
--- a/drivers/iio/adc/mcp3911.c
+++ b/drivers/iio/adc/mcp3911.c
@@ -721,6 +721,8 @@ static int mcp3911_probe(struct spi_device *spi)
adc = iio_priv(indio_dev);
adc->spi = spi;
adc->chip = spi_get_device_match_data(spi);
+ if (!adc->chip)
+ return -ENODATA;
ret = devm_regulator_get_enable_read_voltage(dev, "vref");
if (ret < 0 && ret != -ENODEV)
diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c
index 000e39ca5c62..2b003fd5afeb 100644
--- a/drivers/iio/adc/meson_saradc.c
+++ b/drivers/iio/adc/meson_saradc.c
@@ -739,7 +739,7 @@ static int meson_sar_adc_clk_init(struct iio_dev *indio_dev,
{
struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
struct device *dev = indio_dev->dev.parent;
- struct clk_init_data init;
+ struct clk_init_data init = { };
const char *clk_parents[1];
init.name = devm_kasprintf(dev, GFP_KERNEL, "%s#adc_div", dev_name(dev));
diff --git a/drivers/iio/adc/nxp-sar-adc.c b/drivers/iio/adc/nxp-sar-adc.c
index 894d3211b283..2f716a2f97b8 100644
--- a/drivers/iio/adc/nxp-sar-adc.c
+++ b/drivers/iio/adc/nxp-sar-adc.c
@@ -604,7 +604,7 @@ static void nxp_sar_adc_dma_cb(void *data)
dma_buf = &info->dma_buf;
dma_samples = (u32 *)dma_buf->buf;
- dev_dma = info->dma_chan->device->dev;
+ dev_dma = dmaengine_get_dma_device(info->dma_chan);
/*
* DMA in some corner cases might have already be charged for
diff --git a/drivers/iio/adc/pac1934.c b/drivers/iio/adc/pac1934.c
index 23055405a6e0..2d934452eb11 100644
--- a/drivers/iio/adc/pac1934.c
+++ b/drivers/iio/adc/pac1934.c
@@ -19,6 +19,7 @@
#include
#include
#include
+#include
#include
/*
@@ -494,11 +495,13 @@ static ssize_t pac1934_shunt_value_store(struct device *dev,
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct pac1934_chip_info *info = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
- int sh_val;
+ unsigned int sh_val;
+ int ret;
- if (kstrtouint(buf, 10, &sh_val)) {
+ ret = kstrtouint(buf, 10, &sh_val);
+ if (ret) {
dev_err(dev, "Shunt value is not valid\n");
- return -EINVAL;
+ return ret;
}
scoped_guard(mutex, &info->lock)
diff --git a/drivers/iio/adc/rockchip_saradc.c b/drivers/iio/adc/rockchip_saradc.c
index 0f0bf2906af0..5c45fae11890 100644
--- a/drivers/iio/adc/rockchip_saradc.c
+++ b/drivers/iio/adc/rockchip_saradc.c
@@ -348,6 +348,19 @@ static const struct rockchip_saradc_data rk3588_saradc_data = {
.read = rockchip_saradc_read_v2,
};
+static const struct iio_chan_spec rockchip_rv1106_saradc_iio_channels[] = {
+ SARADC_CHANNEL(0, "adc0", 10),
+ SARADC_CHANNEL(1, "adc1", 10),
+};
+
+static const struct rockchip_saradc_data rv1106_saradc_data = {
+ .channels = rockchip_rv1106_saradc_iio_channels,
+ .num_channels = ARRAY_SIZE(rockchip_rv1106_saradc_iio_channels),
+ .clk_rate = 1000000,
+ .start = rockchip_saradc_start_v2,
+ .read = rockchip_saradc_read_v2,
+};
+
static const struct of_device_id rockchip_saradc_match[] = {
{
.compatible = "rockchip,saradc",
@@ -370,6 +383,9 @@ static const struct of_device_id rockchip_saradc_match[] = {
}, {
.compatible = "rockchip,rk3588-saradc",
.data = &rk3588_saradc_data,
+ }, {
+ .compatible = "rockchip,rv1106-saradc",
+ .data = &rv1106_saradc_data,
},
{ }
};
diff --git a/drivers/iio/adc/rzg2l_adc.c b/drivers/iio/adc/rzg2l_adc.c
index 408fbf8c29cc..3b95f47445a8 100644
--- a/drivers/iio/adc/rzg2l_adc.c
+++ b/drivers/iio/adc/rzg2l_adc.c
@@ -62,7 +62,7 @@
* @adsmp_mask: ADC sampling period mask (see ADM3 register)
* @adint_inten_mask: conversion end interrupt mask (see ADINT register)
* @default_adcmp: default ADC cmp (see ADM3 register)
- * @num_channels: number of supported channels
+ * @max_channels: maximum number of channels
* @adivc: specifies if ADVIC register is available
*/
struct rzg2l_adc_hw_params {
@@ -70,7 +70,7 @@ struct rzg2l_adc_hw_params {
u16 adsmp_mask;
u16 adint_inten_mask;
u8 default_adcmp;
- u8 num_channels;
+ u8 max_channels;
bool adivc;
};
@@ -196,7 +196,7 @@ static int rzg2l_adc_conversion_setup(struct rzg2l_adc *adc, u8 ch)
/* Select analog input channel subjected to conversion. */
reg = rzg2l_adc_readl(adc, RZG2L_ADM(2));
- reg &= ~GENMASK(hw_params->num_channels - 1, 0);
+ reg &= ~GENMASK(hw_params->max_channels - 1, 0);
reg |= BIT(ch);
rzg2l_adc_writel(adc, RZG2L_ADM(2), reg);
@@ -307,11 +307,11 @@ static irqreturn_t rzg2l_adc_isr(int irq, void *dev_id)
return IRQ_HANDLED;
}
- intst = reg & GENMASK(hw_params->num_channels - 1, 0);
+ intst = reg & GENMASK(hw_params->max_channels - 1, 0);
if (!intst)
return IRQ_NONE;
- for_each_set_bit(ch, &intst, hw_params->num_channels)
+ for_each_set_bit(ch, &intst, hw_params->max_channels)
adc->last_val[ch] = rzg2l_adc_readl(adc, RZG2L_ADCR(ch)) & RZG2L_ADCR_AD_MASK;
/* clear the channel interrupt */
@@ -341,12 +341,12 @@ static int rzg2l_adc_parse_properties(struct platform_device *pdev, struct rzg2l
num_channels = devm_iio_adc_device_alloc_chaninfo_se(&pdev->dev,
&rzg2l_adc_chan_template,
- hw_params->num_channels - 1,
+ hw_params->max_channels - 1,
&chan_array);
if (num_channels < 0)
return num_channels;
- if (num_channels > hw_params->num_channels)
+ if (num_channels > hw_params->max_channels)
return dev_err_probe(&pdev->dev, -EINVAL,
"num of channel children out of range\n");
@@ -429,7 +429,7 @@ static int rzg2l_adc_probe(struct platform_device *pdev)
adc = iio_priv(indio_dev);
adc->hw_params = device_get_match_data(dev);
- if (!adc->hw_params || adc->hw_params->num_channels > RZG2L_ADC_MAX_CHANNELS)
+ if (!adc->hw_params || adc->hw_params->max_channels > RZG2L_ADC_MAX_CHANNELS)
return -EINVAL;
ret = rzg2l_adc_parse_properties(pdev, adc);
@@ -484,7 +484,7 @@ static int rzg2l_adc_probe(struct platform_device *pdev)
}
static const struct rzg2l_adc_hw_params rzg2l_hw_params = {
- .num_channels = 8,
+ .max_channels = 8,
.default_adcmp = 0xe,
.default_adsmp = { 0x578 },
.adsmp_mask = GENMASK(15, 0),
@@ -493,15 +493,24 @@ static const struct rzg2l_adc_hw_params rzg2l_hw_params = {
};
static const struct rzg2l_adc_hw_params rzg3s_hw_params = {
- .num_channels = 9,
+ .max_channels = 9,
.default_adcmp = 0x1d,
.default_adsmp = { 0x7f, 0xff },
.adsmp_mask = GENMASK(7, 0),
.adint_inten_mask = GENMASK(11, 0),
};
+static const struct rzg2l_adc_hw_params rzg3l_adc1_hw_params = {
+ .max_channels = 9,
+ .default_adcmp = 0x1d,
+ .default_adsmp = { 0x7f, 0xff },
+ .adsmp_mask = GENMASK(7, 0),
+ .adint_inten_mask = BIT(8),
+};
+
static const struct of_device_id rzg2l_adc_match[] = {
{ .compatible = "renesas,r9a08g045-adc", .data = &rzg3s_hw_params },
+ { .compatible = "renesas,r9a08g046-adc1", .data = &rzg3l_adc1_hw_params },
{ .compatible = "renesas,rzg2l-adc", .data = &rzg2l_hw_params },
{ }
};
diff --git a/drivers/iio/adc/rzt2h_adc.c b/drivers/iio/adc/rzt2h_adc.c
index 4e0eb02d3d14..8ba7b0fde8a1 100644
--- a/drivers/iio/adc/rzt2h_adc.c
+++ b/drivers/iio/adc/rzt2h_adc.c
@@ -2,13 +2,19 @@
#include
#include
+#include
#include
#include
+#include
+#include
#include
+#include
#include
+#include
#include
#include
#include
+#include
#include
#include
#include
@@ -18,6 +24,7 @@
#define RZT2H_ADCSR_ADIE_MASK BIT(12)
#define RZT2H_ADCSR_ADCS_MASK GENMASK(14, 13)
#define RZT2H_ADCSR_ADCS_SINGLE 0b00
+#define RZT2H_ADCSR_ADCS_CONTINUOUS 0b10
#define RZT2H_ADCSR_ADST_MASK BIT(15)
#define RZT2H_ADANSA0_REG 0x04
@@ -25,24 +32,71 @@
#define RZT2H_ADDR_REG(x) (0x20 + 0x2 * (x))
+#define RZT2H_ADSSTRn(n) (0xe0 + 0x1 * (n))
+
+/*
+ * Each A/D channel conversion takes a fixed base of 13 ADCLK cycles plus the
+ * sample time programmed in ADSSTRn, giving a conversion rate of
+ * ADCLK / (13 + ADSSTRn).
+ */
+#define RZT2H_ADC_CONV_CYCLES_BASE 13
+#define RZT2H_ADC_SST_MIN 0x7
+#define RZT2H_ADC_SST_MAX 0xff
+#define RZT2H_ADC_SST_DEFAULT 0xb
+
#define RZT2H_ADCALCTL_REG 0x1f0
#define RZT2H_ADCALCTL_CAL_MASK BIT(0)
#define RZT2H_ADCALCTL_CAL_RDY_MASK BIT(1)
#define RZT2H_ADCALCTL_CAL_ERR_MASK BIT(2)
#define RZT2H_ADC_MAX_CHANNELS 16
+#define RZT2H_ADC_CHANNEL_BYTES sizeof(u16)
+#define RZT2H_ADC_DMA_PERIOD_SAMPLES 128
+#define RZT2H_ADC_DMA_PERIODS 64
+#define RZT2H_ADC_DMA_BUFFER_SAMPLES (RZT2H_ADC_DMA_PERIODS * \
+ RZT2H_ADC_DMA_PERIOD_SAMPLES)
+#define RZT2H_ADC_DMA_BUFFER_SIZE (RZT2H_ADC_DMA_BUFFER_SAMPLES * \
+ RZT2H_ADC_MAX_CHANNELS * \
+ RZT2H_ADC_CHANNEL_BYTES)
+
+struct rzt2h_adc_dma {
+ struct dma_chan *chan;
+ u16 *buf;
+ dma_addr_t addr;
+
+ unsigned int period_index;
+ unsigned int period_bytes;
+ unsigned int first_chan;
+ unsigned int sample_chans;
+
+ u8 gather[RZT2H_ADC_MAX_CHANNELS];
+ unsigned int gather_len;
+
+ atomic_t pending_periods;
+
+ wait_queue_head_t wq;
+ struct task_struct *thread;
+};
struct rzt2h_adc {
void __iomem *base;
struct device *dev;
+ phys_addr_t phys_base;
+ struct rzt2h_adc_dma dma;
struct completion completion;
/* lock to protect against multiple access to the device */
struct mutex lock;
const struct iio_chan_spec *channels;
unsigned int num_channels;
- unsigned int max_channels;
+ u16 buf[RZT2H_ADC_MAX_CHANNELS];
+
+ unsigned long adclk_rate;
+ int samp_freq_avail[3];
+ u8 sst[RZT2H_ADC_MAX_CHANNELS];
+
+ int irq;
};
static void rzt2h_adc_start(struct rzt2h_adc *adc, unsigned int conversion_type)
@@ -72,6 +126,11 @@ static void rzt2h_adc_stop(struct rzt2h_adc *adc)
writew(reg, adc->base + RZT2H_ADCSR_REG);
}
+static void rzt2h_adc_set_sst(struct rzt2h_adc *adc, unsigned int ch, u8 sst)
+{
+ writeb(sst, adc->base + RZT2H_ADSSTRn(ch));
+}
+
static int rzt2h_adc_read_single(struct rzt2h_adc *adc, unsigned int ch, int *val)
{
int ret;
@@ -87,13 +146,18 @@ static int rzt2h_adc_read_single(struct rzt2h_adc *adc, unsigned int ch, int *va
/* Enable a single channel */
writew(RZT2H_ADANSA0_CH_MASK(ch), adc->base + RZT2H_ADANSA0_REG);
+ rzt2h_adc_set_sst(adc, ch, adc->sst[ch]);
+
rzt2h_adc_start(adc, RZT2H_ADCSR_ADCS_SINGLE);
/*
- * Datasheet Page 2770, Table 41.1:
- * 0.32us per channel when sample-and-hold circuits are not in use.
+ * Conversion can take up to ~4.3us at the maximum configurable ADSSTRn
+ * (ADSSTRn + 13 cycles at 62.5 MHz), which rounds up to 1 jiffy. A bare
+ * 1-jiffy timeout can expire almost immediately if it's armed right
+ * before a tick, so add one more jiffy to guarantee the conversion time
+ * actually elapses.
*/
- ret = wait_for_completion_timeout(&adc->completion, usecs_to_jiffies(1));
+ ret = wait_for_completion_timeout(&adc->completion, usecs_to_jiffies(5) + 1);
if (!ret) {
ret = -ETIMEDOUT;
goto disable;
@@ -149,6 +213,281 @@ static int rzt2h_adc_calibrate(struct rzt2h_adc *adc)
return 0;
}
+static void rzt2h_adc_push_period(struct iio_dev *indio_dev, u16 *period,
+ dma_addr_t addr)
+{
+ struct rzt2h_adc *adc = iio_priv(indio_dev);
+ u16 *dst = adc->buf;
+ u16 *src = period;
+
+ dma_sync_single_for_cpu(adc->dev, addr, adc->dma.period_bytes,
+ DMA_FROM_DEVICE);
+
+ for (unsigned int sample = 0; sample < RZT2H_ADC_DMA_PERIOD_SAMPLES; sample++) {
+ for (unsigned int i = 0; i < adc->dma.gather_len; i++)
+ dst[i] = src[adc->dma.gather[i]];
+
+ src += adc->dma.sample_chans;
+
+ iio_push_to_buffers(indio_dev, adc->buf);
+ }
+}
+
+static void rzt2h_adc_advance_period_index(struct rzt2h_adc *adc, unsigned int i)
+{
+ adc->dma.period_index += i;
+ adc->dma.period_index %= RZT2H_ADC_DMA_PERIODS;
+}
+
+static void rzt2h_adc_dma_thread_loop(struct iio_dev *indio_dev)
+{
+ struct rzt2h_adc *adc = iio_priv(indio_dev);
+ int pending, drop;
+ dma_addr_t addr;
+ u16 *period;
+
+ pending = atomic_xchg(&adc->dma.pending_periods, 0);
+
+ if (pending >= RZT2H_ADC_DMA_PERIODS) {
+ /*
+ * The consumer fell a full buffer behind and the oldest periods
+ * have already been overwritten by the cyclic DMA transfer.
+ * Drop them and jump straight to the oldest period that has
+ * not been overwritten.
+ */
+ drop = pending - RZT2H_ADC_DMA_PERIODS + 1;
+
+ rzt2h_adc_advance_period_index(adc, drop);
+ pending -= drop;
+ }
+
+ for (unsigned int i = 0; i < pending; i++) {
+ unsigned int backlog = atomic_read(&adc->dma.pending_periods) +
+ pending - i;
+
+ /*
+ * Bail if enough new periods have completed since reading the
+ * pending_periods that the next period about to be read is at
+ * risk of being overwritten.
+ */
+ if (backlog >= RZT2H_ADC_DMA_PERIODS) {
+ rzt2h_adc_advance_period_index(adc, pending - i);
+ break;
+ }
+
+ period = adc->dma.buf + adc->dma.period_index *
+ RZT2H_ADC_DMA_PERIOD_SAMPLES * adc->dma.sample_chans;
+ addr = adc->dma.addr + adc->dma.period_index *
+ adc->dma.period_bytes;
+
+ rzt2h_adc_push_period(indio_dev, period, addr);
+ rzt2h_adc_advance_period_index(adc, 1);
+ }
+}
+
+static int rzt2h_adc_dma_thread(void *data)
+{
+ struct iio_dev *indio_dev = data;
+ struct rzt2h_adc *adc = iio_priv(indio_dev);
+
+ while (!kthread_should_stop()) {
+ wait_event_interruptible(adc->dma.wq,
+ atomic_read(&adc->dma.pending_periods) ||
+ kthread_should_stop());
+
+ if (kthread_should_stop())
+ break;
+
+ rzt2h_adc_dma_thread_loop(indio_dev);
+ }
+
+ return 0;
+}
+
+static void rzt2h_adc_dma_callback(void *data)
+{
+ struct iio_dev *indio_dev = data;
+ struct rzt2h_adc *adc = iio_priv(indio_dev);
+
+ atomic_inc(&adc->dma.pending_periods);
+ wake_up(&adc->dma.wq);
+}
+
+static void rzt2h_adc_dma_calc_layout(struct iio_dev *indio_dev)
+{
+ struct rzt2h_adc *adc = iio_priv(indio_dev);
+ unsigned int hi = 0, lo = RZT2H_ADC_MAX_CHANNELS - 1;
+ const struct iio_chan_spec *chan;
+ unsigned int sample_chans;
+ unsigned int first_chan;
+ unsigned int scan_index;
+ unsigned int swap;
+ unsigned int idx;
+
+ /* Find the lowest and highest enabled channel. */
+ iio_for_each_active_channel(indio_dev, scan_index) {
+ chan = &indio_dev->channels[scan_index];
+
+ lo = min_t(unsigned int, lo, chan->channel);
+ hi = max_t(unsigned int, hi, chan->channel);
+ }
+
+ /*
+ * The DMA has no scatter-gather and transfers must have a power-of-two
+ * width, so pick the smallest power-of-two-aligned block of channels
+ * that covers all enabled channels.
+ */
+ for (sample_chans = 1; sample_chans < RZT2H_ADC_MAX_CHANNELS; sample_chans <<= 1) {
+ first_chan = round_down(lo, sample_chans);
+
+ if (first_chan + sample_chans > hi)
+ break;
+ }
+
+ /*
+ * Build a table to map each enabled channel to its position in the
+ * transferred block, it will be used later to extract only the enabled
+ * channels out of it.
+ * The DMA moves data in 32-bit words, which swaps each pair of adjacent
+ * 16-bit channels. Undo it.
+ */
+ adc->dma.gather_len = 0;
+ swap = sample_chans > 1;
+ iio_for_each_active_channel(indio_dev, scan_index) {
+ chan = &indio_dev->channels[scan_index];
+ idx = chan->channel - first_chan;
+
+ adc->dma.gather[adc->dma.gather_len++] = idx ^ swap;
+ }
+
+ adc->dma.first_chan = first_chan;
+ adc->dma.sample_chans = sample_chans;
+ adc->dma.period_bytes = RZT2H_ADC_DMA_PERIOD_SAMPLES * sample_chans *
+ RZT2H_ADC_CHANNEL_BYTES;
+}
+
+static int rzt2h_adc_start_dma(struct iio_dev *indio_dev)
+{
+ struct rzt2h_adc *adc = iio_priv(indio_dev);
+ struct dma_async_tx_descriptor *desc;
+ struct dma_slave_config config;
+ unsigned int buffer_bytes;
+ dma_cookie_t cookie;
+ int ret;
+
+ rzt2h_adc_dma_calc_layout(indio_dev);
+
+ config = (struct dma_slave_config) {
+ .src_addr = adc->phys_base + RZT2H_ADDR_REG(adc->dma.first_chan),
+ .src_addr_width = adc->dma.sample_chans * RZT2H_ADC_CHANNEL_BYTES,
+ };
+
+ buffer_bytes = RZT2H_ADC_DMA_PERIODS * adc->dma.period_bytes;
+
+ ret = dmaengine_slave_config(adc->dma.chan, &config);
+ if (ret)
+ return ret;
+
+ desc = dmaengine_prep_dma_cyclic(adc->dma.chan, adc->dma.addr,
+ buffer_bytes, adc->dma.period_bytes,
+ DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
+ if (!desc)
+ return -EBUSY;
+
+ desc->callback = rzt2h_adc_dma_callback;
+ desc->callback_param = indio_dev;
+
+ cookie = dmaengine_submit(desc);
+ ret = dma_submit_error(cookie);
+ if (ret) {
+ dmaengine_terminate_sync(adc->dma.chan);
+ return ret;
+ }
+
+ adc->dma.thread = kthread_run(rzt2h_adc_dma_thread, indio_dev,
+ "rzt2h-adc-dma");
+ if (IS_ERR(adc->dma.thread)) {
+ dmaengine_terminate_sync(adc->dma.chan);
+ return PTR_ERR(adc->dma.thread);
+ }
+
+ disable_irq(adc->irq);
+
+ dma_async_issue_pending(adc->dma.chan);
+
+ return 0;
+}
+
+static int rzt2h_adc_buffer_postenable(struct iio_dev *indio_dev)
+{
+ struct rzt2h_adc *adc = iio_priv(indio_dev);
+ const struct iio_chan_spec *chan;
+ struct device *dev = adc->dev;
+ unsigned int scan_index;
+ u16 val = 0;
+ int ret;
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret)
+ return ret;
+
+ iio_for_each_active_channel(indio_dev, scan_index) {
+ chan = &indio_dev->channels[scan_index];
+ val |= RZT2H_ADANSA0_CH_MASK(chan->channel);
+ rzt2h_adc_set_sst(adc, chan->channel, adc->sst[chan->channel]);
+ }
+
+ writew(val, adc->base + RZT2H_ADANSA0_REG);
+
+ adc->dma.period_index = 0;
+ atomic_set(&adc->dma.pending_periods, 0);
+
+ ret = rzt2h_adc_start_dma(indio_dev);
+ if (ret) {
+ pm_runtime_put_autosuspend(dev);
+ return ret;
+ }
+
+ rzt2h_adc_start(adc, RZT2H_ADCSR_ADCS_CONTINUOUS);
+
+ return 0;
+}
+
+static int rzt2h_adc_buffer_predisable(struct iio_dev *indio_dev)
+{
+ struct rzt2h_adc *adc = iio_priv(indio_dev);
+ struct device *dev = adc->dev;
+
+ rzt2h_adc_stop(adc);
+
+ dmaengine_terminate_sync(adc->dma.chan);
+
+ kthread_stop(adc->dma.thread);
+
+ enable_irq(adc->irq);
+
+ pm_runtime_put_autosuspend(dev);
+
+ return 0;
+}
+
+static int rzt2h_adc_sst_to_freq(struct rzt2h_adc *adc, u8 sst)
+{
+ return adc->adclk_rate / (RZT2H_ADC_CONV_CYCLES_BASE + sst);
+}
+
+static u8 rzt2h_adc_freq_to_sst(struct rzt2h_adc *adc, int freq)
+{
+ unsigned int cycles;
+
+ cycles = DIV_ROUND_CLOSEST(adc->adclk_rate, freq);
+ cycles = clamp_val(cycles,
+ RZT2H_ADC_CONV_CYCLES_BASE + RZT2H_ADC_SST_MIN,
+ RZT2H_ADC_CONV_CYCLES_BASE + RZT2H_ADC_SST_MAX);
+
+ return cycles - RZT2H_ADC_CONV_CYCLES_BASE;
+}
+
static int rzt2h_adc_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
@@ -156,19 +495,76 @@ static int rzt2h_adc_read_raw(struct iio_dev *indio_dev,
struct rzt2h_adc *adc = iio_priv(indio_dev);
switch (mask) {
- case IIO_CHAN_INFO_RAW:
+ case IIO_CHAN_INFO_RAW: {
+ IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim);
+ if (IIO_DEV_ACQUIRE_FAILED(claim))
+ return -EBUSY;
+
return rzt2h_adc_read_single(adc, chan->channel, val);
+ }
case IIO_CHAN_INFO_SCALE:
*val = 1800;
*val2 = 12;
return IIO_VAL_FRACTIONAL_LOG2;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *val = rzt2h_adc_sst_to_freq(adc, adc->sst[chan->channel]);
+ return IIO_VAL_INT;
default:
return -EINVAL;
}
}
+static int rzt2h_adc_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct rzt2h_adc *adc = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ: {
+ if (val <= 0)
+ return -EINVAL;
+
+ IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim);
+ if (IIO_DEV_ACQUIRE_FAILED(claim))
+ return -EBUSY;
+
+ adc->sst[chan->channel] = rzt2h_adc_freq_to_sst(adc, val);
+
+ return 0;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int rzt2h_adc_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long mask)
+{
+ struct rzt2h_adc *adc = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *vals = adc->samp_freq_avail;
+ *type = IIO_VAL_INT;
+ *length = ARRAY_SIZE(adc->samp_freq_avail);
+ return IIO_AVAIL_RANGE;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_buffer_setup_ops rzt2h_adc_buffer_setup_ops = {
+ .postenable = rzt2h_adc_buffer_postenable,
+ .predisable = rzt2h_adc_buffer_predisable,
+};
+
static const struct iio_info rzt2h_adc_iio_info = {
.read_raw = rzt2h_adc_read_raw,
+ .write_raw = rzt2h_adc_write_raw,
+ .read_avail = rzt2h_adc_read_avail,
};
static irqreturn_t rzt2h_adc_isr(int irq, void *private)
@@ -183,14 +579,21 @@ static irqreturn_t rzt2h_adc_isr(int irq, void *private)
static const struct iio_chan_spec rzt2h_adc_chan_template = {
.indexed = 1,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
- BIT(IIO_CHAN_INFO_SCALE),
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ .info_mask_separate_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),
.type = IIO_VOLTAGE,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 12,
+ .storagebits = 16,
+ .endianness = IIO_CPU,
+ },
};
static int rzt2h_adc_parse_properties(struct rzt2h_adc *adc)
{
struct iio_chan_spec *chan_array;
- unsigned int i;
int ret;
ret = devm_iio_adc_device_alloc_chaninfo_se(adc->dev,
@@ -203,19 +606,64 @@ static int rzt2h_adc_parse_properties(struct rzt2h_adc *adc)
adc->num_channels = ret;
adc->channels = chan_array;
- for (i = 0; i < adc->num_channels; i++)
- if (chan_array[i].channel + 1 > adc->max_channels)
- adc->max_channels = chan_array[i].channel + 1;
+ for (unsigned int i = 0; i < adc->num_channels; i++) {
+ adc->sst[chan_array[i].channel] = RZT2H_ADC_SST_DEFAULT;
+
+ chan_array[i].scan_index = i;
+ }
return 0;
}
+static void rzt2h_adc_free_dma_buf(void *p)
+{
+ struct rzt2h_adc *adc = p;
+
+ dma_free_noncoherent(adc->dev, RZT2H_ADC_DMA_BUFFER_SIZE,
+ adc->dma.buf, adc->dma.addr, DMA_FROM_DEVICE);
+}
+
+static int rzt2h_adc_setup_dma(struct iio_dev *indio_dev)
+{
+ struct rzt2h_adc *adc = iio_priv(indio_dev);
+ struct device *dev = adc->dev;
+ int ret;
+
+ adc->dma.chan = devm_dma_request_chan(dev, "rx");
+ if (IS_ERR(adc->dma.chan)) {
+ ret = PTR_ERR(adc->dma.chan);
+ if (ret != -ENODEV)
+ return dev_err_probe(dev, ret, "DMA channel request failed\n");
+
+ adc->dma.chan = NULL;
+ return 0;
+ }
+
+ adc->dma.buf = dma_alloc_noncoherent(dev, RZT2H_ADC_DMA_BUFFER_SIZE,
+ &adc->dma.addr, DMA_FROM_DEVICE,
+ GFP_KERNEL);
+ if (!adc->dma.buf)
+ return -ENOMEM;
+
+ dma_sync_single_for_device(dev, adc->dma.addr, RZT2H_ADC_DMA_BUFFER_SIZE,
+ DMA_FROM_DEVICE);
+
+ ret = devm_add_action_or_reset(dev, rzt2h_adc_free_dma_buf, adc);
+ if (ret)
+ return ret;
+
+ return devm_iio_kfifo_buffer_setup_ext(dev, indio_dev,
+ &rzt2h_adc_buffer_setup_ops, NULL);
+}
+
static int rzt2h_adc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct iio_dev *indio_dev;
struct rzt2h_adc *adc;
- int ret, irq;
+ struct resource *res;
+ struct clk *adclk;
+ int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*adc));
if (!indio_dev)
@@ -224,6 +672,7 @@ static int rzt2h_adc_probe(struct platform_device *pdev)
adc = iio_priv(indio_dev);
adc->dev = dev;
init_completion(&adc->completion);
+ init_waitqueue_head(&adc->dma.wq);
ret = devm_mutex_init(dev, &adc->lock);
if (ret)
@@ -235,21 +684,35 @@ static int rzt2h_adc_probe(struct platform_device *pdev)
if (ret)
return ret;
- adc->base = devm_platform_ioremap_resource(pdev, 0);
+ adc->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(adc->base))
return PTR_ERR(adc->base);
+ adc->phys_base = res->start;
+
+ adclk = devm_clk_get(dev, "adclk");
+ if (IS_ERR(adclk))
+ return dev_err_probe(dev, PTR_ERR(adclk), "failed to get adclk\n");
+
+ adc->adclk_rate = clk_get_rate(adclk);
+ if (!adc->adclk_rate)
+ return dev_err_probe(dev, -EINVAL, "invalid adclk rate\n");
+
+ adc->samp_freq_avail[0] = rzt2h_adc_sst_to_freq(adc, RZT2H_ADC_SST_MAX);
+ adc->samp_freq_avail[1] = 1;
+ adc->samp_freq_avail[2] = rzt2h_adc_sst_to_freq(adc, RZT2H_ADC_SST_MIN);
+
pm_runtime_set_autosuspend_delay(dev, 300);
pm_runtime_use_autosuspend(dev);
ret = devm_pm_runtime_enable(dev);
if (ret)
return ret;
- irq = platform_get_irq_byname(pdev, "adi");
- if (irq < 0)
- return irq;
+ adc->irq = platform_get_irq_byname(pdev, "adi");
+ if (adc->irq < 0)
+ return adc->irq;
- ret = devm_request_irq(dev, irq, rzt2h_adc_isr, 0, dev_name(dev), adc);
+ ret = devm_request_irq(dev, adc->irq, rzt2h_adc_isr, 0, dev_name(dev), adc);
if (ret)
return ret;
@@ -259,6 +722,10 @@ static int rzt2h_adc_probe(struct platform_device *pdev)
indio_dev->channels = adc->channels;
indio_dev->num_channels = adc->num_channels;
+ ret = rzt2h_adc_setup_dma(indio_dev);
+ if (ret)
+ return ret;
+
return devm_iio_device_register(dev, indio_dev);
}
diff --git a/drivers/iio/adc/sophgo-cv1800b-adc.c b/drivers/iio/adc/sophgo-cv1800b-adc.c
index bdc3e1326a9a..c6eed09acfcd 100644
--- a/drivers/iio/adc/sophgo-cv1800b-adc.c
+++ b/drivers/iio/adc/sophgo-cv1800b-adc.c
@@ -182,6 +182,8 @@ static int cv1800b_adc_probe(struct platform_device *pdev)
return PTR_ERR(saradc->regs);
saradc->irq = platform_get_irq_optional(pdev, 0);
+ if (saradc->irq < 0 && saradc->irq != -ENXIO)
+ return saradc->irq;
if (saradc->irq > 0) {
init_completion(&saradc->completion);
ret = devm_request_irq(dev, saradc->irq,
diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c
index 5c6c06b269be..3cde89c06ca3 100644
--- a/drivers/iio/adc/stm32-adc.c
+++ b/drivers/iio/adc/stm32-adc.c
@@ -2456,6 +2456,7 @@ static int stm32_adc_dma_request(struct device *dev, struct iio_dev *indio_dev)
{
struct stm32_adc *adc = iio_priv(indio_dev);
struct dma_slave_config config = { };
+ struct device *dma_dev;
int ret;
adc->dma_chan = dma_request_chan(dev, "rx");
@@ -2470,7 +2471,8 @@ static int stm32_adc_dma_request(struct device *dev, struct iio_dev *indio_dev)
return 0;
}
- adc->rx_buf = dma_alloc_coherent(adc->dma_chan->device->dev,
+ dma_dev = dmaengine_get_dma_device(adc->dma_chan);
+ adc->rx_buf = dma_alloc_coherent(dma_dev,
STM32_DMA_BUFFER_SIZE,
&adc->rx_dma_buf, GFP_KERNEL);
if (!adc->rx_buf) {
@@ -2490,7 +2492,7 @@ static int stm32_adc_dma_request(struct device *dev, struct iio_dev *indio_dev)
return 0;
err_free:
- dma_free_coherent(adc->dma_chan->device->dev, STM32_DMA_BUFFER_SIZE,
+ dma_free_coherent(dma_dev, STM32_DMA_BUFFER_SIZE,
adc->rx_buf, adc->rx_dma_buf);
err_release:
dma_release_channel(adc->dma_chan);
@@ -2617,7 +2619,7 @@ static int stm32_adc_probe(struct platform_device *pdev)
err_dma_disable:
if (adc->dma_chan) {
- dma_free_coherent(adc->dma_chan->device->dev,
+ dma_free_coherent(dmaengine_get_dma_device(adc->dma_chan),
STM32_DMA_BUFFER_SIZE,
adc->rx_buf, adc->rx_dma_buf);
dma_release_channel(adc->dma_chan);
@@ -2640,7 +2642,7 @@ static void stm32_adc_remove(struct platform_device *pdev)
pm_runtime_put_noidle(&pdev->dev);
iio_triggered_buffer_cleanup(indio_dev);
if (adc->dma_chan) {
- dma_free_coherent(adc->dma_chan->device->dev,
+ dma_free_coherent(dmaengine_get_dma_device(adc->dma_chan),
STM32_DMA_BUFFER_SIZE,
adc->rx_buf, adc->rx_dma_buf);
dma_release_channel(adc->dma_chan);
@@ -2725,7 +2727,7 @@ static const struct stm32_adc_cfg stm32h7_adc_cfg = {
.set_ovs = stm32h7_adc_set_ovs,
};
-static const unsigned int stm32_adc_min_ts_mp1[] = { 100, 100, 100, 4300, 9800 };
+static const unsigned int stm32_adc_min_ts_mp1[] = { 100, 0, 0, 4300, 9800 };
static_assert(ARRAY_SIZE(stm32_adc_min_ts_mp1) == STM32_ADC_INT_CH_NB);
static const struct stm32_adc_cfg stm32mp1_adc_cfg = {
@@ -2747,7 +2749,7 @@ static const struct stm32_adc_cfg stm32mp1_adc_cfg = {
.set_ovs = stm32h7_adc_set_ovs,
};
-static const unsigned int stm32_adc_min_ts_mp13[] = { 100, 0, 0, 4300, 9800 };
+static const unsigned int stm32_adc_min_ts_mp13[] = { 1000, 1000, 1000, 4300, 9800 };
static_assert(ARRAY_SIZE(stm32_adc_min_ts_mp13) == STM32_ADC_INT_CH_NB);
static const struct stm32_adc_cfg stm32mp13_adc_cfg = {
diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c
index 00f05e167afc..674767da3ac3 100644
--- a/drivers/iio/adc/stm32-dfsdm-adc.c
+++ b/drivers/iio/adc/stm32-dfsdm-adc.c
@@ -1484,7 +1484,7 @@ static void stm32_dfsdm_dma_release(struct iio_dev *indio_dev)
struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
if (adc->dma_chan) {
- dma_free_coherent(adc->dma_chan->device->dev,
+ dma_free_coherent(dmaengine_get_dma_device(adc->dma_chan),
DFSDM_DMA_BUFFER_SIZE,
adc->rx_buf, adc->dma_buf);
dma_release_channel(adc->dma_chan);
@@ -1504,7 +1504,7 @@ static int stm32_dfsdm_dma_request(struct device *dev,
return ret;
}
- adc->rx_buf = dma_alloc_coherent(adc->dma_chan->device->dev,
+ adc->rx_buf = dma_alloc_coherent(dmaengine_get_dma_device(adc->dma_chan),
DFSDM_DMA_BUFFER_SIZE,
&adc->dma_buf, GFP_KERNEL);
if (!adc->rx_buf) {
diff --git a/drivers/iio/adc/ti-adc128s052.c b/drivers/iio/adc/ti-adc128s052.c
index 1899813c1aee..f9a995ff403e 100644
--- a/drivers/iio/adc/ti-adc128s052.c
+++ b/drivers/iio/adc/ti-adc128s052.c
@@ -195,12 +195,14 @@ static int adc128_probe(struct spi_device *spi)
adc = iio_priv(indio_dev);
adc->spi = spi;
- indio_dev->name = spi_get_device_id(spi)->name;
+ config = spi_get_device_match_data(spi);
+ if (!config)
+ return -ENODATA;
+
+ indio_dev->name = spi->modalias;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &adc128_info;
- config = spi_get_device_match_data(spi);
-
indio_dev->channels = config->channels;
indio_dev->num_channels = config->num_channels;
diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c
index 0fbfa4e499aa..0f9244107c6d 100644
--- a/drivers/iio/adc/ti-ads1015.c
+++ b/drivers/iio/adc/ti-ads1015.c
@@ -233,6 +233,7 @@ static const struct iio_event_spec ads1015_events[] = {
struct ads1015_channel_data {
unsigned int pga;
unsigned int data_rate;
+ const char *label;
};
struct ads1015_thresh_data {
@@ -586,6 +587,15 @@ static int ads1015_read_raw(struct iio_dev *indio_dev,
}
}
+static int ads1015_read_label(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, char *label)
+{
+ struct ads1015_data *data = iio_priv(indio_dev);
+
+ return sysfs_emit(label, "%s\n",
+ data->channel_data[chan->address].label);
+}
+
static int ads1015_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val,
int val2, long mask)
@@ -843,6 +853,7 @@ static const struct iio_buffer_setup_ops ads1015_buffer_setup_ops = {
static const struct iio_info ads1015_info = {
.read_avail = ads1015_read_avail,
.read_raw = ads1015_read_raw,
+ .read_label = ads1015_read_label,
.write_raw = ads1015_write_raw,
.read_event_value = ads1015_read_event,
.write_event_value = ads1015_write_event,
@@ -853,6 +864,7 @@ static const struct iio_info ads1015_info = {
static const struct iio_info tla2024_info = {
.read_avail = ads1015_read_avail,
.read_raw = ads1015_read_raw,
+ .read_label = ads1015_read_label,
.write_raw = ads1015_write_raw,
};
@@ -861,7 +873,9 @@ static int ads1015_client_get_channels_config(struct i2c_client *client)
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct ads1015_data *data = iio_priv(indio_dev);
struct device *dev = &client->dev;
+ const char *label;
int i = -1;
+ int ret;
device_for_each_child_node_scoped(dev, node) {
u32 pval;
@@ -897,6 +911,15 @@ static int ads1015_client_get_channels_config(struct i2c_client *client)
}
}
+ if (fwnode_property_present(node, "label")) {
+ ret = fwnode_property_read_string(node, "label", &label);
+ if (ret) {
+ dev_err(dev, "invalid label on %pfw\n", node);
+ return ret;
+ }
+ data->channel_data[channel].label = label;
+ }
+
data->channel_data[channel].pga = pga;
data->channel_data[channel].data_rate = data_rate;
@@ -985,6 +1008,13 @@ static int ads1015_probe(struct i2c_client *client)
/* we need to keep this ABI the same as used by hwmon ADS1015 driver */
ads1015_get_channels_config(client);
+ /* Channels without a label property fall back to the datasheet name */
+ for (i = 0; i < ADS1015_CHANNELS; i++) {
+ if (!data->channel_data[i].label)
+ data->channel_data[i].label =
+ indio_dev->channels[i].datasheet_name;
+ }
+
data->regmap = devm_regmap_init_i2c(client, chip->has_comparator ?
&ads1015_regmap_config :
&tla2024_regmap_config);
diff --git a/drivers/iio/adc/ti-ads1018.c b/drivers/iio/adc/ti-ads1018.c
index d9ec4a8d7ce5..8f2d03eee77b 100644
--- a/drivers/iio/adc/ti-ads1018.c
+++ b/drivers/iio/adc/ti-ads1018.c
@@ -624,12 +624,16 @@ static int ads1018_trigger_setup(struct iio_dev *indio_dev)
static int ads1018_spi_probe(struct spi_device *spi)
{
- const struct ads1018_chip_info *info = spi_get_device_match_data(spi);
+ const struct ads1018_chip_info *info;
struct device *dev = &spi->dev;
struct iio_dev *indio_dev;
struct ads1018 *ads1018;
int ret;
+ info = spi_get_device_match_data(spi);
+ if (!info)
+ return -ENODATA;
+
indio_dev = devm_iio_device_alloc(dev, sizeof(*ads1018));
if (!indio_dev)
return -ENOMEM;
diff --git a/drivers/iio/adc/ti-ads1100.c b/drivers/iio/adc/ti-ads1100.c
index 9fe8d54cce83..9957c4d813fb 100644
--- a/drivers/iio/adc/ti-ads1100.c
+++ b/drivers/iio/adc/ti-ads1100.c
@@ -5,7 +5,7 @@
* Copyright (c) 2023, Topic Embedded Products
*
* Datasheet: https://www.ti.com/lit/gpn/ads1100
- * IIO driver for ADS1100 and ADS1000 ADC 16-bit I2C
+ * IIO driver for ADS1100 and similar single channel ADC 16-bit I2C
*/
#include
@@ -15,10 +15,12 @@
#include
#include
#include
+#include
#include
#include
#include
#include
+#include
#include
#include
@@ -39,17 +41,44 @@
#define ADS1100_SINGLESHOT ADS1100_CFG_SC
#define ADS1100_SLEEP_DELAY_MS 2000
+#define ADS1110_INTERNAL_REF_mV 2048
static const int ads1100_data_rate[] = { 128, 32, 16, 8 };
+static const int ads1110_data_rate[] = { 240, 60, 30, 15 };
static const int ads1100_data_rate_bits[] = { 12, 14, 15, 16 };
+/* Timeout based on the minimum sample rate of 8 SPS (7500ms) */
+#define ADS1100_MAX_DRDY_TIMEOUT_US (7500 * USEC_PER_MSEC)
+
+struct ads1100_config {
+ const char *name;
+ const int *available_data_rate_Hz;
+ const int data_rate_count;
+ bool has_internal_vref_only;
+};
+
+static const struct ads1100_config ads1100_config = {
+ .name = "ads1100",
+ .available_data_rate_Hz = ads1100_data_rate,
+ .data_rate_count = ARRAY_SIZE(ads1100_data_rate),
+ .has_internal_vref_only = false,
+};
+
+static const struct ads1100_config ads1110_config = {
+ .name = "ads1110",
+ .available_data_rate_Hz = ads1110_data_rate,
+ .data_rate_count = ARRAY_SIZE(ads1110_data_rate),
+ .has_internal_vref_only = true,
+};
+
struct ads1100_data {
struct i2c_client *client;
struct regulator *reg_vdd;
struct mutex lock;
int scale_avail[2 * 4]; /* 4 gain settings */
+ const struct ads1100_config *chip_info;
u8 config;
- bool supports_data_rate; /* Only the ADS1100 can select the rate */
+ bool supports_data_rate;
};
static const struct iio_chan_spec ads1100_channel = {
@@ -85,6 +114,20 @@ static int ads1100_set_config_bits(struct ads1100_data *data, u8 mask, u8 value)
return 0;
};
+static int ads1100_get_vref_millivolts(struct ads1100_data *data)
+{
+ int voltage_uV;
+
+ if (data->chip_info->has_internal_vref_only)
+ return ADS1110_INTERNAL_REF_mV;
+
+ voltage_uV = regulator_get_voltage(data->reg_vdd);
+ if (voltage_uV < 0)
+ return voltage_uV;
+
+ return voltage_uV / (MICRO / MILLI);
+}
+
static int ads1100_data_bits(struct ads1100_data *data)
{
return ads1100_data_rate_bits[FIELD_GET(ADS1100_DR_MASK, data->config)];
@@ -123,10 +166,86 @@ static int ads1100_get_adc_result(struct ads1100_data *data, int chan, int *val)
return 0;
}
+static int ads1100_conversion_busy(struct ads1100_data *data)
+{
+ u8 buffer[3];
+ int ret;
+
+ ret = i2c_master_recv(data->client, (char *)&buffer, sizeof(buffer));
+ if (ret < 0) {
+ dev_err(&data->client->dev, "I2C read fail: %d\n", ret);
+ return ret;
+ }
+
+ return FIELD_GET(ADS1100_CFG_ST_BSY, buffer[2]);
+}
+
+static int ads1100_wait_single_conversion(struct ads1100_data *data)
+{
+ int data_rate_index = FIELD_GET(ADS1100_DR_MASK, data->config);
+ int data_rate_Hz = data->chip_info->available_data_rate_Hz[data_rate_index];
+ unsigned long poll_us = DIV_ROUND_CLOSEST(USEC_PER_SEC, data_rate_Hz) / 4;
+ int busy;
+ int ret;
+
+ ret = readx_poll_timeout(ads1100_conversion_busy, data,
+ busy, busy <= 0,
+ poll_us, ADS1100_MAX_DRDY_TIMEOUT_US);
+ if (busy < 0)
+ return busy;
+
+ return ret;
+}
+
+static int ads1100_start_single_conversion(struct ads1100_data *data)
+{
+ u8 config = data->config | ADS1100_CFG_SC;
+ int ret;
+
+ ret = i2c_master_send(data->client, &config, sizeof(config));
+ if (ret < 0) {
+ dev_err(&data->client->dev, "I2C write fail: %d\n", ret);
+ return ret;
+ }
+ /* Need to wait because of change from continuous to single mode */
+ ret = ads1100_wait_single_conversion(data);
+ if (ret)
+ return ret;
+
+ config |= ADS1100_CFG_ST_BSY;
+
+ ret = i2c_master_send(data->client, &config, sizeof(config));
+ if (ret < 0) {
+ dev_err(&data->client->dev, "I2C write fail: %d\n", ret);
+ return ret;
+ }
+
+ /* No need to cache it, it's status bit */
+ data->config = config & ~ADS1100_CFG_ST_BSY;
+
+ return 0;
+}
+
+static int ads1100_poll_data_ready(struct ads1100_data *data)
+{
+ int ret;
+
+ ret = ads1100_start_single_conversion(data);
+ if (ret)
+ return ret;
+
+ ret = ads1100_wait_single_conversion(data);
+ if (ret)
+ return ret;
+
+ return ads1100_set_config_bits(data, ADS1100_CFG_SC, ADS1100_CONTINUOUS);
+}
+
static int ads1100_set_scale(struct ads1100_data *data, int val, int val2)
{
int microvolts;
int gain;
+ int ret;
/* With Vdd between 2.7 and 5V, the scale is always below 1 */
if (val)
@@ -135,7 +254,12 @@ static int ads1100_set_scale(struct ads1100_data *data, int val, int val2)
if (!val2)
return -EINVAL;
- microvolts = regulator_get_voltage(data->reg_vdd);
+ PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(&data->client->dev, pm);
+ ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+ if (ret)
+ return ret;
+
+ microvolts = ads1100_get_vref_millivolts(data) * (MICRO / MILLI);
/*
* val2 is in 'micro' units, n = val2 / 1000000
* result must be millivolts, d = microvolts / 1000
@@ -149,32 +273,40 @@ static int ads1100_set_scale(struct ads1100_data *data, int val, int val2)
ads1100_set_config_bits(data, ADS1100_PGA_MASK, ffs(gain) - 1);
- return 0;
+ return ads1100_poll_data_ready(data);
}
static int ads1100_set_data_rate(struct ads1100_data *data, int chan, int rate)
{
unsigned int i;
unsigned int size;
+ int ret;
- size = data->supports_data_rate ? ARRAY_SIZE(ads1100_data_rate) : 1;
+ size = data->supports_data_rate ? data->chip_info->data_rate_count : 1;
for (i = 0; i < size; i++) {
- if (ads1100_data_rate[i] == rate)
- return ads1100_set_config_bits(data, ADS1100_DR_MASK,
- FIELD_PREP(ADS1100_DR_MASK, i));
+ if (data->chip_info->available_data_rate_Hz[i] == rate)
+ break;
}
- return -EINVAL;
-}
+ if (i == size)
+ return -EINVAL;
-static int ads1100_get_vdd_millivolts(struct ads1100_data *data)
-{
- return regulator_get_voltage(data->reg_vdd) / (MICRO / MILLI);
+ PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(&data->client->dev, pm);
+ ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+ if (ret)
+ return ret;
+
+ ret = ads1100_set_config_bits(data, ADS1100_DR_MASK,
+ FIELD_PREP(ADS1100_DR_MASK, i));
+ if (ret)
+ return ret;
+
+ return ads1100_poll_data_ready(data);
}
static void ads1100_calc_scale_avail(struct ads1100_data *data)
{
- int millivolts = ads1100_get_vdd_millivolts(data);
+ int millivolts = ads1100_get_vref_millivolts(data);
unsigned int i;
for (i = 0; i < ARRAY_SIZE(data->scale_avail) / 2; i++) {
@@ -196,9 +328,9 @@ static int ads1100_read_avail(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
*type = IIO_VAL_INT;
- *vals = ads1100_data_rate;
+ *vals = data->chip_info->available_data_rate_Hz;
if (data->supports_data_rate)
- *length = ARRAY_SIZE(ads1100_data_rate);
+ *length = data->chip_info->data_rate_count;
else
*length = 1;
return IIO_AVAIL_LIST;
@@ -218,6 +350,7 @@ static int ads1100_read_raw(struct iio_dev *indio_dev,
{
int ret;
struct ads1100_data *data = iio_priv(indio_dev);
+ int data_rate_index;
guard(mutex)(&data->lock);
switch (mask) {
@@ -233,12 +366,12 @@ static int ads1100_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
/* full-scale is the supply voltage in millivolts */
- *val = ads1100_get_vdd_millivolts(data);
+ *val = ads1100_get_vref_millivolts(data);
*val2 = 15 + FIELD_GET(ADS1100_PGA_MASK, data->config);
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_CHAN_INFO_SAMP_FREQ:
- *val = ads1100_data_rate[FIELD_GET(ADS1100_DR_MASK,
- data->config)];
+ data_rate_index = FIELD_GET(ADS1100_DR_MASK, data->config);
+ *val = data->chip_info->available_data_rate_Hz[data_rate_index];
return IIO_VAL_INT;
default:
return -EINVAL;
@@ -318,7 +451,12 @@ static int ads1100_probe(struct i2c_client *client)
data->client = client;
mutex_init(&data->lock);
- indio_dev->name = "ads1100";
+ data->chip_info = i2c_get_match_data(client);
+ if (!data->chip_info)
+ return dev_err_probe(dev, -ENODATA,
+ "Can't get device data from firmware\n");
+
+ indio_dev->name = data->chip_info->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = &ads1100_channel;
indio_dev->num_channels = 1;
@@ -400,16 +538,18 @@ static DEFINE_RUNTIME_DEV_PM_OPS(ads1100_pm_ops,
NULL);
static const struct i2c_device_id ads1100_id[] = {
- { .name = "ads1100" },
- { .name = "ads1000" },
+ { .name = "ads1000", .driver_data = (kernel_ulong_t)&ads1100_config },
+ { .name = "ads1100", .driver_data = (kernel_ulong_t)&ads1100_config },
+ { .name = "ads1110", .driver_data = (kernel_ulong_t)&ads1110_config },
{ }
};
MODULE_DEVICE_TABLE(i2c, ads1100_id);
static const struct of_device_id ads1100_of_match[] = {
- {.compatible = "ti,ads1100" },
- {.compatible = "ti,ads1000" },
+ { .compatible = "ti,ads1000", .data = &ads1100_config },
+ { .compatible = "ti,ads1100", .data = &ads1100_config },
+ { .compatible = "ti,ads1110", .data = &ads1110_config },
{ }
};
diff --git a/drivers/iio/adc/ti-ads112c04.c b/drivers/iio/adc/ti-ads112c04.c
new file mode 100644
index 000000000000..acf7209db761
--- /dev/null
+++ b/drivers/iio/adc/ti-ads112c04.c
@@ -0,0 +1,524 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Texas Instruments ADS112C04 16-bit I2C ADC driver
+ *
+ * Copyright (c) 2026 Kyle Hsieh
+ *
+ * Datasheet: https://www.ti.com/lit/ds/symlink/ads112c04.pdf
+ * Based on TI Reference Code and standard Linux IIO framework.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include