iio: adc: Add support for LTC2378 and similar ADCs
Marcelo Schmitt
maintainerv4 cover iio: adc: Add support for LTC2378 and similar ADCs
This patch series adds support for LTC2378 and similar low noise, low power, high speed, successive approximation register (SAR) ADCs. These ADCs are similar among each other, varying mainly on the amount of precision bits, maximum sample rate, and input configuration (either fully differential or pseudo-differential).
Patch 1 adds device tree documentation for LTC2378.
Patch 2 enables single-shot sample read with a GPIO connected to the LTC2378 CNV pin.
Patch 3 enables high-speed data captures with SPI offloading.
The setup is similar to AD4030, with a specialized PWM generator being used both for SPI offload triggering and conversion start signaling.
Patch 4 enables running buffered data captures without SPI offloading.
Even though these parts are somewhat similar to AD4000, the wiring configuration for LTC parts is different as well as the available HDL for high speed sample rate mode. Because of that, I propose creating a new device driver for supporting LTC2378-like devices.
Specifications can be found at:
https://www.analog.com/media/en/technical-documentation/data-sheets/233818fa.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/236416fa.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/236418f.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/236716fa.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/236718f.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/236816f.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/236818f.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/236918fa.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/237016fa.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/237616fa.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/237618fa.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/237620fb.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/237716fa.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/237718fa.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/237720fb.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/237816fa.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/237818fa.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/237820fb.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/237918fb.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/238016fb.pdf
Despite the initial version of the LTC2378 driver had been developed by Ioan-Daniel. The current version has been greatly rewritten such that very little remained from that initial version. Due to that, having Ioan-Daniel in the author list now seems inaccurate.
Previous submissions:
v3: https://lore.kernel.org/linux-iio/[email protected]/
v2: https://lore.kernel.org/linux-iio/[email protected]/
v1: https://lore.kernel.org/linux-iio/[email protected]/
Change log v3 -> v4:
[DT]
- Added PWM property.
- Documented LTC2338-18 specific refin-supply.
- Picked up Conor's review tag.
[IIO]
- Dropped DMAengine buffer changes.
- Reworked the driver to make IIO channels static according to v3 feedback.
- Updated to use default 8 bits_per_word for non-offloaded transfers.
- Handled refin voltage reference supply for LTC2338.
- Used spi_bpw_to_bytes() where applicable.
With best regards,
Marcelo
Marcelo Schmitt (4):
dt-bindings: iio: adc: Add ltc2378
iio: adc: ltc2378: Add support for LTC2378-20 and similar ADCs
iio: adc: ltc2378: Enable high-speed data capture
iio: adc: ltc2378: Enable triggered buffer data capture
.../bindings/iio/adc/adi,ltc2378.yaml | 185 +++++ MAINTAINERS | 8 + drivers/iio/adc/Kconfig | 19 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ltc2378.c | 778 ++++++++++++++++++ 5 files changed, 991 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/adi,ltc2378.yaml create mode 100644 drivers/iio/adc/ltc2378.c
base-commit: cc746297b23e89bd5df9f91f3a0ca209e8991763
Signature · 1 line
2.53.0
Marcelo Schmitt
maintainerPATCH v4 1/4 dt-bindings: iio: adc: Add ltc2378
Document how to describe LTC2378-20 and similar ADCs in device tree.
---
Change log v3 -> v4:
- Added PWM property.
- Documented LTC2338-18 specific refin-supply.
- Picked up Conor's review tag.
.../bindings/iio/adc/adi,ltc2378.yaml | 185 ++++++++++++++++++ MAINTAINERS | 7 + 2 files changed, 192 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/adi,ltc2378.yaml
Documentation/devicetree/bindings/iio/adc/adi,ltc2378.yaml new file +185 -0
@@ -0,0 +1,185 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/adi,ltc2378.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices LTC2378 and similar Analog to Digital Converters + +maintainers: + - Marcelo Schmitt <[email protected]> + +description: | + Analog Devices LTC2378 series of ADCs. + Specifications can be found at: + https://www.analog.com/media/en/technical-documentation/data-sheets/233818fa.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/236416fa.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/236418f.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/236716fa.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/236718f.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/236816f.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/236818f.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/236918fa.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/237016fa.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/237616fa.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/237618fa.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/237620fb.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/237716fa.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/237718fa.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/237720fb.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/237816fa.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/237818fa.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/237820fb.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/237918fb.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/238016fb.pdf + +$ref: /schemas/spi/spi-peripheral-props.yaml# + +properties: + compatible: + oneOf: + # Single compatible string match. + - enum: + - adi,ltc2338-18 + - adi,ltc2364-16 + - adi,ltc2364-18 + - adi,ltc2367-16 + - adi,ltc2367-18 + - adi,ltc2368-16 + - adi,ltc2368-18 + - adi,ltc2369-18 + - adi,ltc2370-16 + - adi,ltc2376-16 + - adi,ltc2376-18 + - adi,ltc2376-20 + - adi,ltc2377-16 + - adi,ltc2377-18 + - adi,ltc2377-20 + - adi,ltc2378-16 + - adi,ltc2378-18 + - adi,ltc2378-20 + - adi,ltc2379-18 + - adi,ltc2380-16 + + # Low sample rate fallback for 16-bit unipolar sensors. + - items: + - enum: + - adi,ltc2370-16 # 2 MSPS + - adi,ltc2368-16 # 1 MSPS + - adi,ltc2367-16 # 500 kSPS + - const: adi,ltc2364-16 # fallback (250 kSPS) + + # Low sample rate fallback for 18-bit unipolar sensors. + - items: + - enum: + - adi,ltc2369-18 # 1.6 MSPS + - adi,ltc2368-18 # 1 MSPS + - adi,ltc2367-18 # 500 kSPS + - const: adi,ltc2364-18 # fallback (250 kSPS) + + # Low sample rate fallback for 16-bit bipolar sensors. + - items: + - enum: + - adi,ltc2380-16 # 2 MSPS + - adi,ltc2378-16 # 1 MSPS + - adi,ltc2377-16 # 500 kSPS + - const: adi,ltc2376-16 # fallback (250 kSPS) + + # Low sample rate fallback for 18-bit bipolar sensors. + - items: + - enum: + - adi,ltc2379-18 # 1.6 MSPS + - adi,ltc2338-18 # 1 MSPS + - adi,ltc2378-18 # 1 MSPS + - adi,ltc2377-18 # 500 kSPS + - const: adi,ltc2376-18 # fallback (250 kSPS) + + # Low sample rate fallback for 20-bit bipolar sensors. + - items: + - enum: + - adi,ltc2378-20 # 1 MSPS + - adi,ltc2377-20 # 500 kSPS + - const: adi,ltc2376-20 # fallback (250 kSPS) + + reg: + maxItems: 1 + + spi-max-frequency: + maximum: 100000000 + + vdd-supply: + description: A 2.5V supply that powers the chip (VDD). + + ovdd-supply: + description: + A 1.71V to 5.25V supply that sets the logic level for digital interface. + + ref-supply: + description: + Voltage reference input that determines the scale of ADC conversions. + + refin-supply: + description: + Alternative voltage reference input. + + cnv-gpios: + description: + When provided, this property indicates the GPIO that is connected to the + CNV pin. + maxItems: 1 + + pwms: + description: PWM signal connected to the CNV pin. + maxItems: 1 + + interrupts: + description: + Interrupt for signaling the completion of conversion results. The active + low signal provided on the BUSY pin asserts when ADC conversions finish. + maxItems: 1 + +required: + - compatible + - reg + - vdd-supply + - ovdd-supply + +allOf: + # Except for LTC2338, all designs require a voltage reference input + - if: + properties: + compatible: + not: + contains: + enum: + - adi,ltc2338-18 + then: + required: + - ref-supply + properties: + refin-supply: false + else: + properties: + ref-supply: false + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + #include <dt-bindings/interrupt-controller/irq.h> + spi { + #address-cells = <1>; + #size-cells = <0>; + adc@0 { + compatible = "adi,ltc2378-20", "adi,ltc2376-20"; + reg = <0>; + spi-max-frequency = <71000000>; + vdd-supply = <&supply_2_5V>; + ovdd-supply = <&supply_3_3V>; + ref-supply = <&supply_5V>; + cnv-gpios = <&gpio0 88 GPIO_ACTIVE_HIGH>; + interrupts = <7 IRQ_TYPE_EDGE_FALLING>; + interrupt-parent = <&gpio>; + }; + };
MAINTAINERS +7 -0
@@ -15220,6 +15220,13 @@ S: Maintained F: Documentation/devicetree/bindings/iio/dac/lltc,ltc1660.yaml F: drivers/iio/dac/ltc1660.c +LTC2378 IIO ADC DRIVER +M: Marcelo Schmitt <[email protected]> +L: [email protected] +S: Supported +W: https://ez.analog.com/linux-software-drivers +F: Documentation/devicetree/bindings/iio/adc/adi,ltc2378.yaml + LTC2664 IIO DAC DRIVER M: Michael Hennerich <[email protected]> M: Kim Seer Paller <[email protected]>
Signature · 1 line
2.53.0
[email protected]
AI reviewRe: [PATCH v4 1/4] dt-bindings: iio: adc: Add ltc2378
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Medium] The compatible string 'adi,ltc2338-18' incorrectly specifies 'adi,ltc2376-18' as a fallback…
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The compatible string 'adi,ltc2338-18' incorrectly specifies 'adi,ltc2376-18' as a fallback despite conflicting hardware constraints for 'ref-supply', breaking backward compatibility. --
commit aa175408226610e4bc2c27ed8ee768b0307ee6fa
Author: Marcelo Schmitt <[email protected]>
dt-bindings: iio: adc: Add ltc2378
This commit documents the device tree bindings for the Analog Devices LTC2378 and similar series of ADCs. It specifies the compatible strings, required properties, and voltage reference constraints.
Quoted 5 lines
Documentation/devicetree/bindings/iio/adc/adi,ltc2378.yaml new file +0
-0
[ ... ]
Quoted 8 lines
Documentation/devicetree/bindings/iio/adc/adi,ltc2378.yaml new file +8
-0+ # Low sample rate fallback for 18-bit bipolar sensors. + - items: + - enum: + - adi,ltc2379-18 # 1.6 MSPS + - adi,ltc2338-18 # 1 MSPS + - adi,ltc2378-18 # 1 MSPS + - adi,ltc2377-18 # 500 kSPS + - const: adi,ltc2376-18 # fallback (250 kSPS)
[ ... ]
Quoted 7 lines
Documentation/devicetree/bindings/iio/adc/adi,ltc2378.yaml new file +7
-0+allOf: + # Except for LTC2338, all designs require a voltage reference input + - if: + properties: + compatible: + not: + contains:
Documentation/devicetree/bindings/iio/adc/adi,ltc2378.yaml line 163
Quoted 10 lines
Documentation/devicetree/bindings/iio/adc/adi,ltc2378.yaml new file +10
-0+ enum: + - adi,ltc2338-18 + then: + required: + - ref-supply + properties: + refin-supply: false + else: + properties: + ref-supply: false
[Severity: Medium]
Will this cause probe failures on older kernels when using the fallback?
The compatible string adi,ltc2338-18 is configured to use adi,ltc2376-18 as a fallback. However, this conditional block strictly forbids the ref-supply property for adi,ltc2338-18.
Because adi,ltc2376-18 requires a ref-supply, a device tree correctly following this binding for adi,ltc2338-18 will lack that property.
When an older kernel attempts to bind using the adi,ltc2376-18 fallback string, will it fail to find the expected ref-supply regulator and abort probing?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
Marcelo Schmitt
maintainerPATCH v4 2/4 iio: adc: ltc2378: Add support for LTC2378-20 and similar ADCs
In reply to Marcelo SchmittSupport for LTC2378-20 and similar analog-to-digital converters.
---
Change log v3 -> v4:
- Reworked the driver to make IIO channels static according to v3 feedback.
- Updated to use default 8 bits_per_word for non-offloaded transfers.
- Handled refin voltage reference supply for LTC2338.
- Used spi_bpw_to_bytes() where applicable.
MAINTAINERS | 1 + drivers/iio/adc/Kconfig | 12 ++ drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ltc2378.c | 395 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 409 insertions(+) create mode 100644 drivers/iio/adc/ltc2378.c
MAINTAINERS +1 -0
@@ -15226,6 +15226,7 @@ L: [email protected] S: Supported W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/adc/adi,ltc2378.yaml +F: drivers/iio/adc/ltc2378.c LTC2664 IIO DAC DRIVER M: Michael Hennerich <[email protected]>
drivers/iio/adc/Kconfig +12 -0
@@ -941,6 +941,18 @@ config LTC2309 This driver can also be built as a module. If so, the module will be called ltc2309. +config LTC2378 + tristate "Analog Devices LTC2378 ADC driver" + depends on SPI + depends on REGULATOR || COMPILE_TEST + depends on GPIOLIB + help + Say yes here to build support for Analog Devices LTC2378-20 and + similar analog to digital converters. + + This driver can also be built as a module. If so, the module will + be called ltc2378. + config LTC2471 tristate "Linear Technology LTC2471 and LTC2473 ADC driver" depends on I2C
drivers/iio/adc/Makefile +1 -0
@@ -81,6 +81,7 @@ obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o obj-$(CONFIG_LTC2309) += ltc2309.o +obj-$(CONFIG_LTC2378) += ltc2378.o obj-$(CONFIG_LTC2471) += ltc2471.o obj-$(CONFIG_LTC2485) += ltc2485.o obj-$(CONFIG_LTC2496) += ltc2496.o ltc2497-core.o
drivers/iio/adc/ltc2378.c new file +395 -0
395 lines not on this page · raw message
Signature · 1 line
2.53.0
[email protected]
AI reviewRe: [PATCH v4 2/4] iio: adc: ltc2378: Add support for LTC2378-20 and similar ADCs
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: - [High] The voltage from the 'refin' regulator is not multiplied by the internal buffer gain, resulting in…
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] The voltage from the 'refin' regulator is not multiplied by the internal buffer gain, resulting in incorrect ADC scale.
- [Medium] External 'ref' regulator is completely ignored for chips with an internal reference, breaking the ability to overdrive the internal reference. --
commit 06f09452b5298cd69acd94f1c33c2c91342a505d
Author: Marcelo Schmitt <[email protected]>
iio: adc: ltc2378: Add support for LTC2378-20 and similar ADCs
This commit adds a new driver for the Analog Devices LTC2378-20 and similar analog-to-digital converters.
Quoted 5 lines
drivers/iio/adc/ltc2378.c new file +0
-0
[ ... ]
drivers/iio/adc/ltc2378.c line 275
Quoted 9 lines
drivers/iio/adc/ltc2378.c new file +9
-0+static int ltc2378_regulator_setup (struct device *dev,struct ltc2378_state *st) +{ +int ret; + + ret =devm_regulator_get_enable_read_voltage (dev,"refin" ); +if (ret <0 && ret != -ENODEV ) { +return dev_err_probe (dev, ret,"failed to read refin regulator\n" ); + }else if (ret >0 ) { + st->ref_uV = ret;
[Severity: High]
Does this assignment account for the internal buffer's amplification gain?
For example, on chips like the LTC2338-18, the internal reference buffer amplifies the REFIN voltage by a factor of 2. If the 'refin' regulator provides 2.048V, the internal REF pin sees 4.096V. But this code appears to assign the direct REFIN voltage to st->ref_uV, which would result in an incorrect ADC scale calculation.
drivers/iio/adc/ltc2378.c line 281
Quoted 6 lines
drivers/iio/adc/ltc2378.c new file +6
-0+return 0 ; + } + +if (st->info->internal_ref_uv) { + st->ref_uV = st->info->internal_ref_uv; +return 0 ;
[Severity: Medium]
Does this early return prevent a board from overdriving the internal reference with an external 'ref' supply?
If the hardware supports overdriving the internal reference and a 'ref-supply' is provided in the device tree, it looks like this code will silently ignore it and use the internal reference value instead.
Quoted 10 lines
drivers/iio/adc/ltc2378.c new file +10
-0+ } + + ret =devm_regulator_get_enable_read_voltage (dev,"ref" ); +if (ret <0 ) +return dev_err_probe (dev, ret,"failed to read ref regulator\n" ); + + st->ref_uV = ret; + +return 0 ; +}
[ ... ]
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
David Lechner
reviewerRe: [PATCH v4 2/4] iio: adc: ltc2378: Add support for LTC2378-20 and similar ADCs
In reply to Marcelo SchmittQuoted 1 line · Marcelo Schmitt
Support for LTC2378-20 and similar analog-to-digital converters.
This should mention that it contains some future prep for offloading. (Although would be a bit easier to review if we deferred adding the offload stuff).
Quoted 16 lines
Signed-off-by Marcelo Schmitt <[email protected]>---
Change log v3 -> v4:
- Reworked the driver to make IIO channels static according to v3 feedback.
- Updated to use default 8bits_per_wordfor non-offloaded transfers.
- Handled refin voltage reference supply for LTC2338.
- Usedspi_bpw_to_bytes()where applicable.MAINTAINERS | 1 + drivers/iio/adc/Kconfig | 12 ++ drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ltc2378.c | 395 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 409 insertions(+) create mode 100644 drivers/iio/adc/ltc2378.c
...
Quoted 21 lines
drivers/iio/adc/ltc2378.c new file +15
-0@@ -0,0 +1,395 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* +* Analog Devices LTC2378 ADC series driver +* +* Copyright (C) 2026 Analog Devices Inc. +* Author: Marcelo Schmitt <[email protected]> +*/ + +#include <linux/bitops.h> +#include <linux/bits.h> +#include <linux/cleanup.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/gpio/consumer.h> +#include <linux/mod_devicetable.h>
drivers/iio/adc/ltc2378.c line 25
Quoted 10 lines
drivers/iio/adc/ltc2378.c new file +10
-0+#include <linux/module.h> +#include <linux/regulator/consumer.h> +#include <linux/spi/spi.h> +#include <linux/types.h> +#include <linux/units.h> + +#include <linux/iio/iio.h> +#include <linux/iio/types.h> + +#define __LTC2378_DIFF_CHANNEL (_sign, _real_bits, _storage_bits, _offl)\
Why the leading underscores? I don't see a conflicting name.
Quoted 12 lines
drivers/iio/adc/ltc2378.c new file +12
-0+{ \ + .type = IIO_VOLTAGE, \ + .info_mask_separate =BIT (IIO_CHAN_INFO_RAW ) | \ +BIT (IIO_CHAN_INFO_SCALE ) | \ + (_offl ? BIT(IIO_CHAN_INFO_SAMP_FREQ) : 0), \ + .info_mask_separate_available = _offl ? BIT(IIO_CHAN_INFO_SAMP_FREQ) : 0,\ + .scan_index = 0, \ + .scan_type = { \ + .format = _sign ?IIO_SCAN_FORMAT_SIGNED_INT : \ + IIO_SCAN_FORMAT_UNSIGNED_INT, \ + .realbits = _real_bits, \ + .storagebits = _storage_bits, \
drivers/iio/adc/ltc2378.c line 47
Quoted 10 lines
drivers/iio/adc/ltc2378.c new file +10
-0+ .shift = (_offl ? 0 : _storage_bits - _real_bits), \ + .endianness = _offl ? IIO_CPU : IIO_BE \ + }, \ +} + +#define LTC2378_BIPOLAR_DIFF_CHANNEL (_real_bits) \ + __LTC2378_DIFF_CHANNEL(1, _real_bits, (((_real_bits) > 16) ? 32 : 16), 0) + +#define LTC2378_UNIPOLAR_DIFF_CHANNEL (_real_bits) \ + __LTC2378_DIFF_CHANNEL(0, _real_bits, (((_real_bits) > 16) ? 32 : 16), 0)
Why not move the (((_real_bits) > 16) ? 32 : 16) into the __LTC2378_DIFF_CHANNEL() macro to avoid repeating it?
drivers/iio/adc/ltc2378.c line 51
Quoted 4 lines
drivers/iio/adc/ltc2378.c new file +4
-0+ +struct ltc2378_chip_info { +const char *name; +unsigned int internal_ref_uv;
_uV (to be consistent)
Quoted 3 lines
drivers/iio/adc/ltc2378.c new file +3
-0+struct iio_chan_spec chan; +}; +
...
drivers/iio/adc/ltc2378.c line 274
Quoted 8 lines
drivers/iio/adc/ltc2378.c new file +8
-0+static int ltc2378_regulator_setup (struct device *dev,struct ltc2378_state *st) +{ +int ret; + + ret =devm_regulator_get_enable_read_voltage (dev,"refin" ); +if (ret <0 && ret != -ENODEV ) { +return dev_err_probe (dev, ret,"failed to read refin regulator\n" ); + }else if (ret >0 ) {
Else is not needed here.
drivers/iio/adc/ltc2378.c line 282
Quoted 8 lines
drivers/iio/adc/ltc2378.c new file +8
-0+ st->ref_uV = ret; +return 0 ; + } + +if (st->info->internal_ref_uv) { + st->ref_uV = st->info->internal_ref_uv; +return 0 ; + }
I would be tempted to have two separate functions here and only call one depending on the chip. Otherwise, it allows incorrect devicetree.
Quoted 10 lines
drivers/iio/adc/ltc2378.c new file +10
-0+ + ret =devm_regulator_get_enable_read_voltage (dev,"ref" ); +if (ret <0 ) +return dev_err_probe (dev, ret,"failed to read ref regulator\n" ); + + st->ref_uV = ret; + +return 0 ; +} +
Re: [PATCH v4 2/4] iio: adc: ltc2378: Add support for LTC2378-20 and similar ADCs
Quoted 17 lines
Quoted 17 lines
drivers/iio/adc/ltc2378.c new file +17
-0+{ \ + .type = IIO_VOLTAGE, \ + .info_mask_separate =BIT (IIO_CHAN_INFO_RAW ) | \ +BIT (IIO_CHAN_INFO_SCALE ) | \ + (_offl ? BIT(IIO_CHAN_INFO_SAMP_FREQ) : 0), \ + .info_mask_separate_available = _offl ? BIT(IIO_CHAN_INFO_SAMP_FREQ) : 0,\ + .scan_index = 0, \ + .scan_type = { \ + .format = _sign ?IIO_SCAN_FORMAT_SIGNED_INT : \ + IIO_SCAN_FORMAT_UNSIGNED_INT, \ + .realbits = _real_bits, \ + .storagebits = _storage_bits, \ + .shift = (_offl ? 0 : _storage_bits - _real_bits), \ + .endianness = _offl ?IIO_CPU :IIO_BE \ + }, \ +} +
Quoted 9 lines
drivers/iio/adc/ltc2378.c line 47
Quoted 5 lines
drivers/iio/adc/ltc2378.c new file +5
-0+#define LTC2378_BIPOLAR_DIFF_CHANNEL (_real_bits) \ + __LTC2378_DIFF_CHANNEL(1, _real_bits, (((_real_bits) > 16) ? 32 : 16), 0) + +#define LTC2378_UNIPOLAR_DIFF_CHANNEL (_real_bits) \ + __LTC2378_DIFF_CHANNEL(0, _real_bits, (((_real_bits) > 16) ? 32 : 16), 0)Why not move the (((
_real_bits) > 16) ? 32 : 16) into the__LTC2378_DIFF_CHANNEL()macro to avoid repeating it?
Because that would go wrong for LTC2378_OFFLOAD_BIPOLAR_DIFF_CHANNEL() in patch 3.
Quoted 4 lines
Quoted 4 lines
drivers/iio/adc/ltc2378.c new file +4
-0+ +struct ltc2378_chip_info { +const char *name; +unsigned int internal_ref_uv;
...
Quoted 11 lines
drivers/iio/adc/ltc2378.c line 274
Quoted 9 lines
drivers/iio/adc/ltc2378.c new file +8
-0+static int ltc2378_regulator_setup (struct device *dev,struct ltc2378_state *st) +{ +int ret; + + ret =devm_regulator_get_enable_read_voltage (dev,"refin" ); +if (ret <0 && ret != -ENODEV ) { +return dev_err_probe (dev, ret,"failed to read refin regulator\n" ); + }else if (ret >0 ) {Else is not needed here.
Why not? Intendend flow/logic is to get and use refin for devices that have it (currently only one chip has). Except for that chip that has 'refin', other chips have only 'ref' and no internal reference. Also, the chip that has 'refin' doesn't have 'ref' so it uses an internal reference when 'refin' is not found. Anyways, the driver can use 'refin' if there is one available, no?
P.S. Will separate regulator logic according to chip type.
Quoted 12 lines
drivers/iio/adc/ltc2378.c line 282
Quoted 9 lines
drivers/iio/adc/ltc2378.c new file +8
-0+ st->ref_uV = ret; +return 0 ; + } + +if (st->info->internal_ref_uv) { + st->ref_uV = st->info->internal_ref_uv; +return 0 ; + }I would be tempted to have two separate functions here and only call one depending on the chip. Otherwise, it allows incorrect devicetree.
Hmm, I see. Drat, I was hoping to avoid checking for specific chip parts to handle regulators. dtbs_check should error if a chip other than ltc2338 has 'refin'. Anyways, I see maintainers will probably prefer the chip specific init flow.
Quoted 11 lines
drivers/iio/adc/ltc2378.c line 292
Quoted 11 lines
drivers/iio/adc/ltc2378.c new file +10
-0+ + ret =devm_regulator_get_enable_read_voltage (dev,"ref" ); +if (ret <0 ) +return dev_err_probe (dev, ret,"failed to read ref regulator\n" ); + + st->ref_uV = ret; + +return 0 ; +} +
Will adjust according to other comments as well.
Thanks,
Marcelo
David Lechner
reviewerRe: [PATCH v4 2/4] iio: adc: ltc2378: Add support for LTC2378-20 and similar ADCs
It helps if you don't trim the "On ... wrote:" part of the reply so that we know who wrote what. :-)
Quoted 26 lines · Marcelo Schmitt
Quoted 17 lines
Quoted 17 lines
drivers/iio/adc/ltc2378.c new file +17
-0+{ \ + .type = IIO_VOLTAGE, \ + .info_mask_separate =BIT (IIO_CHAN_INFO_RAW ) | \ +BIT (IIO_CHAN_INFO_SCALE ) | \ + (_offl ? BIT(IIO_CHAN_INFO_SAMP_FREQ) : 0), \ + .info_mask_separate_available = _offl ? BIT(IIO_CHAN_INFO_SAMP_FREQ) : 0,\ + .scan_index = 0, \ + .scan_type = { \ + .format = _sign ?IIO_SCAN_FORMAT_SIGNED_INT : \ + IIO_SCAN_FORMAT_UNSIGNED_INT, \ + .realbits = _real_bits, \ + .storagebits = _storage_bits, \ + .shift = (_offl ? 0 : _storage_bits - _real_bits), \ + .endianness = _offl ?IIO_CPU :IIO_BE \ + }, \ +} +Quoted 9 lines
drivers/iio/adc/ltc2378.c line 47
Quoted 5 lines
drivers/iio/adc/ltc2378.c new file +5
-0+#define LTC2378_BIPOLAR_DIFF_CHANNEL (_real_bits) \ + __LTC2378_DIFF_CHANNEL(1, _real_bits, (((_real_bits) > 16) ? 32 : 16), 0) + +#define LTC2378_UNIPOLAR_DIFF_CHANNEL (_real_bits) \ + __LTC2378_DIFF_CHANNEL(0, _real_bits, (((_real_bits) > 16) ? 32 : 16), 0)Why not move the (((
_real_bits) > 16) ? 32 : 16) into the__LTC2378_DIFF_CHANNEL()macro to avoid repeating it?
Quoted 2 lines
Because that would go wrong for
LTC2378_OFFLOAD_BIPOLAR_DIFF_CHANNEL()in patch 3.
It could use _offl ? ... in the macro for that. Not a big deal to me though.
Quoted 16 lines
Quoted 4 lines
Quoted 4 lines
drivers/iio/adc/ltc2378.c new file +4
-0+ +struct ltc2378_chip_info { +const char *name; +unsigned int internal_ref_uv;...
Quoted 11 lines
drivers/iio/adc/ltc2378.c line 274
Quoted 9 lines
drivers/iio/adc/ltc2378.c new file +8
-0+static int ltc2378_regulator_setup (struct device *dev,struct ltc2378_state *st) +{ +int ret; + + ret =devm_regulator_get_enable_read_voltage (dev,"refin" ); +if (ret <0 && ret != -ENODEV ) { +return dev_err_probe (dev, ret,"failed to read refin regulator\n" ); + }else if (ret >0 ) {Else is not needed here.
Quoted 1 line
Why not?
The if returns unconditionally, so else is not needed. This is just a general principal.
Re: [PATCH v4 2/4] iio: adc: ltc2378: Add support for LTC2378-20 and similar ADCs
Quoted 1 line · David Lechner
On 6/29/26 9:57 AM, Marcelo Schmitt wrote:
...
Quoted 1 line
It could use
_offl ? ...in the macro for that. Not a big deal to me though.
Personally I am for a full spelling here.
...
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
drivers/iio/adc/ltc2378.c line 274
Quoted 8 lines
drivers/iio/adc/ltc2378.c new file +8
-0+static int ltc2378_regulator_setup (struct device *dev,struct ltc2378_state *st) +{ +int ret; + + ret =devm_regulator_get_enable_read_voltage (dev,"refin" ); +if (ret <0 && ret != -ENODEV ) { +return dev_err_probe (dev, ret,"failed to read refin regulator\n" ); + }else if (ret >0 ) {Else is not needed here.
Quoted 4 lines
Quoted 1 line
Why not?
The if returns unconditionally, so else is not needed. This is just a general principal.
Unfortunately in this case ENODEV will go further, I don't see full context, but it may lead to something unexpected.
Personally I prefer the ladder of
if (ret == -ENODEV) ... else if (ret < 0) ... else ...
Signature · 2 lines
With Best Regards, Andy Shevchenko
Re: [PATCH v4 2/4] iio: adc: ltc2378: Add support for LTC2378-20 and similar ADCs
Quoted 18 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
drivers/iio/adc/ltc2378.c line 274
Quoted 8 lines
drivers/iio/adc/ltc2378.c new file +8
-0+static int ltc2378_regulator_setup (struct device *dev,struct ltc2378_state *st) +{ +int ret; + + ret =devm_regulator_get_enable_read_voltage (dev,"refin" ); +if (ret <0 && ret != -ENODEV ) { +return dev_err_probe (dev, ret,"failed to read refin regulator\n" ); + }else if (ret >0 ) {Else is not needed here.
Quoted 4 lines
Quoted 1 line
Why not?
The if returns unconditionally, so else is not needed. This is just a general principal.
Unfortunately in this case ENODEV will go further, I don't see full context, but it may lead to something unexpected.
Quoted 9 lines
Personally I prefer the ladder of
if (ret == -ENODEV) ... else if (ret < 0) ... else ...
After splitting regulator availability check on a chip specific basis it will probably simplify to something like
static int ltc2378_refin_setup(struct device *dev, struct ltc2378_state *st)
{
int ret;
ret = devm_regulator_get_enable_read_voltage(dev, "refin");
if (ret == -ENODEV) /* refin is optional */
st->ref_uV = st->info->internal_ref_uv * 2; /* ref buf amplifies REFIN by a factor of 2 */
else if (ret < 0)
return dev_err_probe(...);
else
st->ref_uV = ret * 2; /* ref buf amplifies REFIN by a factor of 2 */
return 0;
}For 'ref' only parts it will probably look like previous versions
static int ltc2378_ref_setup(struct device *dev, struct ltc2378_state *st)
{
ret = devm_regulator_get_enable_read_voltage(dev, "ref"); /* ref is required */
if (ret < 0)
return dev_err_probe(dev, ret, "failed to read ref regulator\n");
st->ref_uV = ret;
return 0;
}Calling the appropriate ref setup function for each part shall then (hopefully) error out incorrect device trees.
Marcelo Schmitt
maintainerPATCH v4 3/4 iio: adc: ltc2378: Enable high-speed data capture
In reply to Marcelo SchmittMake use of SPI transfer offloading to speed up data capture, enabling data acquisition at faster sample rates (up to 2 MSPS).
---
Change log v3 -> v4:
- Squashed offload support into main driver since selecting SPI_OFFLOAD and depending on PWM is acceptable.
drivers/iio/adc/Kconfig | 6 + drivers/iio/adc/ltc2378.c | 359 +++++++++++++++++++++++++++++++++++++- 2 files changed, 362 insertions(+), 3 deletions(-)
drivers/iio/adc/Kconfig +6 -0
@@ -946,6 +946,12 @@ config LTC2378 depends on SPI depends on REGULATOR || COMPILE_TEST depends on GPIOLIB + depends on PWM + select IIO_BUFFER + select IIO_BUFFER_DMA + select IIO_BUFFER_DMAENGINE + select SPI_OFFLOAD + select SPI_OFFLOAD_TRIGGER_PWM help Say yes here to build support for Analog Devices LTC2378-20 and similar analog to digital converters.
drivers/iio/adc/ltc2378.c +356 -3
520 lines not on this page · raw message
Signature · 1 line
2.53.0
[email protected]
AI reviewRe: [PATCH v4 3/4] iio: adc: ltc2378: Enable high-speed data capture
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider: - [High] Missing verification of SPI offload trigger offset after validation loop in…
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] Missing verification of SPI offload trigger offset after validation loop in ltc2378_update_conversion_rate() allows silent data corruption.
- [Medium] In-out parameters accumulate drift across iterative rounding loops in ltc2378_update_conversion_rate().
- [Medium] Torn state on error path in ltc2378_update_conversion_rate() due to partially updated st->offload_trigger_config.
- [Low] Data race on st->cnv_Hz between sysfs readers and writers.
--
commit 57c4b9b3af36aafb3888623014ea397ad6cf0cd6
Author: Marcelo Schmitt <[email protected]>
iio: adc: ltc2378: Enable high-speed data capture
Make use of SPI transfer offloading to speed up data capture, enabling data acquisition at faster sample rates (up to 2 MSPS).
Quoted 3 lines
drivers/iio/adc/ltc2378.c +0
-0
[ ... ]
drivers/iio/adc/ltc2378.c static int ltc2378_read_raw(struct iio_dev *indio_dev, · line 349
Quoted 6 lines
drivers/iio/adc/ltc2378.c +2
-0@@ -254,7 +345,126 @@ static int ltc2378_read_raw(struct iio_dev *indio_dev, *val2 = chan->scan_type.realbits;return IIO_VAL_FRACTIONAL_LOG2 ; +case IIO_CHAN_INFO_SAMP_FREQ : + *val = st->cnv_Hz;
[Severity: Low]
When reading the frequency via ltc2378_read_raw(), st->cnv_Hz is read without acquiring the direct mode lock. Since it can be concurrently modified by ltc2378_update_conversion_rate() during a write, does this cause a data race? Should this be protected or accessed via READ_ONCE()?
Quoted 5 lines
drivers/iio/adc/ltc2378.c +5
-0+return IIO_VAL_INT ; +default : +return -EINVAL ; + } +}
[ ... ]
Quoted 2 lines
drivers/iio/adc/ltc2378.c +2
-0+static int ltc2378_update_conversion_rate (struct ltc2378_state *st,int freq_Hz) +{
[ ... ]
drivers/iio/adc/ltc2378.c static int ltc2378_read_raw(struct iio_dev *indio_dev, · line 418
Quoted 11 lines
drivers/iio/adc/ltc2378.c +10
-0+/* Configure CNV PWM waveform */ + cnv_wf.period_length_ns =DIV_ROUND_CLOSEST (NSEC_PER_SEC , freq_Hz); +/* +* Ensure CNV high time meets minimum requirement (20ns). The PWM +* hardware may round the duty cycle, so iterate until we get at least +* the minimum required high time. +*/ + do { + cnv_wf.duty_length_ns = target; + ret = pwm_round_waveform_might_sleep(st->cnv_trigger, &cnv_wf);
[Severity: Medium]
The pwm_round_waveform_might_sleep() function can modify the passed cnv_wf structure in place. Since the base period (cnv_wf.period_length_ns) is set before the loop and not reset inside, does this cause the period to drift across the iterations if the hardware constraints cause it to be repeatedly rounded?
Quoted 15 lines
drivers/iio/adc/ltc2378.c +15
-0+if (ret) +return ret; + target +=10 ;/* Increment by PWM duty cycle period */ + }while (count++ <100 && cnv_wf.duty_length_ns <LTC2378_TCNV_HIGH_NS ); + +/* Double check the minimum CNV high time is met */ +if (cnv_wf.duty_length_ns <LTC2378_TCNV_HIGH_NS ) +return -EIO ; + +/* +* Configure SPI offload PWM trigger. +* The trigger should fire after tBUSYLH + tCONV + tDSDOBUSYL. +* Minimum time needed: TBUSYLH (13ns) + TCONV (part-specific) + TDSDOBUSYL (5ns) +* +* Use the same period as CNV PWM to avoid timing issues.
drivers/iio/adc/ltc2378.c static int ltc2378_read_raw(struct iio_dev *indio_dev, · line 443
Quoted 10 lines
drivers/iio/adc/ltc2378.c +10
-0+* Convert back from period to frequency for the SPI offload API. +*/ + offload_period_ns = cnv_wf.period_length_ns; + config->periodic.frequency_hz =DIV_ROUND_UP (HZ_PER_GHZ , offload_period_ns); + min_read_offset =LTC2378_TBUSYLH_NS + st->info->tconv_ns +LTC2378_TDSDOBUSYL_NS ; + offload_offset_ns = min_read_offset; + count =0 ; + do { + config->periodic.offset_ns = offload_offset_ns; + ret = spi_offload_trigger_validate(st->offload_trigger, config);
[Severity: Medium]
The config pointer aliases st->offload_trigger_config. If this validation fails, the function returns the error directly below without rolling back the st->offload_trigger_config state. Could this leave the device in an inconsistent state where the old st->cnv_wf configuration is paired with a newly modified but rejected SPI trigger configuration upon the next postenable?
Additionally, similar to the PWM loop above, spi_offload_trigger_validate() modifies config in place. Does config->periodic.frequency_hz drift across iterations since it is not reset inside the loop?
drivers/iio/adc/ltc2378.c static int ltc2378_read_raw(struct iio_dev *indio_dev, · line 447
Quoted 4 lines
drivers/iio/adc/ltc2378.c +4
-0+if (ret) +return ret; + offload_offset_ns +=10 ; + }while (count++ <100 && config->periodic.offset_ns < min_read_offset);
[Severity: High]
If the loop exhausts its 100 retries without meeting the minimum offset requirement, won't it silently proceed here without returning an error?
Unlike the preceding PWM loop which explicitly checks the bounds afterward, could this missing check cause silent data corruption if the SPI controller ends up reading while the ADC is still converting?
Quoted 6 lines
drivers/iio/adc/ltc2378.c +6
-0+ + st->cnv_wf = cnv_wf; + st->cnv_Hz =DIV_ROUND_CLOSEST_ULL (HZ_PER_GHZ , cnv_wf.period_length_ns); + +return 0 ; +}
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=3
Re: [PATCH v4 3/4] iio: adc: ltc2378: Enable high-speed data capture
In reply to Marcelo SchmittQuoted 2 lines · Marcelo Schmitt
Make use of SPI transfer offloading to speed up data capture, enabling data acquisition at faster sample rates (up to 2 MSPS).
...
drivers/iio/adc/ltc2378.c line 16
Quoted 2 lines
drivers/iio/adc/ltc2378.c +2
-0+#include <linux/math.h> +#include <linux/math64.h>
The latter is superior, drop math.h
...
drivers/iio/adc/ltc2378.c line 73
Quoted 6 lines
struct
ltc2378_chip_info{drivers/iio/adc/ltc2378.c +2
-0const char *name;unsigned int internal_ref_uv;struct iio_chan_spec chan; +struct iio_chan_spec offload_chan; +unsigned int max_sample_rate_hz;
Perhaps _Hz for the consistency. I dunno in this case, because it's quite widespread (in small letters).
Quoted 2 lines
drivers/iio/adc/ltc2378.c +1
-0+unsigned int tconv_ns; };
...
drivers/iio/adc/ltc2378.c static int ltc2378_read_raw(struct iio_dev *indio_dev, · line 349
Quoted 1 line
drivers/iio/adc/ltc2378.c +1
-0+ *val = st->cnv_Hz;
Ah, you already use that, so please do in the above.
...
drivers/iio/adc/ltc2378.c static int ltc2378_read_raw(struct iio_dev *indio_dev, · line 405
Quoted 1 line
drivers/iio/adc/ltc2378.c +1
-0+if (freq_Hz <1 || freq_Hz > st->info->max_sample_rate_hz)
Can we use in_range()?
Quoted 1 line
drivers/iio/adc/ltc2378.c +1
-0+return -ERANGE ;
...
drivers/iio/adc/ltc2378.c static int ltc2378_read_raw(struct iio_dev *indio_dev, · line 422
Quoted 7 lines
drivers/iio/adc/ltc2378.c +7
-0+do { + cnv_wf.duty_length_ns = target; + ret =pwm_round_waveform_might_sleep (st->cnv_trigger, &cnv_wf); +if (ret) +return ret; + target +=10 ;/* Increment by PWM duty cycle period */ + }while (count++ <100 && cnv_wf.duty_length_ns <LTC2378_TCNV_HIGH_NS );
Seems count is not used directly, can be while (--count ...) as usual pattern.
drivers/iio/adc/ltc2378.c static int ltc2378_read_raw(struct iio_dev *indio_dev, · line 426
Quoted 3 lines
drivers/iio/adc/ltc2378.c +3
-0+/* Double check the minimum CNV high time is met */ +if (cnv_wf.duty_length_ns <LTC2378_TCNV_HIGH_NS ) +return -EIO ;
Hmm... How is this IO issue?
Quoted 10 lines
drivers/iio/adc/ltc2378.c +10
-0+/* +* Configure SPI offload PWM trigger. +* The trigger should fire after tBUSYLH + tCONV + tDSDOBUSYL. +* Minimum time needed: TBUSYLH (13ns) + TCONV (part-specific) + TDSDOBUSYL (5ns) +* +* Use the same period as CNV PWM to avoid timing issues. +* Convert back from period to frequency for the SPI offload API. +*/ + offload_period_ns = cnv_wf.period_length_ns; + config->periodic.frequency_hz =DIV_ROUND_UP (HZ_PER_GHZ , offload_period_ns);
drivers/iio/adc/ltc2378.c static int ltc2378_read_raw(struct iio_dev *indio_dev, · line 447
Quoted 10 lines
drivers/iio/adc/ltc2378.c +10
-0+ min_read_offset =LTC2378_TBUSYLH_NS + st->info->tconv_ns +LTC2378_TDSDOBUSYL_NS ; + offload_offset_ns = min_read_offset; + count =0 ; +do { + config->periodic.offset_ns = offload_offset_ns; + ret =spi_offload_trigger_validate (st->offload_trigger, config); +if (ret) +return ret; + offload_offset_ns +=10 ; + }while (count++ <100 && config->periodic.offset_ns < min_read_offset);
Same comment against count.
Signature · 2 lines
With Best Regards, Andy Shevchenko
Re: [PATCH v4 3/4] iio: adc: ltc2378: Enable high-speed data capture
Quoted 5 lines
drivers/iio/adc/ltc2378.c static int ltc2378_read_raw(struct iio_dev *indio_dev, · line 426
Quoted 3 lines
drivers/iio/adc/ltc2378.c +3
-0+/* Double check the minimum CNV high time is met */ +if (cnv_wf.duty_length_ns <LTC2378_TCNV_HIGH_NS ) +return -EIO ;Hmm... How is this IO issue?
Okay, what about EDOM for PWM setup failures? Any error code suggestion otherwise? Will follow the other suggestions.
Thanks,
Marcelo
Re: [PATCH v4 3/4] iio: adc: ltc2378: Enable high-speed data capture
Quoted 8 lines · Marcelo Schmitt
Quoted 5 lines
drivers/iio/adc/ltc2378.c static int ltc2378_read_raw(struct iio_dev *indio_dev, · line 426
Quoted 3 lines
drivers/iio/adc/ltc2378.c +3
-0+/* Double check the minimum CNV high time is met */ +if (cnv_wf.duty_length_ns <LTC2378_TCNV_HIGH_NS ) +return -EIO ;Hmm... How is this IO issue?
Okay, what about EDOM for PWM setup failures? Any error code suggestion otherwise? Will follow the other suggestions.
Seems -EDOM is in use in some cases of PWM. I haven't checked those cases, and if fits I have no objection.
"-EDOM if setting failed due to the exact waveform not being possible" (from PWM code comments).
Signature · 2 lines
With Best Regards, Andy Shevchenko
Marcelo Schmitt
maintainerPATCH v4 4/4 iio: adc: ltc2378: Enable triggered buffer data capture
In reply to Marcelo SchmittEnable users to run triggered data captures with LTC2378 and similar ADCs.
---
Change log v3 -> v4:
- Squashed triggered buffer support into main driver.
drivers/iio/adc/Kconfig | 1 + drivers/iio/adc/ltc2378.c | 76 +++++++++++++++++++++++++++------------ 2 files changed, 54 insertions(+), 23 deletions(-)
drivers/iio/adc/Kconfig +1 -0
@@ -950,6 +950,7 @@ config LTC2378 select IIO_BUFFER select IIO_BUFFER_DMA select IIO_BUFFER_DMAENGINE + select IIO_TRIGGERED_BUFFER select SPI_OFFLOAD select SPI_OFFLOAD_TRIGGER_PWM help
drivers/iio/adc/ltc2378.c +53 -23
226 lines not on this page · raw message
Signature · 1 line
2.53.0
[email protected]
AI reviewRe: [PATCH v4 4/4] iio: adc: ltc2378: Enable triggered buffer data capture
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Single reads via sysfs (in_voltage0_raw) return scrambled/garbage data when the SPI offload engine is configured, because they incorrectly use the offload channel's endianness and shift properties. --
commit 5a2926870e368170637e86d31e6346617e37a6b1
Author: Marcelo Schmitt <[email protected]>
iio: adc: ltc2378: Enable triggered buffer data capture
Enable users to run triggered data captures with LTC2378 and similar ADCs.
Quoted 4 lines
drivers/iio/adc/ltc2378.c +0
-0
[ ... ]
Quoted 9 lines
drivers/iio/adc/ltc2378.c +3
-2@@ -640,8 +662,16 @@ static int ltc2378_probe(struct spi_device *spi)/* Fall back to low speed usage when no SPI offload is available. */ if (ret == -ENODEV ) { indio_dev->info = <c2378_iio_info; - indio_dev->channels = &st->info->chan; - indio_dev->num_channels =1 ; + indio_dev->channels = st->info->chan; + indio_dev->num_channels =ARRAY_SIZE (st->info->chan); +
drivers/iio/adc/ltc2378.c static int ltc2378_probe(struct spi_device *spi) · line 677
Quoted 10 lines
drivers/iio/adc/ltc2378.c +7
-0+ ret =devm_iio_triggered_buffer_setup (dev, indio_dev, + iio_pollfunc_store_time, + ltc2378_trigger_handler, +NULL ); +if (ret) +return dev_err_probe (dev, ret, +"failed to setup triggered buffer\n" ); }else if (ret) {return dev_err_probe (dev, ret,"failed to get offload\n" ); }else {
[Severity: High]
This is a pre-existing issue, but do single reads via sysfs (in_voltage0_raw) return scrambled data when the SPI offload engine is configured?
When offload is configured, indio_dev->channels is assigned to the offload channel just after this else block in ltc2378_probe():
indio_dev->channels = &st->info->offload_chan;
This channel specification is later passed to ltc2378_channel_single_read(). However, the single read function relies on the channel's endianness and shift properties to decode the raw SPI data:
static int ltc2378_channel_single_read(const struct iio_chan_spec *chan, ...)
{
...
if (chan->scan_type.endianness == IIO_BE) {
if (chan->scan_type.realbits > 16)
sample = be32_to_cpu(st->scan.data.sample_buf32_be);
else
sample = be16_to_cpu(st->scan.data.sample_buf16_be);
} else {
if (chan->scan_type.realbits > 16)
sample = st->scan.data.sample_buf32;
else
sample = st->scan.data.sample_buf16;
}
sample >>= chan->scan_type.shift;
...
}Because the offload_chan specification defines data as CPU-endian with a 0 shift, the else branch is taken. This treats the natively big-endian, MSB-aligned SPI data as unshifted CPU-endian data, scrambling the values on little-endian architectures.
Could this be updated to properly handle manual sysfs reads when offload is enabled?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=4
Re: [PATCH v4 4/4] iio: adc: ltc2378: Enable triggered buffer data capture
In reply to Marcelo SchmittQuoted 1 line · Marcelo Schmitt
Enable users to run triggered data captures with LTC2378 and similar ADCs.
...
drivers/iio/adc/ltc2378.c static int ltc2378_probe(struct spi_device *spi) · line 674
Quoted 10 lines
drivers/iio/adc/ltc2378.c +10
-0+ indio_dev->channels = st->info->chan; + indio_dev->num_channels =ARRAY_SIZE (st->info->chan); + + ret =devm_iio_triggered_buffer_setup (dev, indio_dev, + iio_pollfunc_store_time, + ltc2378_trigger_handler, +NULL ); +if (ret) +return dev_err_probe (dev, ret, +"failed to setup triggered buffer\n" );
In 99.99% of error cases this will be -ENOMEM, so this is a dead code effectively. Please, drop the message, return ret is enough.
Signature · 2 lines
With Best Regards, Andy Shevchenko
Quoted 5 lines · Marcelo Schmitt
This patch series adds support for LTC2378 and similar low noise, low power, high speed, successive approximation register (SAR) ADCs. These ADCs are similar among each other, varying mainly on the amount of precision bits, maximum sample rate, and input configuration (either fully differential or pseudo-differential).
I had a few minor comments and I suspect Sashiko found a few legitimate things. But this is looking really nice now.
Jonathan Cameron
maintainerQuoted 6 lines · On Sat, 27 Jun 2026 16:39:32 -0500 David Lechner <[email protected]> wrote:
Quoted 5 lines · Marcelo Schmitt
This patch series adds support for LTC2378 and similar low noise, low power, high speed, successive approximation register (SAR) ADCs. These ADCs are similar among each other, varying mainly on the amount of precision bits, maximum sample rate, and input configuration (either fully differential or pseudo-differential).
Quoted 6 lines
I had a few minor comments and I suspect Sashiko found a few legitimate things. But this is looking really nice now.
Reviewed-by David Lechner <[email protected]>
FWIW I took a quick look as well and didn't have anything to add. Indeed do check Sashiko though. I didn't plough through figuring out if the comments are valid or not.
https://sashiko.dev/#/patchset/cover.1782397418.git.marcelo.schmitt%40analog.com