iio: adc: Add support for LTC2378 and similar ADCs
Marcelo Schmitt
maintainerv5 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
Previous submissions:
v4: https://lore.kernel.org/linux-iio/[email protected]/
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 v4 -> v5:
[DT]
- LTC2338 is slightly different from LTC2378 and, because of that, software can't really handle those the same way. No longer setting fallback for LTC2338.
[IIO]
- Took internal reference buffer amplification into account.
- Added checks for PWM parameters after both CNV and Offload trigger PWMs have been configured.
- Return EDOM instead of EIO when failing to achieve a specific PWM configuration.
- Set single-read transfer bits_per_word so the SPI subsystem re-arranges data to CPU endianness, enabling us to reuse offload_chan specifications for single-shot reads.
- Replaced open-coded check by in_range().
- Used conventional loop count decrement pattern instead of count increment.
- Renamed max_sample_rate_hz -> max_sample_rate_Hz.
- Dropped error message on devm_iio_triggered_buffer_setup() fail.
- A few other minor codestyle improvements.
Hopefully, this new version shall tackle all concerns and issues raised both by human reviewers and sashiko.
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 | 184 ++++ MAINTAINERS | 8 + drivers/iio/adc/Kconfig | 19 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ltc2378.c | 802 ++++++++++++++++++ 5 files changed, 1014 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 v5 1/4 dt-bindings: iio: adc: Add ltc2378
Document how to describe LTC2378-20 and similar ADCs in device tree.
---
Change log v4 -> v5:
- LTC2338 is slightly different from LTC2378 and, because of that, software can't really handle those the same way. No longer specify fallback for LTC2338.
.../bindings/iio/adc/adi,ltc2378.yaml | 184 ++++++++++++++++++ MAINTAINERS | 7 + 2 files changed, 191 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/adi,ltc2378.yaml
Documentation/devicetree/bindings/iio/adc/adi,ltc2378.yaml new file +184 -0
@@ -0,0 +1,184 @@ +# 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,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 v5 1/4] dt-bindings: iio: adc: Add ltc2378
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Low] Compatible strings with required fallbacks are incorrectly allowed as standalone strings. --
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] Compatible strings with required fallbacks are incorrectly allowed as standalone strings. --
commit fff47614872c95c6a481f63da8b14dfcedd0bb53
Author: Marcelo Schmitt <[email protected]>
dt-bindings: iio: adc: Add ltc2378
Document how to describe LTC2378-20 and similar ADCs in device tree.
Quoted 4 lines
Documentation/devicetree/bindings/iio/adc/adi,ltc2378.yaml new file +0
-0
[ ... ]
Quoted 4 lines
Documentation/devicetree/bindings/iio/adc/adi,ltc2378.yaml new file +4
-0+properties: + compatible: + oneOf: + # Single compatible string match.
Documentation/devicetree/bindings/iio/adc/adi,ltc2378.yaml line 51
Quoted 10 lines
Documentation/devicetree/bindings/iio/adc/adi,ltc2378.yaml new file +10
-0+ - 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
[Severity: Low]
Does this standalone enum allow devices that should require a fallback to pass schema validation with only a single compatible string?
Because parts like "adi,ltc2370-16" and "adi,ltc2367-16" are listed here in the single enum match, a device tree node specifying only compatible = "adi,ltc2370-16" will satisfy this block and successfully pass schema validation.
This seems to bypass the fallback requirements defined below in the items blocks:
[ ... ]
Documentation/devicetree/bindings/iio/adc/adi,ltc2378.yaml line 70
Quoted 7 lines
Documentation/devicetree/bindings/iio/adc/adi,ltc2378.yaml new file +7
-0+ # 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)
Should the parts that require a fallback be removed from the single compatible string enum so the schema correctly enforces the fallback?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
Re: [PATCH v5 1/4] dt-bindings: iio: adc: Add ltc2378
Quoted 52 lines · On 07/02, [email protected] wrote:
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] Compatible strings with required fallbacks are incorrectly allowed as standalone strings. --commit
fff47614872c95c6a481f63da8b14dfcedd0bb53
Author: Marcelo Schmitt <[email protected]>dt-bindings: iio: adc: Add ltc2378
Document how to describe LTC2378-20 and similar ADCs in device tree.
Quoted 4 lines
Documentation/devicetree/bindings/iio/adc/adi,ltc2378.yaml new file +0
-0[ ... ]
Quoted 4 lines
Documentation/devicetree/bindings/iio/adc/adi,ltc2378.yaml new file +4
-0+properties: + compatible: + oneOf: + # Single compatible string match.Documentation/devicetree/bindings/iio/adc/adi,ltc2378.yaml line 51
Quoted 10 lines
Documentation/devicetree/bindings/iio/adc/adi,ltc2378.yaml new file +10
-0+ - 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[Severity: Low]
Does this standalone enum allow devices that should require a fallback to pass schema validation with only a single compatible string?Because parts like "adi,ltc2370-16" and "adi,ltc2367-16" are listed here in the single enum match, a device tree node specifying only compatible = "adi,ltc2370-16" will satisfy this block and successfully pass schema validation.
This seems to bypass the fallback requirements defined below in the items blocks:
[ ... ]
Documentation/devicetree/bindings/iio/adc/adi,ltc2378.yaml line 70
Quoted 7 lines
Documentation/devicetree/bindings/iio/adc/adi,ltc2378.yaml new file +7
-0+ # 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)
Quoted 2 lines
Should the parts that require a fallback be removed from the single compatible string enum so the schema correctly enforces the fallback?
Why? Should users be prevented to specify a single specific compatible string?
Quoted 3 lines
Signature · 2 lines
-- Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
Jonathan Cameron
maintainerRe: [PATCH v5 1/4] dt-bindings: iio: adc: Add ltc2378
Quoted 53 lines · On Fri, 3 Jul 2026 14:04:51 -0300 Marcelo Schmitt <[email protected]>…
Quoted 52 lines · On 07/02, [email protected] wrote:
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] Compatible strings with required fallbacks are incorrectly allowed as standalone strings. --commit
fff47614872c95c6a481f63da8b14dfcedd0bb53
Author: Marcelo Schmitt <[email protected]>dt-bindings: iio: adc: Add ltc2378
Document how to describe LTC2378-20 and similar ADCs in device tree.
Quoted 4 lines
Documentation/devicetree/bindings/iio/adc/adi,ltc2378.yaml new file +0
-0[ ... ]
Quoted 4 lines
Documentation/devicetree/bindings/iio/adc/adi,ltc2378.yaml new file +4
-0+properties: + compatible: + oneOf: + # Single compatible string match.Documentation/devicetree/bindings/iio/adc/adi,ltc2378.yaml line 51
Quoted 10 lines
Documentation/devicetree/bindings/iio/adc/adi,ltc2378.yaml new file +10
-0+ - 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[Severity: Low]
Does this standalone enum allow devices that should require a fallback to pass schema validation with only a single compatible string?Because parts like "adi,ltc2370-16" and "adi,ltc2367-16" are listed here in the single enum match, a device tree node specifying only compatible = "adi,ltc2370-16" will satisfy this block and successfully pass schema validation.
This seems to bypass the fallback requirements defined below in the items blocks:
[ ... ]
Quoted 7 lines
Documentation/devicetree/bindings/iio/adc/adi,ltc2378.yaml new file +7
-0+ # 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)
Quoted 4 lines
Quoted 2 lines
Should the parts that require a fallback be removed from the single compatible string enum so the schema correctly enforces the fallback?
Why? Should users be prevented to specify a single specific compatible string?
Yes we should. They should always use the double string to provide a fallback.
In practice the driver will work just fine with only a single entry irrespective of what the binding doc says - that doesn't change that we insist on it in the binding doc.
Jonathan
Marcelo Schmitt
maintainerPATCH v5 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 v4 -> v5:
- Took internal reference buffer amplification into account.
The _offload parameter is a preparation for the followup offload enablement patch. Kept in the initial patch to reduce code diff.
The (((_real_bits) > 16) ? 32 : 16) part of normal channel macros could be moved into LTC2378_DIFF_CHANNEL(), becoming
.realbits = (_offload ? (_real_bits) : (((_real_bits) > 16) ? 32 : 16)), \
IMHO, that is a bit harder to read so I kept a small repetition in favor of readability.
Did not pick David's review tag because not all of his suggestions were applied.
MAINTAINERS | 1 + drivers/iio/adc/Kconfig | 12 ++ drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ltc2378.c | 404 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 418 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 +404 -0
404 lines not on this page · raw message
Signature · 1 line
2.53.0
[email protected]
AI reviewRe: [PATCH v5 2/4] iio: adc: ltc2378: Add support for LTC2378-20 and similar ADCs
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider: - [High] Hardware protocol violation: CNV is held high during SPI read - [High] SPI bus not locked during…
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] Hardware protocol violation: CNV is held high during SPI read
- [High] SPI bus not locked during ADC conversion phase
- [Medium] Incorrect scale calculation for LTC2338-18 and similar ADCs
- [Low] Undefined direct mode macros lead to build failure
--
commit b74b536d18af0084ea31bd1e1e8cf9454da5e29c
Author: Marcelo Schmitt <[email protected]>
iio: adc: ltc2378: Add support for LTC2378-20 and similar ADCs
This commit adds support for the Analog Devices LTC2378-20 and similar analog-to-digital converters. It introduces a new IIO driver using the SPI subsystem.
Quoted 6 lines
drivers/iio/adc/ltc2378.c new file +0
-0@@ -0,0 +1,404 @@
[ ... ]
Quoted 5 lines
drivers/iio/adc/ltc2378.c new file +5
-0+static const struct ltc2378_chip_info ltc2338_18_chip_info = { + .name ="ltc2338-18" , + .internal_ref_uV =4096000 , + .chan =LTC2378_BIPOLAR_DIFF_CHANNEL (18 ), +};
[ ... ]
drivers/iio/adc/ltc2378.c line 184
Quoted 7 lines
drivers/iio/adc/ltc2378.c new file +7
-0+static int ltc2378_convert_and_acquire (struct ltc2378_state *st) +{ +int ret; + +/* Cause a rising edge of CNV to initiate a new ADC conversion */ +gpiod_set_value_cansleep (st->cnv_gpio,1 ); +fsleep (4 );
[Severity: High]
Can this sequence cause data corruption on a shared SPI bus?
The CNV pin is toggled and an fsleep(4) occurs before spi_sync_transfer() locks the bus. If another SPI transaction occurs during this sleep window, could it toggle the SCK line and prematurely clock data out of the ADC?
Should the conversion-and-read sequence be wrapped in spi_bus_lock() and spi_bus_unlock()?
drivers/iio/adc/ltc2378.c line 185
Quoted 1 line
drivers/iio/adc/ltc2378.c new file +1
-0+ ret =spi_sync_transfer (st->spi, &st->xfer,1 );
[Severity: High]
Does reading from the SPI bus while CNV is held high violate the hardware protocol?
The ADC requires the CNV pin to be brought low to enable the SDO output before clocking out data via SPI, but spi_sync_transfer() happens before gpiod_set_value_cansleep(st->cnv_gpio, 0), which might result in reading high-impedance garbage data.
Quoted 4 lines
drivers/iio/adc/ltc2378.c new file +4
-0+gpiod_set_value_cansleep (st->cnv_gpio,0 ); + +return ret; +}
[ ... ]
drivers/iio/adc/ltc2378.c line 235
Quoted 12 lines
drivers/iio/adc/ltc2378.c new file +12
-0+static int ltc2378_read_raw (struct iio_dev *indio_dev, +const struct iio_chan_spec *chan, +int *val,int *val2,long mask) +{ +struct ltc2378_state *st =iio_priv (indio_dev); +int ret; + +switch (mask) { +case IIO_CHAN_INFO_RAW : { +IIO_DEV_ACQUIRE_DIRECT_MODE (indio_dev, claim); +if (IIO_DEV_ACQUIRE_FAILED (claim)) +return -EBUSY ;
[Severity: Low]
Will this cause a build failure?
The macros IIO_DEV_ACQUIRE_DIRECT_MODE and IIO_DEV_ACQUIRE_FAILED appear to be undeclared in the kernel tree.
drivers/iio/adc/ltc2378.c line 244
Quoted 9 lines
drivers/iio/adc/ltc2378.c new file +9
-0+ + ret =ltc2378_channel_single_read (chan, st, val); +if (ret) +return ret; + +return IIO_VAL_INT ; + } +case IIO_CHAN_INFO_SCALE : + *val = st->ref_uV /MILLI ;
[Severity: Medium]
Does this calculate an incorrect IIO scale for the LTC2338-18?
Does this miss the 2.5x input span multiplier unique to the LTC2338-18 when calculating the IIO scale here?
Quoted 17 lines
drivers/iio/adc/ltc2378.c new file +17
-0+/* +* For all LTC2378-like devices, the amount of bits that express +* voltage magnitude depend on the polarity / output code format: +* - straight binary: All precision/resolution bits are used. +* - 2's complement: One of the precision bits is used for sign. +*/ +if (chan->scan_type.format ==IIO_SCAN_FORMAT_SIGNED_INT ) + *val2 = chan->scan_type.realbits -1 ; +else + *val2 = chan->scan_type.realbits; + +return IIO_VAL_FRACTIONAL_LOG2 ; + +default : +return -EINVAL ; + } +}
[ ... ]
drivers/iio/adc/ltc2378.c line 277
Quoted 11 lines
drivers/iio/adc/ltc2378.c new file +11
-0+static int ltc2378_refin_setup (struct device *dev,struct ltc2378_state *st) +{ +int ret; + +/* +* The internal reference buffer amplifies both the internal reference +* and REFIN by a factor of 2. +*/ + ret =devm_regulator_get_enable_read_voltage (dev,"refin" ); +if (ret == -ENODEV )/* refin is optional */ + st->ref_uV = st->info->internal_ref_uV *2 ;
[Severity: Medium]
Does this incorrectly double the internal reference voltage?
The ltc2338_18_chip_info already defines internal_ref_uV as the post-buffer value of 4096000 (4.096V). Multiplying it by 2 here would result in an incorrect scale value.
Quoted 7 lines
drivers/iio/adc/ltc2378.c new file +7
-0+else if (ret <0 ) +return dev_err_probe (dev, ret,"failed to read refin regulator\n" ); +else + st->ref_uV = ret *2 ; + +return 0 ; +}
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
Re: [PATCH v5 2/4] iio: adc: ltc2378: Add support for LTC2378-20 and similar ADCs
Quoted 44 lines · On 07/02, [email protected] wrote:
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] Hardware protocol violation: CNV is held high during SPI read
- [High] SPI bus not locked during ADC conversion phase
- [Medium] Incorrect scale calculation for LTC2338-18 and similar ADCs
- [Low] Undefined direct mode macros lead to build failure
--commit
b74b536d18af0084ea31bd1e1e8cf9454da5e29c
Author: Marcelo Schmitt <[email protected]>iio: adc: ltc2378: Add support for LTC2378-20 and similar ADCs
This commit adds support for the Analog Devices LTC2378-20 and similar analog-to-digital converters. It introduces a new IIO driver using the SPI subsystem.
Quoted 6 lines
drivers/iio/adc/ltc2378.c new file +0
-0@@ -0,0 +1,404 @@[ ... ]
Quoted 5 lines
drivers/iio/adc/ltc2378.c new file +5
-0+static const struct ltc2378_chip_info ltc2338_18_chip_info = { + .name ="ltc2338-18" , + .internal_ref_uV =4096000 , + .chan =LTC2378_BIPOLAR_DIFF_CHANNEL (18 ), +};[ ... ]
drivers/iio/adc/ltc2378.c line 184
Quoted 7 lines
drivers/iio/adc/ltc2378.c new file +7
-0+static int ltc2378_convert_and_acquire (struct ltc2378_state *st) +{ +int ret; + +/* Cause a rising edge of CNV to initiate a new ADC conversion */ +gpiod_set_value_cansleep (st->cnv_gpio,1 ); +fsleep (4 );[Severity: High]
Can this sequence cause data corruption on a shared SPI bus?
Quoted 3 lines
The CNV pin is toggled and an fsleep(4) occurs before
spi_sync_transfer()locks the bus. If another SPI transaction occurs during this sleep window, could it toggle the SCK line and prematurely clock data out of the ADC?
Makes sense.
Quoted 3 lines
Should the conversion-and-read sequence be wrapped in
spi_bus_lock()andspi_bus_unlock()?
Because these chips don't have CS line, it seems that locking the bus actually makes sense.
Quoted 6 lines
drivers/iio/adc/ltc2378.c line 185
Quoted 2 lines
drivers/iio/adc/ltc2378.c new file +1
-0+ ret =spi_sync_transfer (st->spi, &st->xfer,1 );[Severity: High]
Does reading from the SPI bus while CNV is held high violate the hardware protocol?
No.
Quoted 5 lines
The ADC requires the CNV pin to be brought low to enable the SDO output before clocking out data via SPI, but
spi_sync_transfer()happens beforegpiod_set_value_cansleep(st->cnv_gpio, 0), which might result in reading high-impedance garbage data.
See 'Using a Single LTC23... in Normal Mode' diagrams (usually Figure 10, 13, or 15 in datasheets). CNV can be either low or high during data transfers.
Quoted 24 lines
Quoted 5 lines
drivers/iio/adc/ltc2378.c new file +4
-0+gpiod_set_value_cansleep (st->cnv_gpio,0 ); + +return ret; +}[ ... ]
drivers/iio/adc/ltc2378.c line 235
Quoted 12 lines
drivers/iio/adc/ltc2378.c new file +12
-0+static int ltc2378_read_raw (struct iio_dev *indio_dev, +const struct iio_chan_spec *chan, +int *val,int *val2,long mask) +{ +struct ltc2378_state *st =iio_priv (indio_dev); +int ret; + +switch (mask) { +case IIO_CHAN_INFO_RAW : { +IIO_DEV_ACQUIRE_DIRECT_MODE (indio_dev, claim); +if (IIO_DEV_ACQUIRE_FAILED (claim)) +return -EBUSY ;[Severity: Low]
Will this cause a build failure?
Quoted 2 lines
The macros
IIO_DEV_ACQUIRE_DIRECT_MODEandIIO_DEV_ACQUIRE_FAILEDappear to be undeclared in the kernel tree.
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/linux/iio/iio.h?h=v7.2-rc1#n785
Outdated LLM?
Quoted 14 lines
drivers/iio/adc/ltc2378.c line 244
Quoted 10 lines
drivers/iio/adc/ltc2378.c new file +9
-0+ + ret =ltc2378_channel_single_read (chan, st, val); +if (ret) +return ret; + +return IIO_VAL_INT ; + } +case IIO_CHAN_INFO_SCALE : + *val = st->ref_uV /MILLI ;[Severity: Medium]
Does this calculate an incorrect IIO scale for the LTC2338-18?
Quoted 2 lines
Does this miss the 2.5x input span multiplier unique to the LTC2338-18 when calculating the IIO scale here?
That's taken care of in ltc2378_refin_setup().
Quoted 36 lines
Quoted 18 lines
drivers/iio/adc/ltc2378.c new file +17
-0+/* +* For all LTC2378-like devices, the amount of bits that express +* voltage magnitude depend on the polarity / output code format: +* - straight binary: All precision/resolution bits are used. +* - 2's complement: One of the precision bits is used for sign. +*/ +if (chan->scan_type.format ==IIO_SCAN_FORMAT_SIGNED_INT ) + *val2 = chan->scan_type.realbits -1 ; +else + *val2 = chan->scan_type.realbits; + +return IIO_VAL_FRACTIONAL_LOG2 ; + +default : +return -EINVAL ; + } +}[ ... ]
drivers/iio/adc/ltc2378.c line 277
Quoted 11 lines
drivers/iio/adc/ltc2378.c new file +11
-0+static int ltc2378_refin_setup (struct device *dev,struct ltc2378_state *st) +{ +int ret; + +/* +* The internal reference buffer amplifies both the internal reference +* and REFIN by a factor of 2. +*/ + ret =devm_regulator_get_enable_read_voltage (dev,"refin" ); +if (ret == -ENODEV )/* refin is optional */ + st->ref_uV = st->info->internal_ref_uV *2 ;[Severity: Medium]
Does this incorrectly double the internal reference voltage?
Quoted 3 lines
The
ltc2338_18_chip_infoalready definesinternal_ref_uVas the post-buffer value of 4096000 (4.096V). Multiplying it by 2 here would result in an incorrect scale value.
Indeed,
- .internal_ref_uV = 4096000,
+ .internal_ref_uV = 2048000,
will solve the issue.
Quoted 11 lines
Quoted 8 lines
drivers/iio/adc/ltc2378.c new file +7
-0+else if (ret <0 ) +return dev_err_probe (dev, ret,"failed to read refin regulator\n" ); +else + st->ref_uV = ret *2 ; + +return 0 ; +}Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
Jonathan Cameron
maintainerRe: [PATCH v5 2/4] iio: adc: ltc2378: Add support for LTC2378-20 and similar ADCs
Quoted 48 lines · On Fri, 3 Jul 2026 14:14:50 -0300 Marcelo Schmitt <[email protected]>…
Quoted 44 lines · On 07/02, [email protected] wrote:
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] Hardware protocol violation: CNV is held high during SPI read
- [High] SPI bus not locked during ADC conversion phase
- [Medium] Incorrect scale calculation for LTC2338-18 and similar ADCs
- [Low] Undefined direct mode macros lead to build failure
--commit
b74b536d18af0084ea31bd1e1e8cf9454da5e29c
Author: Marcelo Schmitt <[email protected]>iio: adc: ltc2378: Add support for LTC2378-20 and similar ADCs
This commit adds support for the Analog Devices LTC2378-20 and similar analog-to-digital converters. It introduces a new IIO driver using the SPI subsystem.
Quoted 6 lines
drivers/iio/adc/ltc2378.c new file +0
-0@@ -0,0 +1,404 @@[ ... ]
Quoted 5 lines
drivers/iio/adc/ltc2378.c new file +5
-0+static const struct ltc2378_chip_info ltc2338_18_chip_info = { + .name ="ltc2338-18" , + .internal_ref_uV =4096000 , + .chan =LTC2378_BIPOLAR_DIFF_CHANNEL (18 ), +};[ ... ]
drivers/iio/adc/ltc2378.c line 184
Quoted 7 lines
drivers/iio/adc/ltc2378.c new file +7
-0+static int ltc2378_convert_and_acquire (struct ltc2378_state *st) +{ +int ret; + +/* Cause a rising edge of CNV to initiate a new ADC conversion */ +gpiod_set_value_cansleep (st->cnv_gpio,1 ); +fsleep (4 );[Severity: High]
Can this sequence cause data corruption on a shared SPI bus?Quoted 3 lines
The CNV pin is toggled and an fsleep(4) occurs before
spi_sync_transfer()locks the bus. If another SPI transaction occurs during this sleep window, could it toggle the SCK line and prematurely clock data out of the ADC?
Quoted 6 lines
Makes sense.
Quoted 3 lines
Should the conversion-and-read sequence be wrapped in
spi_bus_lock()andspi_bus_unlock()?Because these chips don't have CS line, it seems that locking the bus actually makes sense.
What does it even mean? If there is no CS then the bus can only sensibly have one device on it. I'm not sure if the SPI core enforces that but in practice you should never see a board that has multiple devices.
Hence locking could be at the device driver level rather than the bus. I guess bus locking would provide the same conditions and maybe acts as documentation.
Jonathan
Jonathan Cameron
maintainerRe: [PATCH v5 2/4] iio: adc: ltc2378: Add support for LTC2378-20 and similar ADCs
In reply to Marcelo SchmittQuoted 3 lines · On Thu, 2 Jul 2026 18:45:27 -0300 Marcelo Schmitt <[email protected]>…
Support for LTC2378-20 and similar analog-to-digital converters.
Signed-off-by Marcelo Schmitt <[email protected]>
Just a couple of trivial additional comments as you are spinning again anyway.
Quoted 11 lines
drivers/iio/adc/ltc2378.c new file +5
-0@@ -0,0 +1,404 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* +* Analog Devices LTC2378 ADC series driver +* +* Copyright (C) 2026 Analog Devices Inc.
drivers/iio/adc/ltc2378.c line 15
Quoted 10 lines
drivers/iio/adc/ltc2378.c new file +10
-0+* 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>
Drop this one. Uwe just had a series merged that moved the relevant include path into spi/spi.h
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/diff/include/linux/spi/spi.h?id=ecca1d63c1eadbbb38ceab82de0f7adfbc2b465d
I'll probably rebase the iio tree on rc2 or merge that in to resolve any conflicts.
drivers/iio/adc/ltc2378.c line 23
Quoted 8 lines
drivers/iio/adc/ltc2378.c new file +8
-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>
We had some discussion about this recently and IIRC concluded that types.h will always be included by iio.h so maybe just iio.h is enough.
I don't care strongly either way though.
Quoted 8 lines
drivers/iio/adc/ltc2378.c new file +8
-0+ +static int ltc2378_channel_single_read (const struct iio_chan_spec *chan, +struct ltc2378_state *st,int *val) +{ +const struct iio_scan_type *scan_type = &chan->scan_type; +u32 sample; +int ret; +
drivers/iio/adc/ltc2378.c line 207
Quoted 10 lines
drivers/iio/adc/ltc2378.c new file +10
-0+ ret =ltc2378_convert_and_acquire (st); +if (ret) +return ret; + +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 {
Trivial but can we have a /* IIO_CPU */ for this else.
I briefly wondered why for little endian we didn't need to use lexx_to_cpu() before registering this is for offload where the spi controller is dealing with it (and hence IIO_CPU for the endian)
Quoted 15 lines
drivers/iio/adc/ltc2378.c new file +15
-0+if (chan->scan_type.realbits >16 ) + sample = st->scan.data.sample_buf32; +else + sample = st->scan.data.sample_buf16; + } + + sample >>= chan->scan_type.shift; + +if (scan_type->format ==IIO_SCAN_FORMAT_SIGNED_INT ) + *val =sign_extend32 (sample, scan_type->realbits -1 ); +else + *val = sample; + +return 0 ; +}
Re: [PATCH v5 2/4] iio: adc: ltc2378: Add support for LTC2378-20 and similar ADCs
In reply to Marcelo SchmittQuoted 1 line · Marcelo Schmitt
+#include <
linux/mod_devicetable.h>
Please don't add new users for this header file. Only use those <linux/device-id/*.h> that you actually need (if any).
Thanks
Uwe
Marcelo Schmitt
maintainerPATCH v5 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 v4 -> v5:
- Added checks for PWM parameters after both CNV and Offload trigger PWMs have been configured.
- Return EDOM instead of EIO when failing to achieve a specific PWM configuration.
- Set single-read transfer bits_per_word so the SPI subsystem re-arranges data to CPU endianness, enabling us to reuse offload_chan specifications for single-shot reads.
- Replaced open-coded check by in_range().
- Used conventional loop count decrement pattern instead of count increment.
- Renamed max_sample_rate_hz -> max_sample_rate_Hz.
- A few other minor codestyle improvements.
drivers/iio/adc/Kconfig | 6 + drivers/iio/adc/ltc2378.c | 375 +++++++++++++++++++++++++++++++++++++- 2 files changed, 378 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 +372 -3
536 lines not on this page · raw message
Signature · 1 line
2.53.0
[email protected]
AI reviewRe: [PATCH v5 3/4] iio: adc: ltc2378: Enable high-speed data capture
Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider: - [Critical] Access to non-existent `offset_ns` field in `struct spi_offload_trigger_periodic` causes a…
Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
- [Critical] Access to non-existent offset_ns field in struct spi_offload_trigger_periodic causes a build failure.
- [Critical] The macro HZ_PER_GHZ is used but never defined anywhere in the kernel, causing a build failure.
- [High] Mismatch between SPI offload transfer length and IIO channel storage bits for 16-bit devices causes buffer data corruption.
- [High] Unassigned length pointer in ltc2378_read_avail API callback leaves caller variable uninitialized.
- [High] Unpredictable phase shift between two independent PWM channels risks hardware data corruption.
- [High] Forcing unsupported bits_per_word breaks single-shot reads on standard SPI controllers.
- [Medium] st->offload_trigger_config is updated in-place and not rolled back on validation failure, corrupting driver state. --
commit 7c29c089819a4620f86fae01e267747bb7a266ff
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 4 lines
drivers/iio/adc/ltc2378.c +0
-0
[ ... ]
drivers/iio/adc/ltc2378.c line 66
Quoted 10 lines
drivers/iio/adc/ltc2378.c +6
-0@@ -46,10 +58,19 @@#define LTC2378_UNIPOLAR_DIFF_CHANNEL (_real_bits) \ LTC2378_DIFF_CHANNEL(0, _real_bits, (((_real_bits) > 16) ? 32 : 16), 0) +#define LTC2378_OFFLOAD_BIPOLAR_DIFF_CHANNEL (_real_bits) \ + LTC2378_DIFF_CHANNEL(1, (_real_bits), 32, 1) + +#define LTC2378_OFFLOAD_UNIPOLAR_DIFF_CHANNEL (_real_bits) \ + LTC2378_DIFF_CHANNEL(0, (_real_bits), 32, 1) +
[Severity: High]
Does hardcoding the storagebits to 32 here mismatch with the SPI transfer length for 16-bit devices?
When ltc2378_prepare_offload_message() configures the transfer, it sets the length to spi_bpw_to_bytes(16), which is 2 bytes. Since the IIO subsystem expects 4 bytes per sample based on these channel definitions, could this cause buffer reads to be misaligned and return garbage data to userspace?
[ ... ]
Quoted 13 lines
drivers/iio/adc/ltc2378.c +9
-0@@ -254,7 +344,136 @@ 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; +return IIO_VAL_INT ; +default : +return -EINVAL ; + } +} + +static int ltc2378_read_avail(struct iio_dev *indio_dev,
drivers/iio/adc/ltc2378.c static int ltc2378_read_raw(struct iio_dev *indio_dev, · line 365
Quoted 10 lines
drivers/iio/adc/ltc2378.c +10
-0+struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, long mask) +{ + struct ltc2378_state *st = iio_priv(indio_dev); + +switch (mask) { +case IIO_CHAN_INFO_SAMP_FREQ : + *vals = st->sample_freq_range; + *type =IIO_VAL_INT ; +return IIO_AVAIL_RANGE ;
[Severity: High]
Should this callback also initialize the length pointer?
Since this returns IIO_AVAIL_RANGE successfully but doesn't assign *length, callers like iio_read_channel_info_avail() in the core might use an uninitialized stack variable for the array size. Could this lead to out-of-bounds array reads?
Quoted 4 lines
drivers/iio/adc/ltc2378.c +4
-0+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 437
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);
[Severity: Critical]
Is HZ_PER_GHZ defined anywhere in the kernel?
Looking through the tree and include/linux/units.h, this macro doesn't appear to exist. Won't this cause an unconditional build failure?
drivers/iio/adc/ltc2378.c static int ltc2378_read_raw(struct iio_dev *indio_dev, · line 442
Quoted 5 lines
drivers/iio/adc/ltc2378.c +5
-0+ min_read_offset =LTC2378_TBUSYLH_NS + st->info->tconv_ns +LTC2378_TDSDOBUSYL_NS ; + offload_offset_ns = min_read_offset; + count =100 ; + do { + config->periodic.offset_ns = offload_offset_ns;
[Severity: Critical]
Does struct spi_offload_trigger_periodic actually have an offset_ns field?
According to include/linux/spi/offload/types.h, struct spi_offload_trigger_periodic only contains the frequency_hz field. This seems like it will cause a build error.
drivers/iio/adc/ltc2378.c static int ltc2378_read_raw(struct iio_dev *indio_dev, · line 445
Quoted 3 lines
drivers/iio/adc/ltc2378.c +3
-0+ ret =spi_offload_trigger_validate (st->offload_trigger, config); +if (ret) +return ret;
[Severity: Medium]
If validation fails here, does the in-place modification of the shared config struct get rolled back?
Since config points directly to st->offload_trigger_config, returning early leaves the device state with rejected values. If the IIO buffer is later enabled, could the driver use these invalid config values to start the offload trigger?
Quoted 2 lines
drivers/iio/adc/ltc2378.c +2
-0+ offload_offset_ns +=10 ; + }while (count-- && config->periodic.offset_ns < min_read_offset);
[ ... ]
drivers/iio/adc/ltc2378.c static const struct iio_info ltc2378_iio_info = { · line 518
Quoted 11 lines
drivers/iio/adc/ltc2378.c +11
-0+static int ltc2378_offload_buffer_postenable (struct iio_dev *indio_dev) +{ +struct ltc2378_state *st =iio_priv (indio_dev); +int ret; + + ret =pwm_set_waveform_might_sleep (st->cnv_trigger, &st->cnv_wf, true); +if (ret) +return ret; + + ret =spi_offload_trigger_enable (st->offload, st->offload_trigger, + &st->offload_trigger_config);
[Severity: High]
Does starting these two clock sources sequentially result in an unpredictable phase shift?
Since st->cnv_trigger and st->offload_trigger are independent and enabled one after the other in software, CPU execution delays might cause an uncontrolled phase alignment. The LTC2378 datasheet forbids SCLK toggling during the conversion phase. Could this random phase shift cause SPI transactions to overlap with the conversion window and corrupt the sampled data?
Quoted 4 lines
drivers/iio/adc/ltc2378.c +4
-0+if (ret) + goto out_pwm_disable; + +return 0 ;
[ ... ]
Quoted 1 line
drivers/iio/adc/ltc2378.c +0
-0@@ -330,8 +653,53 @@ static int ltc2378_probe(struct spi_device *spi)
[ ... ]
drivers/iio/adc/ltc2378.c static int ltc2378_probe(struct spi_device *spi) · line 701
Quoted 6 lines
drivers/iio/adc/ltc2378.c +6
-0+/* +* Set single-read transfer bits_per_word so the SPI subsystem +* rearanges data to CPU endianness, enabling us to reuse +* offload_chan specifications for single-shot reads. +*/ + st->xfer.bits_per_word = st->info->offload_chan.scan_type.realbits;
[Severity: High]
Is it safe to force this bits_per_word on the shared transfer struct used for regular single-shot reads?
Most generic SPI host controllers only natively support standard word widths (like 8, 16, 32). If bits_per_word is set to an arbitrary resolution like 18, won't the SPI core's __spi_validate reject the transfer with -EINVAL and break sysfs single-shot reads?
Quoted 4 lines
drivers/iio/adc/ltc2378.c +1
-0+ } st->xfer.rx_buf = &st->scan.data; st->xfer.len =spi_bpw_to_bytes (indio_dev->channels[0 ].scan_type.realbits);
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=3
Re: [PATCH v5 3/4] iio: adc: ltc2378: Enable high-speed data capture
Quoted 38 lines · On 07/02, [email protected] wrote:
Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
- [Critical] Access to non-existentoffset_nsfield instruct spi_offload_trigger_periodiccauses a build failure.
- [Critical] The macroHZ_PER_GHZis used but never defined anywhere in the kernel, causing a build failure.
- [High] Mismatch between SPI offload transfer length and IIO channel storage bits for 16-bit devices causes buffer data corruption.
- [High] Unassignedlengthpointer inltc2378_read_availAPI callback leaves caller variable uninitialized.
- [High] Unpredictable phase shift between two independent PWM channels risks hardware data corruption.
- [High] Forcing unsupportedbits_per_wordbreaks single-shot reads on standard SPI controllers.
- [Medium]st->offload_trigger_configis updated in-place and not rolled back on validation failure, corrupting driver state. --commit
7c29c089819a4620f86fae01e267747bb7a266ff
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 4 lines
drivers/iio/adc/ltc2378.c +0
-0[ ... ]
drivers/iio/adc/ltc2378.c line 66
Quoted 10 lines
drivers/iio/adc/ltc2378.c +6
-0@@ -46,10 +58,19 @@#define LTC2378_UNIPOLAR_DIFF_CHANNEL (_real_bits) \ LTC2378_DIFF_CHANNEL(0, _real_bits, (((_real_bits) > 16) ? 32 : 16), 0) +#define LTC2378_OFFLOAD_BIPOLAR_DIFF_CHANNEL (_real_bits) \ + LTC2378_DIFF_CHANNEL(1, (_real_bits), 32, 1) + +#define LTC2378_OFFLOAD_UNIPOLAR_DIFF_CHANNEL (_real_bits) \ + LTC2378_DIFF_CHANNEL(0, (_real_bits), 32, 1) +[Severity: High]
Does hardcoding the storagebits to 32 here mismatch with the SPI transfer length for 16-bit devices?
Quoted 4 lines
When
ltc2378_prepare_offload_message()configures the transfer, it sets the length tospi_bpw_to_bytes(16), which is 2 bytes. Since the IIO subsystem expects 4 bytes per sample based on these channel definitions, could this cause buffer reads to be misaligned and return garbage data to userspace?
The available HDL only supports pushing 32-bit data elements to DMA buffers in CPU endianness. For 16-bit precision parts, 32-bit elements (in CPU endianness) containing the 16-bit data are pushed to DMA. For the offload use case, the IIO buffer is configured for 32 storage bits in CPU endianness so data is correctly aligned in user space (despite 2 out of the 4 bytes being always zeroed). I'll add a comment with the above explanation.
Quoted 20 lines
[ ... ]
Quoted 18 lines
drivers/iio/adc/ltc2378.c +14
-0@@ -254,7 +344,136 @@ 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; +return IIO_VAL_INT ; +default : +return -EINVAL ; + } +} + +static int ltc2378_read_avail (struct iio_dev *indio_dev, +struct iio_chan_spec const *chan, +const int **vals,int *type,int *length,long mask) +{ +struct ltc2378_state *st =iio_priv (indio_dev); +
Quoted 8 lines
drivers/iio/adc/ltc2378.c static int ltc2378_read_raw(struct iio_dev *indio_dev, · line 365
Quoted 5 lines
drivers/iio/adc/ltc2378.c +5
-0+switch (mask) { +case IIO_CHAN_INFO_SAMP_FREQ : + *vals = st->sample_freq_range; + *type =IIO_VAL_INT ; +return IIO_AVAIL_RANGE ;[Severity: High]
Should this callback also initialize the length pointer?
No.
Quoted 14 lines
Since this returns
IIO_AVAIL_RANGEsuccessfully but doesn't assign *length, callers likeiio_read_channel_info_avail()in the core might use an uninitialized stack variable for the array size. Could this lead to out-of-bounds array reads?Quoted 4 lines
drivers/iio/adc/ltc2378.c +4
-0+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) +{[ ... ]
Quoted 13 lines
drivers/iio/adc/ltc2378.c static int ltc2378_read_raw(struct iio_dev *indio_dev, · line 437
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);[Severity: Critical]
IsHZ_PER_GHZdefined anywhere in the kernel?
Quoted 4 lines
Looking through the tree and
include/linux/units.h, this macro doesn't appear to exist. Won't this cause an unconditional build failure?
Quoted 8 lines
drivers/iio/adc/ltc2378.c static int ltc2378_read_raw(struct iio_dev *indio_dev, · line 442
Quoted 5 lines
drivers/iio/adc/ltc2378.c +5
-0+ min_read_offset =LTC2378_TBUSYLH_NS + st->info->tconv_ns +LTC2378_TDSDOBUSYL_NS ; + offload_offset_ns = min_read_offset; + count =100 ; + do { + config->periodic.offset_ns = offload_offset_ns;[Severity: Critical]
Does structspi_offload_trigger_periodicactually have anoffset_nsfield?
Quoted 13 lines
According to
include/linux/spi/offload/types.h, structspi_offload_trigger_periodiconly contains thefrequency_hzfield. This seems like it will cause a build error.drivers/iio/adc/ltc2378.c static int ltc2378_read_raw(struct iio_dev *indio_dev, · line 445
Quoted 3 lines
drivers/iio/adc/ltc2378.c +3
-0+ ret =spi_offload_trigger_validate (st->offload_trigger, config); +if (ret) +return ret;[Severity: Medium]
If validation fails here, does the in-place modification of the shared config struct get rolled back?
Quoted 4 lines
Since config points directly to
st->offload_trigger_config, returning early leaves the device state with rejected values. If the IIO buffer is later enabled, could the driver use these invalid config values to start the offload trigger?
Makes no difference. The PWM configurations are recalculated and re-validated every time the buffer is enabled. There's very little to no benefit in rolling back PWM configurations.
Quoted 20 lines
Quoted 3 lines
drivers/iio/adc/ltc2378.c +2
-0+ offload_offset_ns +=10 ; + }while (count-- && config->periodic.offset_ns < min_read_offset);[ ... ]
drivers/iio/adc/ltc2378.c static const struct iio_info ltc2378_iio_info = { · line 518
Quoted 11 lines
drivers/iio/adc/ltc2378.c +11
-0+static int ltc2378_offload_buffer_postenable (struct iio_dev *indio_dev) +{ +struct ltc2378_state *st =iio_priv (indio_dev); +int ret; + + ret =pwm_set_waveform_might_sleep (st->cnv_trigger, &st->cnv_wf, true); +if (ret) +return ret; + + ret =spi_offload_trigger_enable (st->offload, st->offload_trigger, + &st->offload_trigger_config);[Severity: High]
Does starting these two clock sources sequentially result in an unpredictable phase shift?
Quoted 5 lines
Since
st->cnv_triggerandst->offload_triggerare independent and enabled one after the other in software, CPU execution delays might cause an uncontrolled phase alignment. The LTC2378 datasheet forbids SCLK toggling during the conversion phase. Could this random phase shift cause SPI transactions to overlap with the conversion window and corrupt the sampled data?
That's what the offset_ns field is for.
Quoted 19 lines
Quoted 5 lines
drivers/iio/adc/ltc2378.c +4
-0+if (ret) + goto out_pwm_disable; + +return 0 ;[ ... ]
Quoted 1 line
drivers/iio/adc/ltc2378.c +0
-0@@ -330,8 +653,53 @@ static int ltc2378_probe(struct spi_device *spi)[ ... ]
drivers/iio/adc/ltc2378.c static int ltc2378_probe(struct spi_device *spi) · line 701
Quoted 6 lines
drivers/iio/adc/ltc2378.c +6
-0+/* +* Set single-read transfer bits_per_word so the SPI subsystem +* rearanges data to CPU endianness, enabling us to reuse +* offload_chan specifications for single-shot reads. +*/ + st->xfer.bits_per_word = st->info->offload_chan.scan_type.realbits;[Severity: High]
Is it safe to force thisbits_per_wordon the shared transfer struct used for regular single-shot reads?
Quoted 4 lines
Most generic SPI host controllers only natively support standard word widths (like 8, 16, 32). If
bits_per_wordis set to an arbitrary resolution like 18, won't the SPI core's__spi_validatereject the transfer with-EINVALand break sysfs single-shot reads?
Correct, offload support assumes a controller capable of supporting fine grained number of bits_per_word.
Quoted 8 lines
Quoted 5 lines
drivers/iio/adc/ltc2378.c +1
-0+ } st->xfer.rx_buf = &st->scan.data; st->xfer.len =spi_bpw_to_bytes (indio_dev->channels[0 ].scan_type.realbits);Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=3
Jonathan Cameron
maintainerRe: [PATCH v5 3/4] iio: adc: ltc2378: Enable high-speed data capture
In reply to Marcelo SchmittQuoted 19 lines · On Thu, 2 Jul 2026 18:45:49 -0300 Marcelo Schmitt <[email protected]>…
Make use of SPI transfer offloading to speed up data capture, enabling data acquisition at faster sample rates (up to 2 MSPS).
Signed-off-by Marcelo Schmitt <[email protected]>drivers/iio/adc/ltc2378.c +2
-0@@ -12,16 +12,28 @@#include <linux/delay.h> #include <linux/err.h> #include <linux/gpio/consumer.h> +#include <linux/math64.h> #include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/regulator/consumer.h> +#include <linux/pwm.h> #include <linux/spi/spi.h>
drivers/iio/adc/ltc2378.c line 30
Quoted 10 lines
drivers/iio/adc/ltc2378.c +6
-0+#include <linux/spi/offload/consumer.h> +#include <linux/spi/offload/types.h> +#include <linux/time64.h> #include <linux/types.h> #include <linux/units.h> +#include <linux/iio/buffer.h> +#include <linux/iio/buffer-dmaengine.h> #include <linux/iio/iio.h> +#include <linux/iio/sysfs.h>
I'm probably missing something. Why this include?
Jonathan
Marcelo Schmitt
maintainerPATCH v5 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 v4 -> v5:
- Dropped error message on devm_iio_triggered_buffer_setup() fail.
drivers/iio/adc/Kconfig | 1 + drivers/iio/adc/ltc2378.c | 75 +++++++++++++++++++++++++++------------ 2 files changed, 53 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 +52 -23
225 lines not on this page · raw message
Signature · 1 line
2.53.0