Skip to contentSkip to conversation

iio: adc: ad4134: Enable greater sample rate data capture

PATCH Superseded Marcelo Schmitt 6 participants 42 messages Sep 2 – Sep 15

Subsystems (6)

v1 of 6 Superseded Latest is v6 →

lore
Share & tools
lore

Marcelo Schmitt

author maintainer
#0 lore raw

cover iio: adc: ad4134: Enable greater sample rate data capture

Extend AD4134 support to enable greater sample rate data capture. To achieve that, provide control of digital filter type selection. The default filter type on device power up only supports sample rates up to 374 kSPS. In addition to that, enable interfacing with AD4134 in SPI 4-wire mode that can support reading ADC sample data through multiple wires. Finally, use SPI offloading to speed up data transfers at up to 1.49 MSPS.

Features being added:
- Data filter type selection.
- Triggered buffer data read.
- SPI 4-wire mode.
- High speed data capture with SPI offloading.
- Device tree doc updates to reflect previously missing chip characteristics.

Minor improvements (introduced before the new features):
- Fix typo in vendor name.
- Drop import to empty name space.
- Update include list to comply with IWYU principles.
- Serialize single-read operations.
- Run shorter transfers when CRC is disabled.

Marcelo Schmitt (13):
iio: Fix typo in vendor name
iio: adc: ad4134: Drop import to empty name space
iio: adc: ad4134: Update include list to comply with IWYU principles
iio: adc: ad4134: Serialize single-read operations
iio: adc: ad4134: Run shorter transfers when CRC is disabled
iio: adc: ad4134: Add support for digital filter type selection
iio: adc: ad4134: Support buffered data read
dt-bindings: iio: adc: adi,ad4134: Document SPI connection mode
iio: adc: ad4134: Support SPI 4-wire mode
dt-bindings: iio: adc: adi,ad4134: Document PWM usage
dt-bindings: iio: adc: adi,ad4134: Add high data throughput example
iio: adc: ad4134: Support high-speed data capture
Docs: iio: Add AD4134

 .../bindings/iio/adc/adi,ad4134.yaml          |  68 ++
 Documentation/iio/ad4134.rst                  | 128 ++++
 Documentation/iio/index.rst                   |   1 +
 MAINTAINERS                                   |   1 +
 drivers/iio/adc/Kconfig                       |  20 +-
 drivers/iio/adc/ad4134.c                      | 698 +++++++++++++++++-
 drivers/iio/dac/ad3552r.c                     |   2 +-
 7 files changed, 893 insertions(+), 25 deletions(-)
 create mode 100644 Documentation/iio/ad4134.rst

base-commit: 8992f32c57607bdfaf5de2a2cd26b3b71f3a9d55
prerequisite-patch-id: a509ef662def60ff7a33b7dd949f26cd0eb1b8b7
prerequisite-patch-id: 6b5e2a61b7363b24fa9b9d2f6b20de57550415df
prerequisite-patch-id: 8dcffa92e3d7686214eda37a00a7c58d969d1bbf
prerequisite-patch-id: f84fc98c5728b8a2d401aa97507bed57e4748c7c
prerequisite-patch-id: fc9dcff6eae8019f0e0c38409cfafe020d5aaa05
prerequisite-patch-id: 578583880ef301e0901be4b23d05de5a1ccca926
prerequisite-patch-id: a2a4b770f7b76b965a2eaac95a7d8d1b6c956a7c
prerequisite-patch-id: c42fead7b0d37866757d55679ec2252bc67e9679
prerequisite-patch-id: 851fddf35c3e7cf142a0274879f7bfe354c44b48
prerequisite-patch-id: bcbffeedc3004ae7c7d38e0968248379a2cc11d3
prerequisite-patch-id: 29da6bee42ad3a8a1c1ab3cfa7196e3da8c255a5
prerequisite-patch-id: 24b9fc5c9f8f5e39454a714b6119bcc66c68c332
prerequisite-patch-id: 17ef931c5e720671a4ad3d245c530c3b225a11d2
prerequisite-patch-id: d6c8f2b172bcdf33f3e26cce3aa257cd6abde8f3
prerequisite-patch-id: 5362999f38f6c7db8c232815719d62864cdf9bb4
prerequisite-patch-id: 3c45895d15347202dcb333f4b75589defda6c8bd
prerequisite-patch-id: aa612ba587be22841cbaf1e817afc037a53bdb6e
prerequisite-patch-id: abd9264f4a8ce712fc02a6759cd984591e080714
prerequisite-patch-id: 2305923b790db41e048b4eadd2751837ee356e0f
prerequisite-patch-id: 99eba606a73a31f9cd8edf9efe43f353fa4c6dc1
prerequisite-patch-id: a6821645307265ecb3e8a9192a7ca75ff4ef4c25
prerequisite-patch-id: 3d73401e6137ec3f4b9a2c74aa8bde5ac73c7f43
prerequisite-patch-id: 980b5343a5ed0d38dc3deb50168dffd9a3aa94e5
prerequisite-patch-id: b6ad0c491dffc778949b689a82ae881bd73a7e70
prerequisite-patch-id: a180b3ed7c48d6917291db69f2c737d5f0ae54ef
prerequisite-patch-id: 206d438356ef9752c5409ef2ad6c8abcb4561bfe
prerequisite-patch-id: 0c21540845530f357bd1f0ecd5acb6933396b011
prerequisite-patch-id: 83d82a4a7da474a2be230c938cd01a8654db4b76
prerequisite-patch-id: 7a7bbfcead00fbe85dbcc9717a322dd394c115ff
prerequisite-patch-id: 56fb22d293ed8d1f00446bab19ddd3eab5927a22
prerequisite-patch-id: a54d660597db7fb3f916e8a3c9cf7efa401ae7df
prerequisite-patch-id: b9520c10d63f34769b18ac2034dbfe86e21444aa
prerequisite-patch-id: 2d3f13c29a14be6612de58b0ff45de3f25fec6a2
prerequisite-patch-id: 04fc520dd6f9ab1cf21b50d9052fe42072481407
prerequisite-patch-id: 98aa7964283264e9fb272303f020d96e9d2a6b58
prerequisite-patch-id: a5affc1602a01d0591824a7d11411774fcd381e1
prerequisite-patch-id: 9d8e457f7f9922a6b966193f207332efce7a2259
prerequisite-patch-id: e242d91086a77f3405497a0aee5ddafa971e735e
prerequisite-patch-id: 54e443d84b2f92b602b98d4a0cb902fd83c86691
prerequisite-patch-id: 36db49f322d7859248ae7a51f48f6c9a9986c86e
prerequisite-patch-id: 7dd860477d9c68f12baf74013c7c9b217086ea52
prerequisite-patch-id: aacc247928434df5d0017b6e96e6e8ccab4fd98e
prerequisite-patch-id: 60ea842bf051438047cc6d4383de237bbd7d57a1
prerequisite-patch-id: 1bdde9ce22e6b2818245ab8441fc22a203c116d0
prerequisite-patch-id: 9013dbccb132763b987e40e41d0a2141a4732144
prerequisite-patch-id: fa77c324defdf995d708ab78b46d03e4c456a046
prerequisite-patch-id: fe533cbe9cf454eef8d50aa340b21e1052458f17

Signature · 1 line
2.53.0
author maintainer
#1 lore raw

PATCH 1/13 iio: Fix typo in vendor name

Correct a typo in vendor company name: "Analog Device" -> "Analog Devices".

---
Now
find drivers/iio/ -type f | xargs grep -i "Analog Device " finds no leftover occurrence of such typo.

Also,
grep -nrIi drivers/iio/ -e "Analog Device" | wc -l and
grep -nrIi drivers/iio/ -e "Analog Devices" | wc -l both count the same number of lines.

 drivers/iio/adc/Kconfig   | 12 ++++++------
 drivers/iio/dac/ad3552r.c |  2 +-
 2 files changed, 7 insertions(+), 7 deletions(-)
drivers/iio/adc/Kconfig +6 -6
index 38e212a6f789..02f189e90c30 100644
@@ -105,7 +105,7 @@ config AD4080
 	  called ad4080.
 
 config AD4130
-	tristate "Analog Device AD4130 ADC Driver"
+	tristate "Analog Devices AD4130 ADC Driver"
 	depends on SPI
 	depends on GPIOLIB
 	select IIO_BUFFER
@@ -121,7 +121,7 @@ config AD4130
 	  called ad4130.
 
 config AD4134
-	tristate "Analog Device AD4134 ADC Driver"
+	tristate "Analog Devices AD4134 ADC Driver"
 	depends on SPI
 	select REGMAP_SPI
 	select CRC8
@@ -133,7 +133,7 @@ config AD4134
 	  called ad4134_spi.
 
 config AD4170_4
-	tristate "Analog Device AD4170-4 ADC Driver"
+	tristate "Analog Devices AD4170-4 ADC Driver"
 	depends on SPI
 	select REGMAP_SPI
 	select IIO_BUFFER
@@ -164,7 +164,7 @@ config AD4691
 	  called ad4691.
 
 config AD4695
-	tristate "Analog Device AD4695 ADC Driver"
+	tristate "Analog Devices AD4695 ADC Driver"
 	depends on SPI
 	select IIO_BUFFER
 	select IIO_BUFFER_DMAENGINE
@@ -179,7 +179,7 @@ config AD4695
 	  called ad4695.
 
 config AD4851
-	tristate "Analog Device AD4851 DAS Driver"
+	tristate "Analog Devices AD4851 DAS Driver"
 	depends on SPI
 	depends on PWM
 	select REGMAP_SPI
@@ -347,7 +347,7 @@ config AD7380
 	  called ad7380.
 
 config AD7405
-	tristate "Analog Device AD7405 ADC Driver"
+	tristate "Analog Devices AD7405 ADC Driver"
 	depends on IIO_BACKEND
 	help
 	  Say yes here to build support for Analog Devices AD7405, ADUM7701,
drivers/iio/dac/ad3552r.c +1 -1
index 16db94fef9d4..039af514adde 100644
@@ -696,6 +696,6 @@ static struct spi_driver ad3552r_driver = {
 module_spi_driver(ad3552r_driver);
 
 MODULE_AUTHOR("Mihail Chindris <[email protected]>");
-MODULE_DESCRIPTION("Analog Device AD3552R DAC");
+MODULE_DESCRIPTION("Analog Devices AD3552R DAC");
 MODULE_LICENSE("GPL v2");
 MODULE_IMPORT_NS("IIO_AD3552R");
Signature · 1 line
2.53.0
Reviewed-by on v1 1/13
#2 lore raw

Re: [PATCH v1 01/13] iio: Fix typo in vendor name

Quoted 10 lines · Marcelo Schmitt

---
Now
find drivers/iio/ -type f | xargs grep -i "Analog Device " finds no leftover occurrence of such typo.

Also,
grep -nrIi drivers/iio/ -e "Analog Device" | wc -l and
grep -nrIi drivers/iio/ -e "Analog Devices" | wc -l both count the same number of lines.

Why not git grep ...?

...

But you also want to fix possessive suffix usage

$ git grep -n 'Analog Device[^s]'

Documentation/iio/ade9000.rst:7:This driver supports Analog Device's ADE9000 and ADE9078 energy measurement Documentation/iio/adis16475.rst:7:This driver supports Analog Device's IMUs on SPI bus. Documentation/iio/adis16480.rst:7:This driver supports Analog Device's IMUs on SPI bus. Documentation/iio/adis16550.rst:7:This driver supports Analog Device's IMUs on SPI bus. Documentation/iio/adxl313.rst:7:This driver supports Analog Device's ADXL313 on SPI/I2C bus. Documentation/iio/adxl345.rst:7:This driver supports Analog Device's ADXL345/375 on SPI/I2C bus. Documentation/iio/adxl380.rst:7:This driver supports Analog Device's ADXL380/382 on SPI/I2C bus.

drivers/iio/adc/Kconfig:108:    tristate "Analog Device AD4130 ADC Driver"
drivers/iio/adc/Kconfig:124:    tristate "Analog Device AD4134 ADC Driver"
drivers/iio/adc/Kconfig:136:    tristate "Analog Device AD4170-4 ADC Driver"
drivers/iio/adc/Kconfig:167:    tristate "Analog Device AD4695 ADC Driver"
drivers/iio/adc/Kconfig:182:    tristate "Analog Device AD4851 DAS Driver"
drivers/iio/adc/Kconfig:350:    tristate "Analog Device AD7405 ADC Driver"

drivers/iio/dac/ad3552r.c:699:MODULE_DESCRIPTION("Analog Device AD3552R DAC");

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#3 lore raw

Re: [PATCH v1 01/13] iio: Fix typo in vendor name

Quoted 7 lines · Andy Shevchenko
Quoted 5 lines · Marcelo Schmitt

---
Now
find drivers/iio/ -type f | xargs grep -i "Analog Device " finds no leftover occurrence of such typo.

Quoted 8 lines
Quoted 5 lines

Also,
grep -nrIi drivers/iio/ -e "Analog Device" | wc -l and
grep -nrIi drivers/iio/ -e "Analog Devices" | wc -l both count the same number of lines.

Why not git grep ...?

Could be. I'm just more used to non-git grep.

Quoted 15 lines

...

But you also want to fix possessive suffix usage

$ git grep -n 'Analog Device[^s]'

Documentation/iio/ade9000.rst:7:This driver supports Analog Device's ADE9000 and ADE9078 energy measurement Documentation/iio/adis16475.rst:7:This driver supports Analog Device's IMUs on SPI bus. Documentation/iio/adis16480.rst:7:This driver supports Analog Device's IMUs on SPI bus. Documentation/iio/adis16550.rst:7:This driver supports Analog Device's IMUs on SPI bus. Documentation/iio/adxl313.rst:7:This driver supports Analog Device's ADXL313 on SPI/I2C bus. Documentation/iio/adxl345.rst:7:This driver supports Analog Device's ADXL345/375 on SPI/I2C bus. Documentation/iio/adxl380.rst:7:This driver supports Analog Device's ADXL380/382 on SPI/I2C bus.

Quoted 7 lines
drivers/iio/adc/Kconfig:108:    tristate "Analog Device AD4130 ADC Driver"
drivers/iio/adc/Kconfig:124:    tristate "Analog Device AD4134 ADC Driver"
drivers/iio/adc/Kconfig:136:    tristate "Analog Device AD4170-4 ADC Driver"
drivers/iio/adc/Kconfig:167:    tristate "Analog Device AD4695 ADC Driver"
drivers/iio/adc/Kconfig:182:    tristate "Analog Device AD4851 DAS Driver"
drivers/iio/adc/Kconfig:350:    tristate "Analog Device AD7405 ADC Driver"

drivers/iio/dac/ad3552r.c:699:MODULE_DESCRIPTION("Analog Device AD3552R DAC");

Ah, thanks for bringing this suggestion. Will adjust the possessive use as well.

Thanks for suggestions to other patches too. Will apply them for v2.

Thanks,
Marcelo

#4 lore raw

Re: [PATCH v1 01/13] iio: Fix typo in vendor name

Quoted 2 lines · Marcelo Schmitt
Quoted 1 line · Andy Shevchenko

On Wed, Sep 02, 2026 at 02:21:34PM -0300, Marcelo Schmitt wrote:

...

Quoted 10 lines
Quoted 10 lines
Quoted 9 lines

Now
find drivers/iio/ -type f | xargs grep -i "Analog Device " finds no leftover occurrence of such typo.

Also,
grep -nrIi drivers/iio/ -e "Analog Device" | wc -l and
grep -nrIi drivers/iio/ -e "Analog Devices" | wc -l both count the same number of lines.

Quoted 3 lines
Quoted 2 lines

Why not git grep ...?

Could be. I'm just more used to non-git grep.

The rationale here is that grep goes over filesystem (and files) while git grep goes over index which requires much less resources to waste and hence 10x faster or so). That said, I highly recommend using git grep when it's applicable.

...

Quoted 1 line

Thanks for suggestions to other patches too. Will apply them for v2.

You're welcome!

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#5 lore raw

Re: [PATCH v1 01/13] iio: Fix typo in vendor name

Quoted 3 lines · Andy Shevchenko
Quoted 2 lines · Marcelo Schmitt
Quoted 1 line · Andy Shevchenko

On Wed, Sep 02, 2026 at 02:21:34PM -0300, Marcelo Schmitt wrote:

...

Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 9 lines

Now
find drivers/iio/ -type f | xargs grep -i "Analog Device " finds no leftover occurrence of such typo.

Also,
grep -nrIi drivers/iio/ -e "Analog Device" | wc -l and
grep -nrIi drivers/iio/ -e "Analog Devices" | wc -l both count the same number of lines.

Quoted 8 lines
Quoted 3 lines
Quoted 2 lines

Why not git grep ...?

Could be. I'm just more used to non-git grep.

The rationale here is that grep goes over filesystem (and files) while git grep goes over index which requires much less resources to waste and hence 10x faster or so). That said, I highly recommend using git grep when it's applicable.

One more important thing, it skips ignored or temporary files, while grep goes over all of them.

...

Quoted 3 lines
Quoted 1 line

Thanks for suggestions to other patches too. Will apply them for v2.

You're welcome!

Signature · 2 lines
With Best Regards,
Andy Shevchenko
author maintainer
#6 lore raw

PATCH 2/13 iio: adc: ad4134: Drop import to empty name space

In reply to Marcelo Schmitt

Drop unused name space that somehow remained being included by the device driver.

---
 drivers/iio/adc/ad4134.c | 1 -
 1 file changed, 1 deletion(-)
drivers/iio/adc/ad4134.c +0 -1
index 0490218bb0e9..70f80bf1825f 100644
@@ -496,4 +496,3 @@ module_spi_driver(ad4134_driver);
 MODULE_AUTHOR("Marcelo Schmitt <[email protected]>");
 MODULE_DESCRIPTION("Analog Devices AD4134 SPI driver");
 MODULE_LICENSE("GPL");
-MODULE_IMPORT_NS("IIO_AD4134");
Signature · 1 line
2.53.0
author maintainer
#7 lore raw

PATCH 3/13 iio: adc: ad4134: Update include list to comply with IWYU principles

In reply to Marcelo Schmitt

Add includes that were missing (according to include-what-you-use tool) to comply with include what is used principles. Namely, add bits.h for BIT and GENMASK, and time64.h for USEC_PER_SEC.

Remove time.h which is covered by time64.h and iio/types.h which is covered by iio/iio.h.

While updating the list, organize it to follow current IIO include list convention.

---
 drivers/iio/adc/ad4134.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/iio/adc/ad4134.c +4 -3
index 70f80bf1825f..7a3b05aacc74 100644
@@ -7,6 +7,7 @@
 #include <linux/array_size.h>
 #include <linux/bitfield.h>
 #include <linux/bitops.h>
+#include <linux/bits.h>
 #include <linux/clk.h>
 #include <linux/crc8.h>
 #include <linux/delay.h>
@@ -14,18 +15,18 @@
 #include <linux/err.h>
 #include <linux/export.h>
 #include <linux/gpio/consumer.h>
-#include <linux/iio/iio.h>
-#include <linux/iio/types.h>
 #include <linux/module.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/reset.h>
 #include <linux/spi/spi.h>
-#include <linux/time.h>
+#include <linux/time64.h>
 #include <linux/types.h>
 #include <linux/unaligned.h>
 #include <linux/units.h>
 
+#include <linux/iio/iio.h>
+
 #define AD4134_RESET_TIME_US			(10 * USEC_PER_SEC)
 
 #define AD4134_REG_READ_MASK			BIT(7)
Signature · 1 line
2.53.0
#8 lore raw

Re: [PATCH v1 03/13] iio: adc: ad4134: Update include list to comply with IWYU principles

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

Pre-existing issues:
- [High] tx_buf and rx_buf in ad4134_state share the same cacheline, leading to potential data corruption during concurrent DMA mappings.
- [High] The 24-bit ADC raw data is read as an unsigned integer but never sign-extended to 32 bits, causing negative voltages to be reported as large positive values. --

commit 7ad0a307d46e16f77ecfa435dfba2e8a4ef0334d
Author: Marcelo Schmitt <[email protected]>

iio: adc: ad4134: Update include list to comply with IWYU principles

This commit updates the AD4134 driver's include list to comply with include-what-you-use principles. It adds necessary headers like bits.h and time64.h, and removes redundant ones.

drivers/iio/adc/ad4134.c

Quoted 4 lines
drivers/iio/adc/ad4134.c +0 -0
index 70f80bf1825f8..7a3b05aacc744 100644

[ ... ]

drivers/iio/adc/ad4134.c:ad4134_state()

Quoted 7 lines
	/*
	 * DMA (thus cache coherency maintenance) requires the transfer buffers
	 * to live in their own cache lines.
	 */
	u8 rx_buf[AD4134_SPI_MAX_XFER_LEN] __aligned(IIO_DMA_MINALIGN);
	u8 tx_buf[AD4134_SPI_MAX_XFER_LEN];
};

[Severity: High]
This isn't a bug introduced by this patch, but does tx_buf lack the necessary IIO_DMA_MINALIGN attribute here in ad4134_state?

Since rx_buf is aligned to a cacheline boundary but only takes 3 bytes (AD4134_SPI_MAX_XFER_LEN), tx_buf appears to be placed at offset 3 within the exact same cacheline.

During SPI transfers (such as in ad4134_register_read), the SPI core executes dma_map_single() for both tx_buf and rx_buf independently on the same transfer. Can performing concurrent DMA cache maintenance on the same cacheline (flushing tx_buf and invalidating rx_buf) cause data corruption on non-coherent systems?

While later patches in this series move the alignment attribute to the preceding scan buffer, it seems rx_buf and tx_buf still continue to share a cacheline with each other in the final state.

drivers/iio/adc/ad4134.c:ad4134_data_read()

Quoted 11 lines
		/*
		 * AD4134 has a built-in feature that flags when data transfers
		 * don't run enough clock cycles to read the entire data frame.
		 * Clock out data from all channels to avoid that.
		 */
		if (i == AD4134_VREG_CH(reg))
			*val = get_unaligned_be24(st->rx_buf);
	}

	return 0;
}

[Severity: High]
This is a pre-existing issue, but does this code fail to properly sign-extend the 24-bit raw ADC data in ad4134_data_read()?

The ADC channels are defined with IIO_SCAN_FORMAT_SIGNED_INT, meaning the hardware outputs 24-bit signed two's complement data. However, reading the 3 bytes with get_unaligned_be24() returns an unsigned 24-bit value.

Because this value is not sign-extended (e.g. using sign_extend32), could negative ADC readings (like 0xFFFFFF) be incorrectly reported to userspace as large positive integers (16777215) instead of negative values?

It appears this issue also remains unfixed in the final state of this series.

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=3
Reviewed-by on v1 3/13
#9 lore raw

Re: [PATCH v1 03/13] iio: adc: ad4134: Update include list to comply with IWYU principles

In reply to Marcelo Schmitt
Quoted 9 lines · Marcelo Schmitt

Add includes that were missing (according to include-what-you-use tool) to comply with include what is used principles. Namely, add bits.h for BIT and GENMASK, and time64.h for USEC_PER_SEC.

Remove time.h which is covered by time64.h and iio/types.h which is covered by iio/iio.h.

While updating the list, organize it to follow current IIO include list convention.

...

drivers/iio/adc/ad4134.c line 10

Quoted 5 lines
drivers/iio/adc/ad4134.c +1 -0
@@ -7,6 +7,7 @@
 #include <linux/array_size.h>
 #include <linux/bitfield.h>
 #include <linux/bitops.h>
+#include <linux/bits.h>

No need, bitops.h implies it.

...

With that being addressed

Signature · 2 lines
With Best Regards,
Andy Shevchenko
author maintainer
#10 lore raw

PATCH 4/13 iio: adc: ad4134: Serialize single-read operations

In reply to Marcelo Schmitt

Protect single-sample read operations from going wrong if two or more of them run concurrently. Serialize the data read operation so to avoid single-sample read requests disrupting each other.

---
 drivers/iio/adc/ad4134.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)
drivers/iio/adc/ad4134.c +12 -0
index 7a3b05aacc74..3460ecf4cafd 100644
@@ -8,6 +8,7 @@
 #include <linux/bitfield.h>
 #include <linux/bitops.h>
 #include <linux/bits.h>
+#include <linux/cleanup.h>
 #include <linux/clk.h>
 #include <linux/crc8.h>
 #include <linux/delay.h>
@@ -16,6 +17,7 @@
 #include <linux/export.h>
 #include <linux/gpio/consumer.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/reset.h>
@@ -100,6 +102,11 @@ struct ad4134_state {
 	unsigned long sys_clk_hz;
 	struct gpio_desc *odr_gpio;
 	int refin_mv;
+	/*
+	 * Synchronize access to members the of driver state, and ensure
+	 * atomicity of consecutive register access operations.
+	 */
+	struct mutex lock;
 	/*
 	 * DMA (thus cache coherency maintenance) requires the transfer buffers
 	 * to live in their own cache lines.
@@ -257,6 +264,7 @@ static int ad4134_read_raw(struct iio_dev *indio_dev,
 
 	switch (info) {
 	case IIO_CHAN_INFO_RAW:
+		guard(mutex)(&st->lock);
 		gpiod_set_value_cansleep(st->odr_gpio, 1);
 		/*
 		 * For slave mode gated DCLK (data sheet page 11), the minimum
@@ -443,6 +451,10 @@ static int ad4134_probe(struct spi_device *spi)
 
 	crc8_populate_msb(ad4134_spi_crc_table, AD4134_SPI_CRC_POLYNOM);
 
+	ret = devm_mutex_init(dev, &st->lock);
+	if (ret)
+		return ret;
+
 	st->regmap = devm_regmap_init(dev, NULL, st, &ad4134_regmap_config);
 	if (IS_ERR(st->regmap))
 		return dev_err_probe(dev, PTR_ERR(st->regmap),
Signature · 1 line
2.53.0
Reviewed-by on v1 4/13
#11 lore raw

Re: [PATCH v1 04/13] iio: adc: ad4134: Serialize single-read operations

Quoted 3 lines · Marcelo Schmitt

Protect single-sample read operations from going wrong if two or more of them run concurrently. Serialize the data read operation so to avoid single-sample read requests disrupting each other.

...

drivers/iio/adc/ad4134.c static int ad4134_read_raw(struct iio_dev *indio_dev, · line 267

Quoted 2 lines
drivers/iio/adc/ad4134.c +1 -0
 	case IIO_CHAN_INFO_RAW:
+		guard(mutex)(&st->lock);

Always delimit guard()() with a blank line.

Quoted 1 line

gpiod_set_value_cansleep(st->odr_gpio, 1);

...

With blank line added

Signature · 2 lines
With Best Regards,
Andy Shevchenko
maintainer
#12 lore raw

Re: [PATCH v1 04/13] iio: adc: ad4134: Serialize single-read operations

Quoted 9 lines · Andy Shevchenko
Quoted 3 lines · Marcelo Schmitt

Protect single-sample read operations from going wrong if two or more of them run concurrently. Serialize the data read operation so to avoid single-sample read requests disrupting each other.

...

Quoted 1 line

case IIO_CHAN_INFO_RAW:

Define the scope.

	case IIO_CHAN_INFO_RAW: {

Scope has a funny definition in switch statements and that can lead
to 'entertaining' results. Some compilers will also moan about this.

Quoted 11 lines

drivers/iio/adc/ad4134.c static int ad4134_read_raw(struct iio_dev *indio_dev, · line 267

Quoted 1 line
drivers/iio/adc/ad4134.c +1 -0
+		guard(mutex)(&st->lock);

Always delimit guard()() with a blank line.

Quoted 1 line

gpiod_set_value_cansleep(st->odr_gpio, 1);

...

With blank line added

author maintainer
#13 lore raw

PATCH 5/13 iio: adc: ad4134: Run shorter transfers when CRC is disabled

In reply to Marcelo Schmitt

When AD4134 has its SPI CRC feature enabled, one extra byte (the CRC code) is sent through SPI for both ends to verify the integrity of data transfers. Though, when CRC is not enabled, SPI transfers can be shorter.

---
 drivers/iio/adc/ad4134.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)
drivers/iio/adc/ad4134.c +6 -4
index 3460ecf4cafd..7da6734d4609 100644
@@ -102,6 +102,7 @@ struct ad4134_state {
 	unsigned long sys_clk_hz;
 	struct gpio_desc *odr_gpio;
 	int refin_mv;
+	bool crc_en;
 	/*
 	 * Synchronize access to members the of driver state, and ensure
 	 * atomicity of consecutive register access operations.
@@ -160,7 +161,7 @@ static int ad4134_reg_write(void *context, unsigned int reg, unsigned int val)
 	struct spi_transfer xfer = {
 		.tx_buf = st->tx_buf,
 		.rx_buf = st->rx_buf,
-		.len = AD4134_SPI_MAX_XFER_LEN,
+		.len = st->crc_en ? AD4134_SPI_MAX_XFER_LEN : 2,
 	};
 	int ret;
 
@@ -170,7 +171,7 @@ static int ad4134_reg_write(void *context, unsigned int reg, unsigned int val)
 	if (ret)
 		return ret;
 
-	if (st->rx_buf[2] != st->tx_buf[2])
+	if (st->crc_en && st->rx_buf[2] != st->tx_buf[2])
 		dev_dbg(&st->spi->dev, "reg write CRC check failed\n");
 
 	return 0;
@@ -216,7 +217,7 @@ static int ad4134_register_read(struct ad4134_state *st, unsigned int reg,
 	struct spi_transfer xfer = {
 		.tx_buf = st->tx_buf,
 		.rx_buf = st->rx_buf,
-		.len = AD4134_SPI_MAX_XFER_LEN,
+		.len = st->crc_en ? AD4134_SPI_MAX_XFER_LEN : 2,
 	};
 	unsigned int inst;
 	int ret;
@@ -231,7 +232,7 @@ static int ad4134_register_read(struct ad4134_state *st, unsigned int reg,
 	*val = st->rx_buf[1];
 
 	/* Check CRC */
-	if (st->rx_buf[2] != st->tx_buf[2])
+	if (st->crc_en && st->rx_buf[2] != st->tx_buf[2])
 		dev_dbg(&st->spi->dev, "reg read CRC check failed\n");
 
 	return 0;
@@ -310,6 +311,7 @@ static int ad4134_min_io_mode_setup(struct ad4134_state *st)
 	struct device *dev = &st->spi->dev;
 	int ret;
 
+	st->crc_en = true; /* In minimum I/O mode CRC cannot be disabled */
 	st->odr_gpio = devm_gpiod_get(dev, "odr", GPIOD_OUT_LOW);
 	if (IS_ERR(st->odr_gpio))
 		return dev_err_probe(dev, PTR_ERR(st->odr_gpio),
Signature · 1 line
2.53.0
#14 lore raw

Re: [PATCH v1 05/13] iio: adc: ad4134: Run shorter transfers when CRC is disabled

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

Pre-existing issues:
- [High] The TX and RX SPI buffers (tx_buf and rx_buf) share the same cacheline, violating the DMA API constraints for concurrent bidirectional mapping and causing potential memory corruption.
- [Medium] Incorrect SPI CRC verification logic compares the received response CRC against the transmitted command CRC, causing spurious validation failures and rendering the CRC check useless. --

commit 6e10b7a255a6c4b304554d7ef28e9e98a2139736
Author: Marcelo Schmitt <[email protected]>

iio: adc: ad4134: Run shorter transfers when CRC is disabled

When AD4134 has its SPI CRC feature enabled, one extra byte (the CRC code) is sent through SPI for both ends to verify the integrity of data transfers. Though, when CRC is not enabled, SPI transfers can be shorter.

drivers/iio/adc/ad4134.c struct ad4134_state { · line 105

Quoted 9 lines
drivers/iio/adc/ad4134.c +1 -0
index 3460ecf4cafd4..7da6734d4609f 100644
@@ -102,6 +102,7 @@ struct ad4134_state {
 	unsigned long sys_clk_hz;
 	struct gpio_desc *odr_gpio;
 	int refin_mv;
+	bool crc_en;

[Severity: High]
This is a pre-existing issue, but does struct ad4134_state force tx_buf and rx_buf to share a cacheline?

Looking at the struct definition, rx_buf is annotated with __aligned(IIO_DMA_MINALIGN), which aligns its start address:

	u8 rx_buf[AD4134_SPI_MAX_XFER_LEN] __aligned(IIO_DMA_MINALIGN);
	u8 tx_buf[AD4134_SPI_MAX_XFER_LEN];

Because rx_buf is only 3 bytes long and tx_buf immediately follows it without its own alignment, tx_buf resides in the exact same cacheline.

When both buffers are passed simultaneously to spi_sync_transfer() during ad4134_reg_write() or ad4134_register_read(), they are mapped concurrently.

Will performing a simultaneous flush for tx_buf and invalidate for rx_buf on the same cacheline violate DMA API rules and cause memory corruption on non-coherent architectures?

Quoted 3 lines
drivers/iio/adc/ad4134.c +0 -0
 	/*
 	 * Synchronize access to members the of driver state, and ensure
 	 * atomicity of consecutive register access operations.

[ ... ]

drivers/iio/adc/ad4134.c static int ad4134_reg_write(void *context, unsigned int reg, unsigned int val) · line 174

Quoted 6 lines
drivers/iio/adc/ad4134.c +1 -1
@@ -170,7 +171,7 @@ static int ad4134_reg_write(void *context, unsigned int reg, unsigned int val)
 	if (ret)
 		return ret;
 
-	if (st->rx_buf[2] != st->tx_buf[2])
+	if (st->crc_en && st->rx_buf[2] != st->tx_buf[2])

[Severity: Medium]
This isn't a bug introduced by this patch, but is the CRC validation logic comparing the correct values?

In ad4134_reg_write(), the outgoing command CRC is calculated over the instruction and stored in st->tx_buf[2]. The incoming response CRC computed by the device is placed in st->rx_buf[2].

Because the transmitted data differs from the received data, won't comparing the response CRC directly against the command CRC result in constant mismatch failures?

Quoted 3 lines
drivers/iio/adc/ad4134.c +0 -0
 		dev_dbg(&st->spi->dev, "reg write CRC check failed\n");
 
 	return 0;

[ ... ]

drivers/iio/adc/ad4134.c static int ad4134_register_read(struct ad4134_state *st, unsigned int reg, · line 235

Quoted 6 lines
drivers/iio/adc/ad4134.c +1 -1
@@ -231,7 +232,7 @@ static int ad4134_register_read(struct ad4134_state *st, unsigned int reg,
 	*val = st->rx_buf[1];
 
 	/* Check CRC */
-	if (st->rx_buf[2] != st->tx_buf[2])
+	if (st->crc_en && st->rx_buf[2] != st->tx_buf[2])

[Severity: Medium]
This is a pre-existing issue, but does this comparison render the CRC check useless for register reads?

Similar to the write path above, st->tx_buf[2] holds the CRC for the outgoing command (including a dummy data byte), while st->rx_buf[2] holds the device's CRC over the read response (which includes the actual register value).

Since the response data is mathematically unrelated to the outgoing command, will this always produce false-positive CRC check failures rather than actually validating incoming data integrity?

Quoted 3 lines
drivers/iio/adc/ad4134.c +0 -0
 		dev_dbg(&st->spi->dev, "reg read CRC check failed\n");
 
 	return 0;
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=5
author maintainer
#15 lore raw

PATCH 6/13 iio: adc: ad4134: Add support for digital filter type selection

In reply to Marcelo Schmitt

AD4134 supports four types of programmable digital filters that allow users to choose between different output data rates and input bandwidths. Enable basic digital filter configuration by providing a way to select which filter type is activated for each channel.

---
 drivers/iio/adc/ad4134.c | 80 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 80 insertions(+)
drivers/iio/adc/ad4134.c +80 -0
index 7da6734d4609..a1474316e330 100644
@@ -64,6 +64,9 @@
 #define AD4134_PW_DOWN_CTRL_REG			0x13
 #define AD4134_DEVICE_STATUS_REG		0x15
 #define AD4134_ODR_VAL_INT_LSB_REG		0x16
+#define AD4134_CHAN_DIG_FILTER_SEL_REG		0x1E
+#define AD4134_CHAN_DIG_FILTER_SEL_CH_MASK(ch)	(GENMASK(1, 0) << 2 * (ch))
+
 #define AD4134_CH3_OFFSET_MSB_REG		0x3E
 #define AD4134_AIN_OR_ERROR_REG			0x48
 
@@ -81,12 +84,48 @@
 #define AD4134_SPI_CRC_INIT_VALUE		0xA5
 static unsigned char ad4134_spi_crc_table[CRC8_TABLE_SIZE];
 
+enum ad4134_filter_type {
+	AD4134_WIDEBAND,
+	AD4134_SINC6,
+	AD4134_SINC3,
+	AD4134_SINC3_REJ60,
+};
+
+static const char * const ad4134_filt_names[] = {
+	[AD4134_WIDEBAND] = "wideband",
+	[AD4134_SINC6] = "sinc6",
+	[AD4134_SINC3] = "sinc3",
+	[AD4134_SINC3_REJ60] = "sinc3+rej60",
+};
+
+static int ad4134_get_filter_type(struct iio_dev *indio_dev,
+				  struct iio_chan_spec const *chan);
+
+static int ad4134_set_filter_type(struct iio_dev *indio_dev,
+				  struct iio_chan_spec const *chan,
+				  unsigned int val);
+
+static const struct iio_enum ad4134_filter_type_enum = {
+	.items = ad4134_filt_names,
+	.num_items = ARRAY_SIZE(ad4134_filt_names),
+	.get = ad4134_get_filter_type,
+	.set = ad4134_set_filter_type,
+};
+
+static const struct iio_chan_spec_ext_info ad4134_filter_type_ext_info[] = {
+	IIO_ENUM("filter_type", IIO_SEPARATE, &ad4134_filter_type_enum),
+	IIO_ENUM_AVAILABLE("filter_type", IIO_SEPARATE,
+			   &ad4134_filter_type_enum),
+	{ }
+};
+
 #define AD4134_CHANNEL(_index) {						\
 	.type = IIO_VOLTAGE,							\
 	.indexed = 1,								\
 	.channel = (_index),							\
 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),				\
 	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),			\
+	.ext_info = ad4134_filter_type_ext_info,				\
 }
 
 static const struct iio_chan_spec ad4134_chan_set[] = {
@@ -116,6 +155,47 @@ struct ad4134_state {
 	u8 tx_buf[AD4134_SPI_MAX_XFER_LEN];
 };
 
+static int ad4134_set_filter_type(struct iio_dev *indio_dev,
+				  struct iio_chan_spec const *chan,
+				  unsigned int val)
+{
+	struct ad4134_state *st = iio_priv(indio_dev);
+	unsigned int mask, reg_val;
+
+	IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim);
+	if (IIO_DEV_ACQUIRE_FAILED(claim))
+		return -EBUSY;
+
+	guard(mutex)(&st->lock);
+
+	mask = AD4134_CHAN_DIG_FILTER_SEL_CH_MASK(chan->channel);
+	reg_val = field_prep(mask, val);
+	return regmap_update_bits(st->regmap, AD4134_CHAN_DIG_FILTER_SEL_REG,
+				  mask, reg_val);
+}
+
+static int ad4134_get_filter_type(struct iio_dev *indio_dev,
+				  struct iio_chan_spec const *chan)
+{
+	struct ad4134_state *st = iio_priv(indio_dev);
+	enum ad4134_filter_type f_type;
+	unsigned int mask, reg_val;
+	int ret;
+
+	IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim);
+	if (IIO_DEV_ACQUIRE_FAILED(claim))
+		return -EBUSY;
+
+	ret = regmap_read(st->regmap, AD4134_CHAN_DIG_FILTER_SEL_REG, &reg_val);
+	if (ret)
+		return ret;
+
+	mask = AD4134_CHAN_DIG_FILTER_SEL_CH_MASK(chan->channel);
+	f_type = field_get(mask, reg_val);
+
+	return f_type;
+}
+
 static const struct regmap_range ad4134_regmap_rd_range[] = {
 	regmap_reg_range(AD4134_IFACE_CONFIG_A_REG, AD4134_SILICON_REV_REG),
 	regmap_reg_range(AD4134_SCRATCH_PAD_REG, AD4134_PW_DOWN_CTRL_REG),
Signature · 1 line
2.53.0
#16 lore raw

Re: [PATCH v1 06/13] iio: adc: ad4134: Add support for digital filter type selection

Quoted 4 lines · Marcelo Schmitt

AD4134 supports four types of programmable digital filters that allow users to choose between different output data rates and input bandwidths. Enable basic digital filter configuration by providing a way to select which filter type is activated for each channel.

...

drivers/iio/adc/ad4134.c line 118

Quoted 4 lines
drivers/iio/adc/ad4134.c +4 -0
+static const struct iio_chan_spec_ext_info ad4134_filter_type_ext_info[] = {
+	IIO_ENUM("filter_type", IIO_SEPARATE, &ad4134_filter_type_enum),
+	IIO_ENUM_AVAILABLE("filter_type", IIO_SEPARATE,
+			   &ad4134_filter_type_enum),

Make it a single line (it's only 82 characters).

Quoted 2 lines
drivers/iio/adc/ad4134.c +2 -0
+	{ }
+};

...

drivers/iio/adc/ad4134.c struct ad4134_state { · line 178

Quoted 2 lines
drivers/iio/adc/ad4134.c +2 -0
+static int ad4134_get_filter_type(struct iio_dev *indio_dev,
+				  struct iio_chan_spec const *chan)

int

drivers/iio/adc/ad4134.c struct ad4134_state { · line 181

Quoted 3 lines
drivers/iio/adc/ad4134.c +3 -0
+{
+	struct ad4134_state *st = iio_priv(indio_dev);
+	enum ad4134_filter_type f_type;

enum

Quoted 6 lines
drivers/iio/adc/ad4134.c +6 -0
+	unsigned int mask, reg_val;
+	int ret;
+
+	IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim);
+	if (IIO_DEV_ACQUIRE_FAILED(claim))
+		return -EBUSY;

drivers/iio/adc/ad4134.c struct ad4134_state { · line 196

Quoted 10 lines
drivers/iio/adc/ad4134.c +9 -0
+
+	ret = regmap_read(st->regmap, AD4134_CHAN_DIG_FILTER_SEL_REG, &reg_val);
+	if (ret)
+		return ret;
+
+	mask = AD4134_CHAN_DIG_FILTER_SEL_CH_MASK(chan->channel);
 
+	f_type = field_get(mask, reg_val);
+
+	return f_type;

field_get() macro...

I think you can get rid of temporary variable if it's not used afterwards.

Quoted 1 line

+}

Signature · 2 lines
With Best Regards,
Andy Shevchenko
author maintainer
#17 lore raw

PATCH 7/13 iio: adc: ad4134: Support buffered data read

In reply to Marcelo Schmitt

Enable users to run buffered data captures triggered by IIO trigger device. Add an IIO timestamp channel so each data scan is provided with measurement time information. Require single-read operations to be in IIO device direct access mode to prevent buffered and single-shot data captures to disrupt each other.

---
 drivers/iio/adc/Kconfig  |  2 ++
 drivers/iio/adc/ad4134.c | 59 ++++++++++++++++++++++++++++++++++++++--
 2 files changed, 59 insertions(+), 2 deletions(-)
drivers/iio/adc/Kconfig +2 -0
index 02f189e90c30..584251a3f45c 100644
@@ -125,6 +125,8 @@ config AD4134
 	depends on SPI
 	select REGMAP_SPI
 	select CRC8
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
 	help
 	  Say yes here to build support for Analog Devices AD4134 SPI analog to
 	  digital converters (ADC).
drivers/iio/adc/ad4134.c +57 -2

108 lines not on this page · raw message

Signature · 1 line
2.53.0
#18 lore raw

Re: [PATCH v1 07/13] iio: adc: ad4134: Support buffered data read

Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider: - [High] The trigger handler loops up to masklength instead of the physical channel count, causing an…

Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [High] The trigger handler loops up to masklength instead of the physical channel count, causing an out-of-bounds array write and issuing an invalid SPI read for the software timestamp channel.
- [High] The scan buffer is undersized for captures with a timestamp, causing iio_push_to_buffers_with_ts() to always fail with -ENOSPC.
- [High] Adding the timestamp channel breaks single-shot reads by causing ad4134_data_read() to execute 5 SPI transfers instead of 4.
- [High] Removing DMA alignment from rx_buf and tx_buf causes them to share a cacheline with st->scan, leading to potential DMA data corruption.
- [Low] Buffer compaction logic uses memcpy with identically overlapping memory regions, triggering Undefined Behavior.
--

commit 923506d627d1a5bd978cd92880886f1fdb5f8bfd

Author: Marcelo Schmitt <[email protected]>
Date:   Wed Sep 2 17:23:42 2026 +0000

iio: adc: ad4134: Support buffered data read

This commit adds buffered data capture support for the AD4134, triggered by an IIO trigger device, and introduces a software timestamp channel. It also enforces direct access mode for single-read operations to prevent interference with buffered reads.

Quoted 4 lines
drivers/iio/adc/ad4134.c +0 -0
index a1474316e330d..0751b89dec8f3 100644

[ ... ]

drivers/iio/adc/ad4134.c static const struct iio_chan_spec ad4134_chan_set[] = { · line 148

Quoted 6 lines
drivers/iio/adc/ad4134.c +1 -0
@@ -133,6 +144,7 @@ static const struct iio_chan_spec ad4134_chan_set[] = {
 	AD4134_CHANNEL(1),
 	AD4134_CHANNEL(2),
 	AD4134_CHANNEL(3),
+	IIO_CHAN_SOFT_TIMESTAMP(4),
 };

[Severity: High]
Will adding this timestamp channel break single-shot reads?

Looking at ad4134_data_read(), the loop iterating over this set uses ARRAY_SIZE(ad4134_chan_set):

    for (i = 0; i < ARRAY_SIZE(ad4134_chan_set); i++) {
        ret = spi_write_then_read(...)

Since the array size is now 5, this will execute 5 times instead of the 4 times expected by the hardware. Could this clock out invalid data and disrupt the ADC's data framing state machine?

drivers/iio/adc/ad4134.c struct ad4134_state { · line 169

Quoted 10 lines
drivers/iio/adc/ad4134.c +2 -1
 struct ad4134_state {
@@ -151,7 +163,8 @@ struct ad4134_state {
 	 * DMA (thus cache coherency maintenance) requires the transfer buffers
 	 * to live in their own cache lines.
 	 */
-	u8 rx_buf[AD4134_SPI_MAX_XFER_LEN] __aligned(IIO_DMA_MINALIGN);
+	u32 scan[AD4134_NUM_CHANNELS] __aligned(IIO_DMA_MINALIGN);
+	u8 rx_buf[AD4134_SPI_MAX_XFER_LEN];
 	u8 tx_buf[AD4134_SPI_MAX_XFER_LEN];
 };

[Severity: High]
Does the removal of the __aligned(IIO_DMA_MINALIGN) attribute from rx_buf and tx_buf risk silent DMA data corruption?

Because scan is only 16 bytes (4 channels * 4 bytes), rx_buf and tx_buf could now share the same cacheline. A concurrent debugfs/sysfs register read/write could cause cacheline invalidation during a DMA unmap, resulting in lost CPU writes to the scan buffer during a triggered capture.

Also, is the scan buffer large enough to hold the timestamp? The scan buffer allocates 16 bytes, but the naturally-aligned 64-bit IIO timestamp appended by IIO will require an additional 8 bytes of space.

[ ... ]

Quoted 9 lines
drivers/iio/adc/ad4134.c +5 -0
@@ -336,6 +349,36 @@ static const struct regmap_config ad4134_regmap_config = {
 	.max_register = AD4134_CH_VREG(ARRAY_SIZE(ad4134_chan_set)),
 };
 
+static irqreturn_t ad4134_trigger_handler(int irq, void *p)
+{
+	struct iio_poll_func *pf = p;
+	struct iio_dev *indio_dev = pf->indio_dev;
+	struct ad4134_state *st = iio_priv(indio_dev);

drivers/iio/adc/ad4134.c static const struct regmap_config ad4134_regmap_config = { · line 366

Quoted 10 lines
drivers/iio/adc/ad4134.c +10 -0
+	unsigned int i = 0;
+	int ret;
+
+	gpiod_set_value_cansleep(st->odr_gpio, 1);
+	fsleep(1);
+	gpiod_set_value_cansleep(st->odr_gpio, 0);
+
+	for (unsigned int ch = 0; ch < iio_get_masklength(indio_dev); ch++) {
+		ret = spi_write_then_read(st->spi, NULL, 0, &st->scan[ch],
+					  BITS_TO_BYTES(AD4134_CHAN_PRECISION_BITS));

[Severity: High]
When the software timestamp channel is enabled, does iio_get_masklength() evaluate to 5?

If so, this loop will exceed the hardware channel count (4) and write out of bounds to st->scan[4]. This could directly corrupt the adjacent rx_buf field and issue an invalid SPI read to the device.

drivers/iio/adc/ad4134.c static const struct regmap_config ad4134_regmap_config = { · line 371

Quoted 5 lines
drivers/iio/adc/ad4134.c +5 -0
+		if (ret)
+			goto err_out;
+
+		if (test_bit(ch, indio_dev->active_scan_mask))
+			memcpy(&st->scan[i++], &st->scan[ch], sizeof(st->scan[ch]));

[Severity: Low]
Is it safe to use memcpy() here when the source and destination overlap?

When ch == i, the memory regions overlap identically. Since memcpy() restricts overlapping pointers, this can trigger undefined behavior.

drivers/iio/adc/ad4134.c static const struct regmap_config ad4134_regmap_config = { · line 375

Quoted 4 lines
drivers/iio/adc/ad4134.c +4 -0
+	}
+
+	iio_push_to_buffers_with_ts(indio_dev, &st->scan, sizeof(st->scan),
+				    pf->timestamp);

[Severity: High]
Does this fail with -ENOSPC when the timestamp channel is enabled?

The length passed here is sizeof(st->scan), which is 16 bytes. The IIO core requires 24 bytes (16 bytes data + 8 bytes timestamp) for pushing captures with a timestamp, which could cause every sample to be rejected and dropped.

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=7
author maintainer
#19 lore raw

PATCH 8/13 dt-bindings: iio: adc: adi,ad4134: Document SPI connection mode

In reply to Marcelo Schmitt

Document how AD4134 chips are connected to the host SPI controller according to different wiring configurations.

---
 .../bindings/iio/adc/adi,ad4134.yaml          | 22 +++++++++++++++++++
 1 file changed, 22 insertions(+)
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +22 -0
index ea6d7e026419..d843c02a394a 100644
@@ -131,6 +131,28 @@ properties:
     enum: [ free-running, gated ]
     default: gated
 
+  adi,spi-mode:
+    $ref: /schemas/types.yaml#/definitions/string
+    enum: [ no-cs, 4-wire, one-channel-chain, two-channel-chain ]
+    description: |
+      This property indicates the SPI wiring configuration.
+
+      When this property is omitted, it is assumed that the device is using
+      'no-cs' wiring. When this property is present, it indicates that the
+      device is using one of the following wiring configurations:
+
+      * no-cs: The datasheet calls this "minimum I/O mode". In this mode, the CS
+        line is not used (tied to GND).
+      * 4-wire: Specifies a conventional SPI wiring configuration.
+      * one-channel-chain: In this mode, the DOUT0 line of one chip is connected
+        to DOUT2 of the next chip upstream in the chain. Only the data interface
+        of the upmost device in the stream is in direct connection with the
+        digital host.
+      * two-channel-chain: In this mode, the DOUT0 and DOUT1 lines of one chip
+        are respectively connected to DOUT2 and DOUT3 of the next chip upstream
+        in the chain. Only the data interface of the upmost device in the stream
+        is in direct connection with the digital host.
+
 required:
   - compatible
   - reg
Signature · 1 line
2.53.0
#20 lore raw

Re: [PATCH v1 08/13] dt-bindings: iio: adc: adi,ad4134: Document SPI connection mode

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider: - [Critical] Unconditional buffer overflow in `ad4134_trigger_handler()` and silent data loss when the…

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [Critical] Unconditional buffer overflow in ad4134_trigger_handler() and silent data loss when the timestamp channel is enabled.
- [High] The ad4134 driver ignores unsupported adi,spi-mode values and silently falls back to no-cs mode without throwing an error.
- [Medium] Adding daisy-chain modes without explicitly allowing the '#daisy-chained-devices' property.
- [Low] The adi,spi-mode property describes a default fallback in text but lacks the YAML default keyword in the schema. --

commit 5c85e25862888f2e9a104a75c26404312b5feaf0
Author: Marcelo Schmitt <[email protected]>

dt-bindings: iio: adc: adi,ad4134: Document SPI connection mode

Document how AD4134 chips are connected to the host SPI controller according to different wiring configurations.

Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml properties: · line 136

Quoted 11 lines
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +3 -0
index ea6d7e0264190..d843c02a394a3 100644
@@ -131,6 +131,28 @@ properties:
     enum: [ free-running, gated ]
     default: gated
 
+  adi,spi-mode:
+    $ref: /schemas/types.yaml#/definitions/string
+    enum: [ no-cs, 4-wire, one-channel-chain, two-channel-chain ]

[Severity: Medium]
Does this schema need to explicitly allow the '#daisy-chained-devices' property, or reference /schemas/spi/spi-peripheral-props.yaml?

Standard devicetree descriptions for daisy-chained IIO devices require '#daisy-chained-devices' to communicate chain length.

Without it, won't any devicetree using the newly added 'one-channel-chain' mode fail dt_binding_check validation?

Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml properties:

Quoted 5 lines
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +5 -0
+    description: |
+      This property indicates the SPI wiring configuration.
+
+      When this property is omitted, it is assumed that the device is using
+      'no-cs' wiring.

[Severity: Low]
Is it possible to add the YAML 'default: no-cs' keyword to the schema definition?

Since the text describes a default fallback, structurally representing it ensures tooling can infer the default configuration.

[ ... ]

I also noticed some regressions in the driver code related to these SPI modes.

In drivers/iio/adc/ad4134.c:ad4134_probe():

	ret = device_property_match_property_string(dev, "adi,spi-mode",
						    ad4134_spi_modes,
						    ARRAY_SIZE(ad4134_spi_modes));
	/* Default to "no-cs" mode if adi,spi-mode is not specified */
	if (ret == -EINVAL)
		st->spi_mode = AD4134_SPI_MODE_NO_CS;

[Severity: High]
Does this code silently ignore unsupported strings?

device_property_match_property_string() returns -EINVAL when the property exists but contains a string not in the array (such as the newly added "one-channel-chain" mode).

If the driver doesn't support the chain modes yet, will this incorrectly configure the SPI host and multiplexer for no-cs minimum I/O mode?

Could this cause hardware protocol violations and garbage data reads during system initialization when a misconfigured or untrusted DT is provided?

In drivers/iio/adc/ad4134.c:ad4134_trigger_handler():

	for (unsigned int ch = 0; ch < iio_get_masklength(indio_dev); ch++) {
		ret = spi_write_then_read(st->spi, NULL, 0, &st->scan[ch],
...
	iio_push_to_buffers_with_ts(indio_dev, &st->scan, sizeof(st->scan),
				    pf->timestamp);

[Severity: Critical]
Does this loop overflow the st->scan array?

Because ad4134_chan_set includes the soft timestamp channel, iio_get_masklength(indio_dev) returns 5. The loop will unconditionally iterate up to ch=4, performing an SPI read into &st->scan[4].

Since st->scan is only sized for 4 channels (u32 scan[AD4134_NUM_CHANNELS]), won't this result in out-of-bounds memory corruption on every hardware trigger?

Furthermore, when the timestamp channel is enabled, IIO requires a 24-byte buffer (4x4 bytes + 8-byte timestamp). Because sizeof(st->scan) is 16 bytes, will iio_push_to_buffers_with_ts() detect the undersized buffer and silently drop all captured data?

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=8
#21 lore raw

Re: [PATCH v1 08/13] dt-bindings: iio: adc: adi,ad4134: Document SPI connection mode

In reply to Marcelo Schmitt
Quoted 15 lines · Marcelo Schmitt

Document how AD4134 chips are connected to the host SPI controller according to different wiring configurations.

---
 .../bindings/iio/adc/adi,ad4134.yaml          | 22 +++++++++++++++++++
 1 file changed, 22 insertions(+)
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +0 -0
index ea6d7e026419..d843c02a394a 100644
@@ -131,6 +131,28 @@ properties:
     enum: [ free-running, gated ]
     default: gated

Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml properties: · line 142

Quoted 10 lines
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +9 -0
 
+  adi,spi-mode:
+    $ref: /schemas/types.yaml#/definitions/string
+    enum: [ no-cs, 4-wire, one-channel-chain, two-channel-chain ]
+    description: |
+      This property indicates the SPI wiring configuration.
+
+      When this property is omitted, it is assumed that the device is using
+      'no-cs' wiring. When this property is present, it indicates that the
+      device is using one of the following wiring configurations:

"default: no-cs" and drop the text about the default, but there's some pretty interesting comments from Sashiko about #daisy-chained-devices (used for ad7944), although I'm not sure how that'd work for the two-channel-chain case.

I'd also really appreciate a dts example for a system
with one-channel-chain or two-channel-chain looks, given the second device may require different supplies etc. I have no impression in my head of how the dt would be constructed, so I'd like to see wht you have in mind.

Quoted 19 lines
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +13 -0
+
+      * no-cs: The datasheet calls this "minimum I/O mode". In this mode, the CS
+        line is not used (tied to GND).
+      * 4-wire: Specifies a conventional SPI wiring configuration.
+      * one-channel-chain: In this mode, the DOUT0 line of one chip is connected
+        to DOUT2 of the next chip upstream in the chain. Only the data interface
+        of the upmost device in the stream is in direct connection with the
+        digital host.
+      * two-channel-chain: In this mode, the DOUT0 and DOUT1 lines of one chip
+        are respectively connected to DOUT2 and DOUT3 of the next chip upstream
+        in the chain. Only the data interface of the upmost device in the stream
+        is in direct connection with the digital host.
+
 required:
   - compatible
   - reg
Signature · 1 line
2.53.0
#22 lore raw

Re: [PATCH v1 08/13] dt-bindings: iio: adc: adi,ad4134: Document SPI connection mode

Quoted 27 lines · Conor Dooley
Quoted 25 lines · Marcelo Schmitt

Document how AD4134 chips are connected to the host SPI controller according to different wiring configurations.

---
 .../bindings/iio/adc/adi,ad4134.yaml          | 22 +++++++++++++++++++
 1 file changed, 22 insertions(+)
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +9 -0
index ea6d7e026419..d843c02a394a 100644
@@ -131,6 +131,28 @@ properties:
     enum: [ free-running, gated ]
     default: gated
 
+  adi,spi-mode:
+    $ref: /schemas/types.yaml#/definitions/string
+    enum: [ no-cs, 4-wire, one-channel-chain, two-channel-chain ]
+    description: |
+      This property indicates the SPI wiring configuration.
+
+      When this property is omitted, it is assumed that the device is using
+      'no-cs' wiring. When this property is present, it indicates that the
+      device is using one of the following wiring configurations:

...

Quoted 5 lines

I'd also really appreciate a dts example for a system
with one-channel-chain or two-channel-chain looks, given the second device may require different supplies etc. I have no impression in my head of how the dt would be constructed, so I'd like to see wht you have in mind.

I've added the daisy-chain modes for completeness. It has the same semantics of ad7944 (daisy-)chain, despite the wiring being different. It looks like the supplies for the chained devices are simply assumed to be there (unless I'm missing something?). Though, now that I'm checking how to configure AD4134 for daisy-chain, I'm not sure how we could set them in dt. For 3 devices, we would have

    spi {
        ...
        adc@0 {
            compatible = "adi,ad4134";
            reg = <0>;
            spi-rx-bus-width = <1>, <1>; /* 2 lanes of 1 bit each */

            <supplies, clock, and other properties ...> 

            #daisy-chained-devices = <2>;

            adi,spi-mode = "4-wire";
        };
    };

But, the peripheral needs a register write to set the DOUT lines to 2-line daisy-chain and it doesn't seem to have register access propagation. So, we would need

    spi {
        ...
        adc@0 {
            compatible = "adi,ad4134";
            spi-rx-bus-width = <1>, <1>; /* 2 lanes of 1 bit each */

            <supplies, clock, and other properties ...> 

            #daisy-chained-devices = <2>;

            adi,spi-mode = "4-wire";
        };
        adc@1 {
            compatible = "adi,ad4134";
            <supplies, clock, and other properties ...> 

            adi,spi-mode = "4-wire";
        };
        adc@2 {
            compatible = "adi,ad4134";
            <supplies, clock, and other properties ...> 

            adi,spi-mode = "4-wire";
        };
    };

with adc@1 and adc@2 only set for register access. Even if not a dt-doc issue, that might (probably) lead to interface issues. The top of the daisy-chain may want to read from the other ADCs, but those could also be requested by IIO sysfs operations.

Quoted 14 lines
Quoted 4 lines
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +3 -0
+
+      * no-cs: The datasheet calls this "minimum I/O mode". In this mode, the CS
+        line is not used (tied to GND).

Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml properties: · line 155

Quoted 10 lines
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +10 -0
+      * 4-wire: Specifies a conventional SPI wiring configuration.
+      * one-channel-chain: In this mode, the DOUT0 line of one chip is connected
+        to DOUT2 of the next chip upstream in the chain. Only the data interface
+        of the upmost device in the stream is in direct connection with the
+        digital host.
+      * two-channel-chain: In this mode, the DOUT0 and DOUT1 lines of one chip
+        are respectively connected to DOUT2 and DOUT3 of the next chip upstream
+        in the chain. Only the data interface of the upmost device in the stream
+        is in direct connection with the digital host.
+

With best regards,
Marcelo

#23 lore raw

Re: [PATCH v1 08/13] dt-bindings: iio: adc: adi,ad4134: Document SPI connection mode

Quoted 28 lines · Marcelo Schmitt
Quoted 17 lines · Conor Dooley
Quoted 16 lines · Marcelo Schmitt

Document how AD4134 chips are connected to the host SPI controller according to different wiring configurations.

---
 .../bindings/iio/adc/adi,ad4134.yaml          | 22 +++++++++++++++++++
 1 file changed, 22 insertions(+)
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +0 -0
index ea6d7e026419..d843c02a394a 100644
@@ -131,6 +131,28 @@ properties:
     enum: [ free-running, gated ]
     default: gated
 
Quoted 10 lines

Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml properties: · line 142

Quoted 9 lines
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +9 -0
+  adi,spi-mode:
+    $ref: /schemas/types.yaml#/definitions/string
+    enum: [ no-cs, 4-wire, one-channel-chain, two-channel-chain ]
+    description: |
+      This property indicates the SPI wiring configuration.
+
+      When this property is omitted, it is assumed that the device is using
+      'no-cs' wiring. When this property is present, it indicates that the
+      device is using one of the following wiring configurations:
Quoted 7 lines

...

Quoted 5 lines

I'd also really appreciate a dts example for a system
with one-channel-chain or two-channel-chain looks, given the second device may require different supplies etc. I have no impression in my head of how the dt would be constructed, so I'd like to see wht you have in mind.

...

Realized what I said doesn't make much sense. The peripherals can all have the same configuration and thus share CS, SCLK, and controller SDO. The wiring would be like the following

::

  +-----------------------+                               +-----------------+
  |         AD4134        |                               | SPI Controller  |
  |                       |                               |                 |
  |                       |                               |                 |
  | SPI interface    SCLK |<--------------------+---------| SCLK            |
  | for register       CS |<--------------------|-+-------| CS              |
  | access            SDI |<--------------------|-|-+-----| SDO             |
  |                   SDO |------->|¯¯¯¯\       | | |     |                 |
  |                       |        |MUX  >------|-|-|---->| SDI0            |
  | Data interface  DOUT0 |------->|____/<------|-|-|---- | GPIO            |
  | for ADC sample  DOUT1 |---------------------|-|-|---->| SDI1            |
  | data read        DCLK |<-------------+------|-|-|-----| DCLK            |
  |                 DOUT2 |<-+           |      | | |     |                 |
  |                 DOUT3 |<-|-+         |      | | |     |                 |
  |                   ODR |<-|-|---------|--+   | | |  +->| Offload Trigger |
  +-----------------------+  | |         |  |   | | |  |  +-----------------+
                             | |         |  |   | | |  +--| PWM1            |
                             | |         |  +---| | | ----| PWM0            |
                             | |         |  |   | | |    +-----------------+
                             | |         |  |   | | |
  +-----------------------+  | |         |  |   | | |
  |         AD4134        |  | |         |  |   | | |
  |                       |  | |         |  |   | | |
  | SPI interface         |  | |         |  |   | | |
  | for register     SCLK |<-|-|---------|--|---+ | |
  | access             CS |<-|-|---------|--|---|-+ |
  |                   SDI |<-|-|---------|--|---|-|-+
  |                   SDO |  | |         |  |   | | |
  | Data interface        |  | |         |  |   | | |
  | for ADC sample  DOUT0 |--+ |         |  |   | | |
  | data read       DOUT1 |----+         |  |   | | |
  |                 DOUT2 |<-+           |  |   | | |
  |                 DOUT3 |<-|-+         |  |   | | |
  |                  DCLK |<-|-|---------+  |   | | |
  |                   ODR |<-|-|---------|--+   | | |
  +-----------------------+  | |         |  |   | | |
                             | |         |  |   | | |
                             | |         |  |   | | |
                             | |         |  |   | | |
  +-----------------------+  | |         |  |   | | |
  |         AD4134        |  | |         |  |   | | |
  |                       |  | |         |  |   | | |
  |                       |  | |         |  |   | | |
  | SPI interface    SCLK |<-|-|---------|--|---+ | |
  | for register       CS |<-|-|---------|--|-----+ |
  | access            SDI |<-|-|---------|--|-------+
  |                       |  | |         |  |
  | Data interface        |  | |         |  |
  | for ADC sample  DOUT0 |--+ |         |  |
  | data read       DOUT1 |----+         |  |
  |                 DOUT2 |              |  |
  |                 DOUT3 |              |  |
  |                  DCLK |<-------------+  |
  |                   ODR |<----------------+
  +-----------------------+

So we would set them as only one daisy-chained device.

    spi {
        ...
        adc@0 {
            compatible = "adi,ad4134";
            reg = <0>;
            spi-rx-bus-width = <1>, <1>; /* 2 lanes of 1 bit each */

            <supplies, clock, and other properties ...> 

            #daisy-chained-devices = <2>;

            adi,spi-mode = "two-channel-chain";
        };
    };

Thanks,
Marcelo

maintainer
#24 lore raw

Re: [PATCH v1 08/13] dt-bindings: iio: adc: adi,ad4134: Document SPI connection mode

Quoted 35 lines · On Fri, 4 Sep 2026 19:06:44 -0300 Marcelo Schmitt <[email protected]>…
Quoted 28 lines · Marcelo Schmitt
Quoted 26 lines · Conor Dooley
Quoted 25 lines · Marcelo Schmitt

Document how AD4134 chips are connected to the host SPI controller according to different wiring configurations.

---
 .../bindings/iio/adc/adi,ad4134.yaml          | 22 +++++++++++++++++++
 1 file changed, 22 insertions(+)
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +9 -0
index ea6d7e026419..d843c02a394a 100644
@@ -131,6 +131,28 @@ properties:
     enum: [ free-running, gated ]
     default: gated
 
+  adi,spi-mode:
+    $ref: /schemas/types.yaml#/definitions/string
+    enum: [ no-cs, 4-wire, one-channel-chain, two-channel-chain ]
+    description: |
+      This property indicates the SPI wiring configuration.
+
+      When this property is omitted, it is assumed that the device is using
+      'no-cs' wiring. When this property is present, it indicates that the
+      device is using one of the following wiring configurations:  

...

Quoted 6 lines
Quoted 5 lines

I'd also really appreciate a dts example for a system
with one-channel-chain or two-channel-chain looks, given the second device may require different supplies etc. I have no impression in my head of how the dt would be constructed, so I'd like to see wht you have in mind.

Quoted 5 lines

...

Realized what I said doesn't make much sense. The peripherals can all have the same configuration and thus share CS, SCLK, and controller SDO. The wiring would be like the following

That mux in the middle is controlled how?
I'd assume we still have separate chip selects and SDO/SDI shared. So I'd expect those to be on one SPI bus and the data to be going into separate buses (maybe all that can be hidden in the backend, not sure).

Or are you suggesting we are just letting all the chained devices see the same register writes? That might work I guess with no ability to read any register state back other than for first device. If you want to do the
mux magic below you are going to need to treat it as an SPI mux - just with some lines shared. That means this device ends up split into multiple device (even if only one ad4134 which is messy).

So to me this has a simple SPI bus, potentially connected to multiple devices and an IIO backend that deals with DOUT0 etc and the chaining.

Jonathan

Quoted 79 lines

::

  +-----------------------+                               +-----------------+
  |         AD4134        |                               | SPI Controller  |
  |                       |                               |                 |
  |                       |                               |                 |
  | SPI interface    SCLK |<--------------------+---------| SCLK            |
  | for register       CS |<--------------------|-+-------| CS              |
  | access            SDI |<--------------------|-|-+-----| SDO             |
  |                   SDO |------->|¯¯¯¯\       | | |     |                 |
  |                       |        |MUX  >------|-|-|---->| SDI0            |
  | Data interface  DOUT0 |------->|____/<------|-|-|---- | GPIO            |
  | for ADC sample  DOUT1 |---------------------|-|-|---->| SDI1            |
  | data read        DCLK |<-------------+------|-|-|-----| DCLK            |
  |                 DOUT2 |<-+           |      | | |     |                 |
  |                 DOUT3 |<-|-+         |      | | |     |                 |
  |                   ODR |<-|-|---------|--+   | | |  +->| Offload Trigger |
  +-----------------------+  | |         |  |   | | |  |  +-----------------+
                             | |         |  |   | | |  +--| PWM1            |
                             | |         |  +---| | | ----| PWM0            |
                             | |         |  |   | | |    +-----------------+
                             | |         |  |   | | |
  +-----------------------+  | |         |  |   | | |
  |         AD4134        |  | |         |  |   | | |
  |                       |  | |         |  |   | | |
  | SPI interface         |  | |         |  |   | | |
  | for register     SCLK |<-|-|---------|--|---+ | |
  | access             CS |<-|-|---------|--|---|-+ |
  |                   SDI |<-|-|---------|--|---|-|-+
  |                   SDO |  | |         |  |   | | |
  | Data interface        |  | |         |  |   | | |
  | for ADC sample  DOUT0 |--+ |         |  |   | | |
  | data read       DOUT1 |----+         |  |   | | |
  |                 DOUT2 |<-+           |  |   | | |
  |                 DOUT3 |<-|-+         |  |   | | |
  |                  DCLK |<-|-|---------+  |   | | |
  |                   ODR |<-|-|---------|--+   | | |
  +-----------------------+  | |         |  |   | | |
                             | |         |  |   | | |
                             | |         |  |   | | |
                             | |         |  |   | | |
  +-----------------------+  | |         |  |   | | |
  |         AD4134        |  | |         |  |   | | |
  |                       |  | |         |  |   | | |
  |                       |  | |         |  |   | | |
  | SPI interface    SCLK |<-|-|---------|--|---+ | |
  | for register       CS |<-|-|---------|--|-----+ |
  | access            SDI |<-|-|---------|--|-------+
  |                       |  | |         |  |
  | Data interface        |  | |         |  |
  | for ADC sample  DOUT0 |--+ |         |  |
  | data read       DOUT1 |----+         |  |
  |                 DOUT2 |              |  |
  |                 DOUT3 |              |  |
  |                  DCLK |<-------------+  |
  |                   ODR |<----------------+
  +-----------------------+

So we would set them as only one daisy-chained device.

    spi {
        ...
        adc@0 {
            compatible = "adi,ad4134";
            reg = <0>;
            spi-rx-bus-width = <1>, <1>; /* 2 lanes of 1 bit each */

            <supplies, clock, and other properties ...> 

            #daisy-chained-devices = <2>;

            adi,spi-mode = "two-channel-chain";
        };
    };

Thanks,
Marcelo

#25 lore raw

Re: [PATCH v1 08/13] dt-bindings: iio: adc: adi,ad4134: Document SPI connection mode

Quoted 38 lines · Jonathan Cameron
Quoted 35 lines · On Fri, 4 Sep 2026 19:06:44 -0300 Marcelo Schmitt <[email protected]>…
Quoted 34 lines · Marcelo Schmitt
Quoted 26 lines · Conor Dooley
Quoted 25 lines · Marcelo Schmitt

Document how AD4134 chips are connected to the host SPI controller according to different wiring configurations.

---
 .../bindings/iio/adc/adi,ad4134.yaml          | 22 +++++++++++++++++++
 1 file changed, 22 insertions(+)
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +9 -0
index ea6d7e026419..d843c02a394a 100644
@@ -131,6 +131,28 @@ properties:
     enum: [ free-running, gated ]
     default: gated
 
+  adi,spi-mode:
+    $ref: /schemas/types.yaml#/definitions/string
+    enum: [ no-cs, 4-wire, one-channel-chain, two-channel-chain ]
+    description: |
+      This property indicates the SPI wiring configuration.
+
+      When this property is omitted, it is assumed that the device is using
+      'no-cs' wiring. When this property is present, it indicates that the
+      device is using one of the following wiring configurations:  

...

Quoted 5 lines

I'd also really appreciate a dts example for a system
with one-channel-chain or two-channel-chain looks, given the second device may require different supplies etc. I have no impression in my head of how the dt would be constructed, so I'd like to see wht you have in mind.

Quoted 7 lines
Quoted 5 lines

...

Realized what I said doesn't make much sense. The peripherals can all have the same configuration and thus share CS, SCLK, and controller SDO. The wiring would be like the following

That mux in the middle is controlled how?

The mux is controlled by a GPIO. I ended up drawing the GPIO among SPI lines in the connection diagram but the mux controll signal is not part of the SPI controller.

Quoted 7 lines

I'd assume we still have separate chip selects and SDO/SDI shared. So I'd expect those to be on one SPI bus and the data to be going into separate buses (maybe all that can be hidden in the backend, not sure).

Or are you suggesting we are just letting all the chained devices see the same register writes? That might work I guess with no ability to read any register state back other than for first device.

Correct, that's the proposed configuration for daisy-chaining. Since all peripherals will receive the same write commands they shall all retain the same register configurations (except maybe for error indication registers). Reading from the topmost device in the chain would be enough to figure out the status of the other chained devices.

Quoted 4 lines

If you want to do the
mux magic below you are going to need to treat it as an SPI mux - just with some lines shared. That means this device ends up split into multiple device (even if only one ad4134 which is messy).

You mean spi-mux.yaml/spi-mux.c? So the goal/intent would be to have one IIO device for each peripheral in the chain? I think that would also work. Though, the only device bringing ADC sample data is the topmost one so that would be the only one buffer capable.

Quoted 3 lines

So to me this has a simple SPI bus, potentially connected to multiple devices and an IIO backend that deals with DOUT0 etc and the chaining.

Yeah, the benefit of having the mux is being able to connect both AD4134 interfaces to a single bus while being able to have ADC sample data on all SDI lines as the diagrams in patch 13.

Alternatively, we could have something like

                                                              +-------------+
  +----------------------+                                    |  DATA HOST  |
  |       AD4134         |                                    |             |
  |                      |                                    |             |
  |Data interface  DOUT0 |----------------------------------->| SDI1        |
  |for ADC data    DOUT1 |----------------------------------->| SDI2        |
  |sample read     DOUT2 |----------------------------------->| SDI3        |
  |                DOUT3 |----------------------------------->| SDI4        |
  |                DCLK  |<--------------+        +---------->| CS          |
  |                ODR   |<------------+ |        | +-------->| SCLK        |
  |                      |             | |        | | +------>| SDO         |
  |                      |             | |        | | | +---->| SDI         |
  | SPI interface   CS   |<-------+    | +--------|-|-|-|-----| DCLK        |
  | for register    SCLK |<-----+ |    |          | | | |     |             |
  | access          SDI  |<---+ | |    |          | | | |     | TRIGGER     |
  |                 SDO  |--+ | | |    |          | | | |     +-------------+
  +----------------------+  | | | |    +----------|-|-|-|---------+
                            | | | +---------------+ | | |
                            | | +-------------------+ | |
                            | +-----------------------+ |
                            +---------------------------+

The downside of the above is we would need an SPI_MULTI_LANE_MODE_STRIPE to read only from SDI1 to SDI4.

Quoted 83 lines

Jonathan

Quoted 79 lines

::

  +-----------------------+                               +-----------------+
  |         AD4134        |                               | SPI Controller  |
  |                       |                               |                 |
  |                       |                               |                 |
  | SPI interface    SCLK |<--------------------+---------| SCLK            |
  | for register       CS |<--------------------|-+-------| CS              |
  | access            SDI |<--------------------|-|-+-----| SDO             |
  |                   SDO |------->|¯¯¯¯\       | | |     |                 |
  |                       |        |MUX  >------|-|-|---->| SDI0            |
  | Data interface  DOUT0 |------->|____/<------|-|-|---- | GPIO            |
  | for ADC sample  DOUT1 |---------------------|-|-|---->| SDI1            |
  | data read        DCLK |<-------------+------|-|-|-----| DCLK            |
  |                 DOUT2 |<-+           |      | | |     |                 |
  |                 DOUT3 |<-|-+         |      | | |     |                 |
  |                   ODR |<-|-|---------|--+   | | |  +->| Offload Trigger |
  +-----------------------+  | |         |  |   | | |  |  +-----------------+
                             | |         |  |   | | |  +--| PWM1            |
                             | |         |  +---| | | ----| PWM0            |
                             | |         |  |   | | |    +-----------------+
                             | |         |  |   | | |
  +-----------------------+  | |         |  |   | | |
  |         AD4134        |  | |         |  |   | | |
  |                       |  | |         |  |   | | |
  | SPI interface         |  | |         |  |   | | |
  | for register     SCLK |<-|-|---------|--|---+ | |
  | access             CS |<-|-|---------|--|---|-+ |
  |                   SDI |<-|-|---------|--|---|-|-+
  |                   SDO |  | |         |  |   | | |
  | Data interface        |  | |         |  |   | | |
  | for ADC sample  DOUT0 |--+ |         |  |   | | |
  | data read       DOUT1 |----+         |  |   | | |
  |                 DOUT2 |<-+           |  |   | | |
  |                 DOUT3 |<-|-+         |  |   | | |
  |                  DCLK |<-|-|---------+  |   | | |
  |                   ODR |<-|-|---------|--+   | | |
  +-----------------------+  | |         |  |   | | |
                             | |         |  |   | | |
                             | |         |  |   | | |
                             | |         |  |   | | |
  +-----------------------+  | |         |  |   | | |
  |         AD4134        |  | |         |  |   | | |
  |                       |  | |         |  |   | | |
  |                       |  | |         |  |   | | |
  | SPI interface    SCLK |<-|-|---------|--|---+ | |
  | for register       CS |<-|-|---------|--|-----+ |
  | access            SDI |<-|-|---------|--|-------+
  |                       |  | |         |  |
  | Data interface        |  | |         |  |
  | for ADC sample  DOUT0 |--+ |         |  |
  | data read       DOUT1 |----+         |  |
  |                 DOUT2 |              |  |
  |                 DOUT3 |              |  |
  |                  DCLK |<-------------+  |
  |                   ODR |<----------------+
  +-----------------------+

So we would set them as only one daisy-chained device.

    spi {
        ...
        adc@0 {
            compatible = "adi,ad4134";
            reg = <0>;
            spi-rx-bus-width = <1>, <1>; /* 2 lanes of 1 bit each */

            <supplies, clock, and other properties ...> 

            #daisy-chained-devices = <2>;

            adi,spi-mode = "two-channel-chain";
        };
    };

Thanks,
Marcelo

maintainer
#26 lore raw

Re: [PATCH v1 08/13] dt-bindings: iio: adc: adi,ad4134: Document SPI connection mode

Quoted 41 lines · On Wed, 9 Sep 2026 12:17:37 -0300 Marcelo Schmitt <[email protected]>…
Quoted 40 lines · Jonathan Cameron
Quoted 37 lines · On Fri, 4 Sep 2026 19:06:44 -0300 Marcelo Schmitt <[email protected]>…
Quoted 34 lines · Marcelo Schmitt
Quoted 26 lines · Conor Dooley
Quoted 25 lines · Marcelo Schmitt

Document how AD4134 chips are connected to the host SPI controller according to different wiring configurations.

---
 .../bindings/iio/adc/adi,ad4134.yaml          | 22 +++++++++++++++++++
 1 file changed, 22 insertions(+)
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +9 -0
index ea6d7e026419..d843c02a394a 100644
@@ -131,6 +131,28 @@ properties:
     enum: [ free-running, gated ]
     default: gated
 
+  adi,spi-mode:
+    $ref: /schemas/types.yaml#/definitions/string
+    enum: [ no-cs, 4-wire, one-channel-chain, two-channel-chain ]
+    description: |
+      This property indicates the SPI wiring configuration.
+
+      When this property is omitted, it is assumed that the device is using
+      'no-cs' wiring. When this property is present, it indicates that the
+      device is using one of the following wiring configurations:    

...

Quoted 5 lines

I'd also really appreciate a dts example for a system
with one-channel-chain or two-channel-chain looks, given the second device may require different supplies etc. I have no impression in my head of how the dt would be constructed, so I'd like to see wht you have in mind.

...

Quoted 8 lines
Quoted 5 lines
Quoted 3 lines

Realized what I said doesn't make much sense. The peripherals can all have the same configuration and thus share CS, SCLK, and controller SDO. The wiring would be like the following

That mux in the middle is controlled how?

The mux is controlled by a GPIO. I ended up drawing the GPIO among SPI lines in the connection diagram but the mux controll signal is not part of the SPI controller.

Ok. So we are effectively making that mux part of of the ad4134 controlled hardware. I guess I don't mind that but shout about it a lot in the driver as anyone coming in will wonder where the magic mux appeared from :)

Quoted 5 lines
Quoted 5 lines

I'd assume we still have separate chip selects and SDO/SDI shared. So I'd expect those to be on one SPI bus and the data to be going into separate buses (maybe all that can be hidden in the backend, not sure).

Quoted 8 lines
Quoted 3 lines

Or are you suggesting we are just letting all the chained devices see the same register writes? That might work I guess with no ability to read any register state back other than for first device.

Correct, that's the proposed configuration for daisy-chaining. Since all peripherals will receive the same write commands they shall all retain the same register configurations (except maybe for error indication registers). Reading from the topmost device in the chain would be enough to figure out the status of the other chained devices.

It's errors that concern me about this. Maybe it's the best we can do.

Quoted 9 lines
Quoted 5 lines

If you want to do the
mux magic below you are going to need to treat it as an SPI mux - just with some lines shared. That means this device ends up split into multiple device (even if only one ad4134 which is messy).

You mean spi-mux.yaml/spi-mux.c? So the goal/intent would be to have one IIO device for each peripheral in the chain? I think that would also work. Though, the only device bringing ADC sample data is the topmost one so that would be the only one buffer capable.

We went through that discussion IIRC for the original chaining devices and it ends up too odd as there is no way for userspace to know that we have this strange interacting set of devices.

Quoted 32 lines
Quoted 4 lines

So to me this has a simple SPI bus, potentially connected to multiple devices and an IIO backend that deals with DOUT0 etc and the chaining.

Yeah, the benefit of having the mux is being able to connect both AD4134 interfaces to a single bus while being able to have ADC sample data on all SDI lines as the diagrams in patch 13.

Alternatively, we could have something like

                                                              +-------------+
  +----------------------+                                    |  DATA HOST  |
  |       AD4134         |                                    |             |
  |                      |                                    |             |
  |Data interface  DOUT0 |----------------------------------->| SDI1        |
  |for ADC data    DOUT1 |----------------------------------->| SDI2        |
  |sample read     DOUT2 |----------------------------------->| SDI3        |
  |                DOUT3 |----------------------------------->| SDI4        |
  |                DCLK  |<--------------+        +---------->| CS          |
  |                ODR   |<------------+ |        | +-------->| SCLK        |
  |                      |             | |        | | +------>| SDO         |
  |                      |             | |        | | | +---->| SDI         |
  | SPI interface   CS   |<-------+    | +--------|-|-|-|-----| DCLK        |
  | for register    SCLK |<-----+ |    |          | | | |     |             |
  | access          SDI  |<---+ | |    |          | | | |     | TRIGGER     |
  |                 SDO  |--+ | | |    |          | | | |     +-------------+
  +----------------------+  | | | |    +----------|-|-|-|---------+
                            | | | +---------------+ | | |
                            | | +-------------------+ | |
                            | +-----------------------+ |
                            +---------------------------+
Quoted 2 lines

The downside of the above is we would need an SPI_MULTI_LANE_MODE_STRIPE to read only from SDI1 to SDI4.

I don't totally follow that detail, but indeed the control SPI plane would be independent and so we'd need to do something to get that from the binding in a way that distinguishes it from other spi controllers. The device would be sitting on two SPI busses, one of which had the multi channel properties.

To me this one is more natural but I can see both might get built and the complexity of representing that as an SPI mux would be you'd be using part of a wider spi controller. Hence I guess maybe the hidden (ish) mux is the way to go.

Jonathan

Quoted 84 lines
Quoted 84 lines

Jonathan

Quoted 79 lines

::

  +-----------------------+                               +-----------------+
  |         AD4134        |                               | SPI Controller  |
  |                       |                               |                 |
  |                       |                               |                 |
  | SPI interface    SCLK |<--------------------+---------| SCLK            |
  | for register       CS |<--------------------|-+-------| CS              |
  | access            SDI |<--------------------|-|-+-----| SDO             |
  |                   SDO |------->|¯¯¯¯\       | | |     |                 |
  |                       |        |MUX  >------|-|-|---->| SDI0            |
  | Data interface  DOUT0 |------->|____/<------|-|-|---- | GPIO            |
  | for ADC sample  DOUT1 |---------------------|-|-|---->| SDI1            |
  | data read        DCLK |<-------------+------|-|-|-----| DCLK            |
  |                 DOUT2 |<-+           |      | | |     |                 |
  |                 DOUT3 |<-|-+         |      | | |     |                 |
  |                   ODR |<-|-|---------|--+   | | |  +->| Offload Trigger |
  +-----------------------+  | |         |  |   | | |  |  +-----------------+
                             | |         |  |   | | |  +--| PWM1            |
                             | |         |  +---| | | ----| PWM0            |
                             | |         |  |   | | |    +-----------------+
                             | |         |  |   | | |
  +-----------------------+  | |         |  |   | | |
  |         AD4134        |  | |         |  |   | | |
  |                       |  | |         |  |   | | |
  | SPI interface         |  | |         |  |   | | |
  | for register     SCLK |<-|-|---------|--|---+ | |
  | access             CS |<-|-|---------|--|---|-+ |
  |                   SDI |<-|-|---------|--|---|-|-+
  |                   SDO |  | |         |  |   | | |
  | Data interface        |  | |         |  |   | | |
  | for ADC sample  DOUT0 |--+ |         |  |   | | |
  | data read       DOUT1 |----+         |  |   | | |
  |                 DOUT2 |<-+           |  |   | | |
  |                 DOUT3 |<-|-+         |  |   | | |
  |                  DCLK |<-|-|---------+  |   | | |
  |                   ODR |<-|-|---------|--+   | | |
  +-----------------------+  | |         |  |   | | |
                             | |         |  |   | | |
                             | |         |  |   | | |
                             | |         |  |   | | |
  +-----------------------+  | |         |  |   | | |
  |         AD4134        |  | |         |  |   | | |
  |                       |  | |         |  |   | | |
  |                       |  | |         |  |   | | |
  | SPI interface    SCLK |<-|-|---------|--|---+ | |
  | for register       CS |<-|-|---------|--|-----+ |
  | access            SDI |<-|-|---------|--|-------+
  |                       |  | |         |  |
  | Data interface        |  | |         |  |
  | for ADC sample  DOUT0 |--+ |         |  |
  | data read       DOUT1 |----+         |  |
  |                 DOUT2 |              |  |
  |                 DOUT3 |              |  |
  |                  DCLK |<-------------+  |
  |                   ODR |<----------------+
  +-----------------------+

So we would set them as only one daisy-chained device.

    spi {
        ...
        adc@0 {
            compatible = "adi,ad4134";
            reg = <0>;
            spi-rx-bus-width = <1>, <1>; /* 2 lanes of 1 bit each */

            <supplies, clock, and other properties ...> 

            #daisy-chained-devices = <2>;

            adi,spi-mode = "two-channel-chain";
        };
    };

Thanks,
Marcelo

#27 lore raw

Re: [PATCH v1 08/13] dt-bindings: iio: adc: adi,ad4134: Document SPI connection mode

In reply to Marcelo Schmitt
Quoted 103 lines · Marcelo Schmitt
Quoted 28 lines · Marcelo Schmitt
Quoted 17 lines · Conor Dooley
Quoted 16 lines · Marcelo Schmitt

Document how AD4134 chips are connected to the host SPI controller according to different wiring configurations.

---
 .../bindings/iio/adc/adi,ad4134.yaml          | 22 +++++++++++++++++++
 1 file changed, 22 insertions(+)
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +0 -0
index ea6d7e026419..d843c02a394a 100644
@@ -131,6 +131,28 @@ properties:
     enum: [ free-running, gated ]
     default: gated
 
Quoted 10 lines

Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml properties: · line 142

Quoted 9 lines
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +9 -0
+  adi,spi-mode:
+    $ref: /schemas/types.yaml#/definitions/string
+    enum: [ no-cs, 4-wire, one-channel-chain, two-channel-chain ]
+    description: |
+      This property indicates the SPI wiring configuration.
+
+      When this property is omitted, it is assumed that the device is using
+      'no-cs' wiring. When this property is present, it indicates that the
+      device is using one of the following wiring configurations:
Quoted 7 lines

...

Quoted 5 lines

I'd also really appreciate a dts example for a system
with one-channel-chain or two-channel-chain looks, given the second device may require different supplies etc. I have no impression in my head of how the dt would be constructed, so I'd like to see wht you have in mind.

...

Realized what I said doesn't make much sense. The peripherals can all have the same configuration and thus share CS, SCLK, and controller SDO. The wiring would be like the following

::

  +-----------------------+                               +-----------------+
  |         AD4134        |                               | SPI Controller  |
  |                       |                               |                 |
  |                       |                               |                 |
  | SPI interface    SCLK |<--------------------+---------| SCLK            |
  | for register       CS |<--------------------|-+-------| CS              |
  | access            SDI |<--------------------|-|-+-----| SDO             |
  |                   SDO |------->|¯¯¯¯\       | | |     |                 |
  |                       |        |MUX  >------|-|-|---->| SDI0            |
  | Data interface  DOUT0 |------->|____/<------|-|-|---- | GPIO            |
  | for ADC sample  DOUT1 |---------------------|-|-|---->| SDI1            |
  | data read        DCLK |<-------------+------|-|-|-----| DCLK            |
  |                 DOUT2 |<-+           |      | | |     |                 |
  |                 DOUT3 |<-|-+         |      | | |     |                 |
  |                   ODR |<-|-|---------|--+   | | |  +->| Offload Trigger |
  +-----------------------+  | |         |  |   | | |  |  +-----------------+
                             | |         |  |   | | |  +--| PWM1            |
                             | |         |  +---| | | ----| PWM0            |
                             | |         |  |   | | |    +-----------------+
                             | |         |  |   | | |
  +-----------------------+  | |         |  |   | | |
  |         AD4134        |  | |         |  |   | | |
  |                       |  | |         |  |   | | |
  | SPI interface         |  | |         |  |   | | |
  | for register     SCLK |<-|-|---------|--|---+ | |
  | access             CS |<-|-|---------|--|---|-+ |
  |                   SDI |<-|-|---------|--|---|-|-+
  |                   SDO |  | |         |  |   | | |
  | Data interface        |  | |         |  |   | | |
  | for ADC sample  DOUT0 |--+ |         |  |   | | |
  | data read       DOUT1 |----+         |  |   | | |
  |                 DOUT2 |<-+           |  |   | | |
  |                 DOUT3 |<-|-+         |  |   | | |
  |                  DCLK |<-|-|---------+  |   | | |
  |                   ODR |<-|-|---------|--+   | | |
  +-----------------------+  | |         |  |   | | |
                             | |         |  |   | | |
                             | |         |  |   | | |
                             | |         |  |   | | |
  +-----------------------+  | |         |  |   | | |
  |         AD4134        |  | |         |  |   | | |
  |                       |  | |         |  |   | | |
  |                       |  | |         |  |   | | |
  | SPI interface    SCLK |<-|-|---------|--|---+ | |
  | for register       CS |<-|-|---------|--|-----+ |
  | access            SDI |<-|-|---------|--|-------+
  |                       |  | |         |  |
  | Data interface        |  | |         |  |
  | for ADC sample  DOUT0 |--+ |         |  |
  | data read       DOUT1 |----+         |  |
  |                 DOUT2 |              |  |
  |                 DOUT3 |              |  |
  |                  DCLK |<-------------+  |
  |                   ODR |<----------------+
  +-----------------------+

So we would set them as only one daisy-chained device.

Quoted 10 lines
    spi {
        ...
        adc@0 {
            compatible = "adi,ad4134";
            reg = <0>;
            spi-rx-bus-width = <1>, <1>; /* 2 lanes of 1 bit each */

            <supplies, clock, and other properties ...> 

            #daisy-chained-devices = <2>;

Does this property actually provide value here? I assume it does because otherwise you don't know how many devices there are.

Quoted 1 line
            adi,spi-mode = "two-channel-chain";

How does this interact with spi-rx-bus-width? Is the value of this consistent with adi,spi-mode? IOW, for adi,spi-mode = "one.." will there only ever be Dout0 connected to the host and for adi,spi-mode = "two.." will Dout1 and Dout0 both be connected?

#28 lore raw

Re: [PATCH v1 08/13] dt-bindings: iio: adc: adi,ad4134: Document SPI connection mode

Hello Conor, sorry for delayed reply.

Quoted 111 lines · Conor Dooley
Quoted 110 lines · Marcelo Schmitt
Quoted 28 lines · Marcelo Schmitt
Quoted 17 lines · Conor Dooley
Quoted 16 lines · Marcelo Schmitt

Document how AD4134 chips are connected to the host SPI controller according to different wiring configurations.

---
 .../bindings/iio/adc/adi,ad4134.yaml          | 22 +++++++++++++++++++
 1 file changed, 22 insertions(+)
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +0 -0
index ea6d7e026419..d843c02a394a 100644
@@ -131,6 +131,28 @@ properties:
     enum: [ free-running, gated ]
     default: gated
 
Quoted 10 lines

Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml properties: · line 142

Quoted 9 lines
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +9 -0
+  adi,spi-mode:
+    $ref: /schemas/types.yaml#/definitions/string
+    enum: [ no-cs, 4-wire, one-channel-chain, two-channel-chain ]
+    description: |
+      This property indicates the SPI wiring configuration.
+
+      When this property is omitted, it is assumed that the device is using
+      'no-cs' wiring. When this property is present, it indicates that the
+      device is using one of the following wiring configurations:
Quoted 7 lines

...

Quoted 5 lines

I'd also really appreciate a dts example for a system
with one-channel-chain or two-channel-chain looks, given the second device may require different supplies etc. I have no impression in my head of how the dt would be constructed, so I'd like to see wht you have in mind.

...

Realized what I said doesn't make much sense. The peripherals can all have the same configuration and thus share CS, SCLK, and controller SDO. The wiring would be like the following

::

  +-----------------------+                               +-----------------+
  |         AD4134        |                               | SPI Controller  |
  |                       |                               |                 |
  |                       |                               |                 |
  | SPI interface    SCLK |<--------------------+---------| SCLK            |
  | for register       CS |<--------------------|-+-------| CS              |
  | access            SDI |<--------------------|-|-+-----| SDO             |
  |                   SDO |------->|¯¯¯¯\       | | |     |                 |
  |                       |        |MUX  >------|-|-|---->| SDI0            |
  | Data interface  DOUT0 |------->|____/<------|-|-|---- | GPIO            |
  | for ADC sample  DOUT1 |---------------------|-|-|---->| SDI1            |
  | data read        DCLK |<-------------+------|-|-|-----| DCLK            |
  |                 DOUT2 |<-+           |      | | |     |                 |
  |                 DOUT3 |<-|-+         |      | | |     |                 |
  |                   ODR |<-|-|---------|--+   | | |  +->| Offload Trigger |
  +-----------------------+  | |         |  |   | | |  |  +-----------------+
                             | |         |  |   | | |  +--| PWM1            |
                             | |         |  +---| | | ----| PWM0            |
                             | |         |  |   | | |    +-----------------+
                             | |         |  |   | | |
  +-----------------------+  | |         |  |   | | |
  |         AD4134        |  | |         |  |   | | |
  |                       |  | |         |  |   | | |
  | SPI interface         |  | |         |  |   | | |
  | for register     SCLK |<-|-|---------|--|---+ | |
  | access             CS |<-|-|---------|--|---|-+ |
  |                   SDI |<-|-|---------|--|---|-|-+
  |                   SDO |  | |         |  |   | | |
  | Data interface        |  | |         |  |   | | |
  | for ADC sample  DOUT0 |--+ |         |  |   | | |
  | data read       DOUT1 |----+         |  |   | | |
  |                 DOUT2 |<-+           |  |   | | |
  |                 DOUT3 |<-|-+         |  |   | | |
  |                  DCLK |<-|-|---------+  |   | | |
  |                   ODR |<-|-|---------|--+   | | |
  +-----------------------+  | |         |  |   | | |
                             | |         |  |   | | |
                             | |         |  |   | | |
                             | |         |  |   | | |
  +-----------------------+  | |         |  |   | | |
  |         AD4134        |  | |         |  |   | | |
  |                       |  | |         |  |   | | |
  |                       |  | |         |  |   | | |
  | SPI interface    SCLK |<-|-|---------|--|---+ | |
  | for register       CS |<-|-|---------|--|-----+ |
  | access            SDI |<-|-|---------|--|-------+
  |                       |  | |         |  |
  | Data interface        |  | |         |  |
  | for ADC sample  DOUT0 |--+ |         |  |
  | data read       DOUT1 |----+         |  |
  |                 DOUT2 |              |  |
  |                 DOUT3 |              |  |
  |                  DCLK |<-------------+  |
  |                   ODR |<----------------+
  +-----------------------+

So we would set them as only one daisy-chained device.

    spi {
        ...
        adc@0 {
            compatible = "adi,ad4134";
            reg = <0>;
            spi-rx-bus-width = <1>, <1>; /* 2 lanes of 1 bit each */
Quoted 6 lines
Quoted 3 lines

<supplies, clock, and other properties ...>

#daisy-chained-devices = <2>;

Does this property actually provide value here? I assume it does because otherwise you don't know how many devices there are.

Yes, the number of daisy-chained-devices is needed to determine how much data to transfer on ADC sample read. We already have some documentation in Documentation/devicetree/bindings/common-properties.txt

Quoted 7 lines
Quoted 2 lines
            adi,spi-mode = "two-channel-chain";

How does this interact with spi-rx-bus-width? Is the value of this consistent with adi,spi-mode? IOW, for adi,spi-mode = "one.." will there only ever be Dout0 connected to the host and for adi,spi-mode = "two.." will Dout1 and Dout0 both be connected?

For this particular ADC design, yes.
adi,spi-mode = "one-channel-chain" always expects spi-rx-bus-width = <1> (only DOUT0) and adi,spi-mode = "two-channel-chain" always expects spi-rx-bus-width = <1>, <1> (DOUT0, DOOUT1). Though, it is possible to have spi-rx-bus-width = <1> and
spi-rx-bus-width = <1>, <1> in non-chained setups.

Will make the constraints explicit on v2.
allOf:
...
- oneOf:
- required: [adi,spi-mode, '#daisy-chained-devices'] properties:
adi,spi-mode:
const: one-channel-chain
spi-rx-bus-width:
maxItems: 1
- required: [adi,spi-mode, '#daisy-chained-devices'] properties:
adi,spi-mode:
const: two-channel-chain
spi-rx-bus-width:
minItems: 2
maxItems: 2
- properties:
'#daisy-chained-devices': false

Best regards,
Marcelo

#29 lore raw

Re: [PATCH v1 08/13] dt-bindings: iio: adc: adi,ad4134: Document SPI connection mode

Quoted 133 lines · Marcelo Schmitt

Hello Conor, sorry for delayed reply.

Quoted 111 lines · Conor Dooley
Quoted 110 lines · Marcelo Schmitt
Quoted 28 lines · Marcelo Schmitt
Quoted 17 lines · Conor Dooley
Quoted 16 lines · Marcelo Schmitt

Document how AD4134 chips are connected to the host SPI controller according to different wiring configurations.

---
 .../bindings/iio/adc/adi,ad4134.yaml          | 22 +++++++++++++++++++
 1 file changed, 22 insertions(+)
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +0 -0
index ea6d7e026419..d843c02a394a 100644
@@ -131,6 +131,28 @@ properties:
     enum: [ free-running, gated ]
     default: gated
 
Quoted 10 lines

Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml properties: · line 142

Quoted 9 lines
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +9 -0
+  adi,spi-mode:
+    $ref: /schemas/types.yaml#/definitions/string
+    enum: [ no-cs, 4-wire, one-channel-chain, two-channel-chain ]
+    description: |
+      This property indicates the SPI wiring configuration.
+
+      When this property is omitted, it is assumed that the device is using
+      'no-cs' wiring. When this property is present, it indicates that the
+      device is using one of the following wiring configurations:
Quoted 7 lines

...

Quoted 5 lines

I'd also really appreciate a dts example for a system
with one-channel-chain or two-channel-chain looks, given the second device may require different supplies etc. I have no impression in my head of how the dt would be constructed, so I'd like to see wht you have in mind.

...

Realized what I said doesn't make much sense. The peripherals can all have the same configuration and thus share CS, SCLK, and controller SDO. The wiring would be like the following

::

  +-----------------------+                               +-----------------+
  |         AD4134        |                               | SPI Controller  |
  |                       |                               |                 |
  |                       |                               |                 |
  | SPI interface    SCLK |<--------------------+---------| SCLK            |
  | for register       CS |<--------------------|-+-------| CS              |
  | access            SDI |<--------------------|-|-+-----| SDO             |
  |                   SDO |------->|¯¯¯¯\       | | |     |                 |
  |                       |        |MUX  >------|-|-|---->| SDI0            |
  | Data interface  DOUT0 |------->|____/<------|-|-|---- | GPIO            |
  | for ADC sample  DOUT1 |---------------------|-|-|---->| SDI1            |
  | data read        DCLK |<-------------+------|-|-|-----| DCLK            |
  |                 DOUT2 |<-+           |      | | |     |                 |
  |                 DOUT3 |<-|-+         |      | | |     |                 |
  |                   ODR |<-|-|---------|--+   | | |  +->| Offload Trigger |
  +-----------------------+  | |         |  |   | | |  |  +-----------------+
                             | |         |  |   | | |  +--| PWM1            |
                             | |         |  +---| | | ----| PWM0            |
                             | |         |  |   | | |    +-----------------+
                             | |         |  |   | | |
  +-----------------------+  | |         |  |   | | |
  |         AD4134        |  | |         |  |   | | |
  |                       |  | |         |  |   | | |
  | SPI interface         |  | |         |  |   | | |
  | for register     SCLK |<-|-|---------|--|---+ | |
  | access             CS |<-|-|---------|--|---|-+ |
  |                   SDI |<-|-|---------|--|---|-|-+
  |                   SDO |  | |         |  |   | | |
  | Data interface        |  | |         |  |   | | |
  | for ADC sample  DOUT0 |--+ |         |  |   | | |
  | data read       DOUT1 |----+         |  |   | | |
  |                 DOUT2 |<-+           |  |   | | |
  |                 DOUT3 |<-|-+         |  |   | | |
  |                  DCLK |<-|-|---------+  |   | | |
  |                   ODR |<-|-|---------|--+   | | |
  +-----------------------+  | |         |  |   | | |
                             | |         |  |   | | |
                             | |         |  |   | | |
                             | |         |  |   | | |
  +-----------------------+  | |         |  |   | | |
  |         AD4134        |  | |         |  |   | | |
  |                       |  | |         |  |   | | |
  |                       |  | |         |  |   | | |
  | SPI interface    SCLK |<-|-|---------|--|---+ | |
  | for register       CS |<-|-|---------|--|-----+ |
  | access            SDI |<-|-|---------|--|-------+
  |                       |  | |         |  |
  | Data interface        |  | |         |  |
  | for ADC sample  DOUT0 |--+ |         |  |
  | data read       DOUT1 |----+         |  |
  |                 DOUT2 |              |  |
  |                 DOUT3 |              |  |
  |                  DCLK |<-------------+  |
  |                   ODR |<----------------+
  +-----------------------+

So we would set them as only one daisy-chained device.

    spi {
        ...
        adc@0 {
            compatible = "adi,ad4134";
            reg = <0>;
            spi-rx-bus-width = <1>, <1>; /* 2 lanes of 1 bit each */
Quoted 6 lines
Quoted 3 lines

<supplies, clock, and other properties ...>

#daisy-chained-devices = <2>;

Does this property actually provide value here? I assume it does because otherwise you don't know how many devices there are.

Yes, the number of daisy-chained-devices is needed to determine how much data to transfer on ADC sample read. We already have some documentation in Documentation/devicetree/bindings/common-properties.txt

Quoted 7 lines
Quoted 2 lines
            adi,spi-mode = "two-channel-chain";

How does this interact with spi-rx-bus-width? Is the value of this consistent with adi,spi-mode? IOW, for adi,spi-mode = "one.." will there only ever be Dout0 connected to the host and for adi,spi-mode = "two.." will Dout1 and Dout0 both be connected?

Quoted 7 lines

For this particular ADC design, yes.
adi,spi-mode = "one-channel-chain" always expects spi-rx-bus-width = <1> (only DOUT0) and adi,spi-mode = "two-channel-chain" always expects spi-rx-bus-width = <1>, <1> (DOUT0, DOOUT1). Though, it is possible to have spi-rx-bus-width = <1> and
spi-rx-bus-width = <1>, <1> in non-chained setups.

Will make the constraints explicit on v2.

If you think that helps, sure. I was mostly asking this for my own education, because this kind of device is new to me, so that I know what to expect from future bindings of the same kind (and to have a record on lore when I inevitably forget).

Quoted 9 lines

allOf:
...
- oneOf:
- required: [adi,spi-mode, '#daisy-chained-devices'] properties:
adi,spi-mode:
const: one-channel-chain
spi-rx-bus-width:
maxItems: 1

Is this enough of a constraint? Someone could still put in spi-rx-bus-width = <2>...

Quoted 7 lines

- required: [adi,spi-mode, '#daisy-chained-devices'] properties:
adi,spi-mode:
const: two-channel-chain
spi-rx-bus-width:
minItems: 2
maxItems: 2

...or spi-rx-bus-width = <2>, <3> here which conflicts with your comment above, right?

Prob worth limiting the actual item to 1, if you're gonna add constraints like this.

Quoted 6 lines

- properties:
'#daisy-chained-devices': false

Best regards,
Marcelo

maintainer
#30 lore raw

Re: [PATCH v1 08/13] dt-bindings: iio: adc: adi,ad4134: Document SPI connection mode

In reply to Marcelo Schmitt
Quoted 35 lines · On Fri, 4 Sep 2026 17:47:56 -0300 Marcelo Schmitt <[email protected]>…
Quoted 27 lines · Conor Dooley
Quoted 25 lines · Marcelo Schmitt

Document how AD4134 chips are connected to the host SPI controller according to different wiring configurations.

---
 .../bindings/iio/adc/adi,ad4134.yaml          | 22 +++++++++++++++++++
 1 file changed, 22 insertions(+)
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +9 -0
index ea6d7e026419..d843c02a394a 100644
@@ -131,6 +131,28 @@ properties:
     enum: [ free-running, gated ]
     default: gated
 
+  adi,spi-mode:
+    $ref: /schemas/types.yaml#/definitions/string
+    enum: [ no-cs, 4-wire, one-channel-chain, two-channel-chain ]
+    description: |
+      This property indicates the SPI wiring configuration.
+
+      When this property is omitted, it is assumed that the device is using
+      'no-cs' wiring. When this property is present, it indicates that the
+      device is using one of the following wiring configurations:  

...

Quoted 5 lines

I'd also really appreciate a dts example for a system
with one-channel-chain or two-channel-chain looks, given the second device may require different supplies etc. I have no impression in my head of how the dt would be constructed, so I'd like to see wht you have in mind.

Quoted 4 lines

I've added the daisy-chain modes for completeness. It has the same semantics of ad7944 (daisy-)chain, despite the wiring being different. It looks like the supplies for the chained devices are simply assumed to be there (unless I'm missing something?).

I think the only cases we ever had of this in the past either used always on supplies or shared them. That is a bit of an annoying limitation so if we can work around that it would be good.

Quoted 19 lines

Though, now that I'm checking how to configure AD4134
for daisy-chain, I'm not sure how we could set them in dt. For 3 devices, we would have

    spi {
        ...
        adc@0 {
            compatible = "adi,ad4134";
            reg = <0>;
            spi-rx-bus-width = <1>, <1>; /* 2 lanes of 1 bit each */

            <supplies, clock, and other properties ...> 

            #daisy-chained-devices = <2>;

            adi,spi-mode = "4-wire";
        };
    };
Quoted 3 lines

But, the peripheral needs a register write to set the DOUT lines to 2-line daisy-chain and it doesn't seem to have register access propagation. So, we would need

That lack of register access propagation I think is the difference here from devices we have supported chaining on in the past. To me it sounds fairly fundamental to any generic solution.

Quoted 26 lines
    spi {
        ...
        adc@0 {
            compatible = "adi,ad4134";
            spi-rx-bus-width = <1>, <1>; /* 2 lanes of 1 bit each */

            <supplies, clock, and other properties ...> 

            #daisy-chained-devices = <2>;

            adi,spi-mode = "4-wire";
        };
        adc@1 {
            compatible = "adi,ad4134";
            <supplies, clock, and other properties ...> 

            adi,spi-mode = "4-wire";
        };
        adc@2 {
            compatible = "adi,ad4134";
            <supplies, clock, and other properties ...> 

            adi,spi-mode = "4-wire";
        };
    };
Quoted 4 lines

with adc@1 and adc@2 only set for register access. Even if not a dt-doc issue, that might (probably) lead to interface issues. The top of the daisy-chain may want to read from the other ADCs, but those could also be requested by IIO sysfs operations.

I think this bit you rewrite in next mail so I'll ignore.

Quoted 18 lines
Quoted 15 lines
Quoted 5 lines
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +3 -0
+
+      * no-cs: The datasheet calls this "minimum I/O mode". In this mode, the CS
+        line is not used (tied to GND).

Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml properties: · line 155

Quoted 10 lines
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +10 -0
+      * 4-wire: Specifies a conventional SPI wiring configuration.
+      * one-channel-chain: In this mode, the DOUT0 line of one chip is connected
+        to DOUT2 of the next chip upstream in the chain. Only the data interface
+        of the upmost device in the stream is in direct connection with the
+        digital host.
+      * two-channel-chain: In this mode, the DOUT0 and DOUT1 lines of one chip
+        are respectively connected to DOUT2 and DOUT3 of the next chip upstream
+        in the chain. Only the data interface of the upmost device in the stream
+        is in direct connection with the digital host.
+  

With best regards,
Marcelo

author maintainer
#31 lore raw

PATCH 9/13 iio: adc: ad4134: Support SPI 4-wire mode

In reply to Marcelo Schmitt

AD4134 devices can be wired in a few different ways. So far, only minimum I/O mode was supported. While minimum I/O mode allows interfacing with AD4134 with a reduced number of wires, that wiring configuration is not optimal for high-throughput data acquisition.

Extend AD4134 support to enable interfacing in SPI 4-wire configuration.

---
The reason for the input multiplexer is enable both register access and multi-lane read. Before coming to the current solution, we tried the following configuration.

  +-----------------------+                           +-----------------+
  |       AD4134          |                           | SPI Controller  |
  |                       |                           |                 |
  | SPI interface         |                           |                 |
  | for register     SCLK |<--------------------------| SCLK            |
  | access             CS |<--------------------------| CS              |
  |                   SDI |<--------------------------| SDO             |
  |                   SDO |---+                       |                 |
  |                       |   |                       |                 |
  | Data interface  DOUT0 |---+---------------------->| SDI0            |
  | for ADC data    DOUT1 |-------------------------->| SDI1            |
  | read back       DOUT2 |-------------------------->| SDI2            |
  |                 DOUT3 |-------------------------->| SDI3            |
  |                 DCLK  |<--------------------------| DCLK
  |                 ODR   |<------------------+    +->| Offload Trigger |
  +-----------------------+                   |    |  +-----------------+
                                              |    +--| PWM1            |
                                              +-------| PWM0            |
                                              +-------| GPIO            |
                                                      +-----------------+

Though, because DOUT0 never goes high-Z, the DOUT0 pin keeps driving the data line, causing register read to fail (always get 0xFF). Another solution would be to connect SDO to SDI0 and DOUT pins to SDI1, SDI2, SDI3, SDI4. That would then require a special multi-lane mode.

Please, see patch 13 for a better view of how the proposed setup works.

 drivers/iio/adc/Kconfig  |   1 +
 drivers/iio/adc/ad4134.c | 162 +++++++++++++++++++++++++++++++++++++--
 2 files changed, 158 insertions(+), 5 deletions(-)
drivers/iio/adc/Kconfig +1 -0
index 584251a3f45c..ef77ee60df4e 100644
@@ -127,6 +127,7 @@ config AD4134
 	select CRC8
 	select IIO_BUFFER
 	select IIO_TRIGGERED_BUFFER
+	select MULTIPLEXER
 	help
 	  Say yes here to build support for Analog Devices AD4134 SPI analog to
 	  digital converters (ADC).
drivers/iio/adc/ad4134.c +157 -5

217 lines not on this page · raw message

Signature · 1 line
2.53.0
#32 lore raw

Re: [PATCH v1 09/13] iio: adc: ad4134: Support SPI 4-wire mode

Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:

Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:

New issues:
- [High] The access_mode_lock mutex is declared but never initialized before use.
- [High] Manual deselection of a devres-managed mux state corrupts the mux controller lock.
- [High] The IIO buffer setup callbacks are silently overwritten with NULL, breaking the 4-wire mode data acquisition.
- [High] Error handling flaws in MUX state transitions lead to hardware desync and lock corruption.
- [High] Missing direct mode protection in debugfs register access corrupts the active IIO buffer hardware state.

Pre-existing issues:
- [Critical] Incorrect loop bounds using IIO mask length and array sizes cause buffer overflows and ADC hardware desync.
- [High] DMA buffers rx_buf and tx_buf are not cache-line aligned, sharing a cache line with scan and each other. --

commit 9456cb761dce0c0b24bcfb813fd2681f50469691
Author: Marcelo Schmitt <[email protected]>

iio: adc: ad4134: Support SPI 4-wire mode

AD4134 devices can be wired in a few different ways. So far, only minimum I/O mode was supported. While minimum I/O mode allows interfacing with AD4134 with a reduced number of wires, that wiring configuration is not optimal for high-throughput data acquisition.

Extend AD4134 support to enable interfacing in SPI 4-wire configuration.

Quoted 4 lines
drivers/iio/adc/ad4134.c +0 -0
index 0751b89dec8f3..8453b44ef368f 100644

[ ... ]

Quoted 5 lines
drivers/iio/adc/ad4134.c +1 -0
@@ -154,11 +170,17 @@ struct ad4134_state {
 	struct gpio_desc *odr_gpio;
 	int refin_mv;
 	bool crc_en;
+	enum ad4134_spi_mode spi_mode;

drivers/iio/adc/ad4134.c struct ad4134_state { · line 183

Quoted 10 lines
drivers/iio/adc/ad4134.c +5 -0
+	struct mux_state *mux_st[2];
 	/*
 	 * Synchronize access to members the of driver state, and ensure
 	 * atomicity of consecutive register access operations.
 	 */
 	struct mutex lock;
+	/*
+	 * Ensure atomicity of access mode switch operations.
+	 */
+	struct mutex access_mode_lock;

[Severity: High]
Is access_mode_lock ever initialized before use?

The lock is allocated within struct ad4134_state via devm_iio_device_alloc() (which zero-initializes the memory), but it doesn't appear to be initialized via mutex_init() or devm_mutex_init() in ad4134_probe() before it is used by the new access mode functions. Does this cause a kernel crash or lockdep splat when the guard is invoked in ad4134_set_register_access()?

[Severity: High]
This is a pre-existing issue, but does this code cause a DMA cache coherency violation?

struct ad4134_state {
...

    u32 scan[AD4134_NUM_CHANNELS] __aligned(IIO_DMA_MINALIGN);
    u8 rx_buf[AD4134_SPI_MAX_XFER_LEN];
    u8 tx_buf[AD4134_SPI_MAX_XFER_LEN];
};

While scan is aligned to IIO_DMA_MINALIGN, it is only 16 bytes. Because rx_buf and tx_buf immediately follow it without their own alignment attributes, they occupy the same cache line. When the SPI core maps rx_buf and tx_buf for DMA in ad4134_register_read(), will cache invalidation on the RX buffer silently destroy adjacent CPU writes or DMA buffers residing in the same cache line?

[ ... ]

drivers/iio/adc/ad4134.c static const struct regmap_access_table ad4134_regmap_wr_table = { · line 270

Quoted 9 lines
drivers/iio/adc/ad4134.c +9 -0
+static int ad4134_set_register_access(struct ad4134_state *st)
+{
+	int ret;
+
+	guard(mutex)(&st->access_mode_lock);
+	st->spi->mode = SPI_MODE_0;
+	ret = spi_setup(st->spi);
+	if (ret)
+		return ret;

[Severity: High]
If spi_setup() fails, this returns early. Does this abandon the physical mux in the DOUT0_INPUT state, and bypass the rest of the mux state machine updates?

drivers/iio/adc/ad4134.c static const struct regmap_access_table ad4134_regmap_wr_table = { · line 278

Quoted 8 lines
drivers/iio/adc/ad4134.c +8 -0
+
+	ret = mux_state_deselect(st->mux_st[AD4134_DOUT0_INPUT]);
+	if (ret)
+		dev_err(&st->spi->dev, "error on DOUT0 deselect: %d\n", ret);
+
+	ret = mux_state_try_select(st->mux_st[AD4134_SDO_INPUT]);
+	if (ret && ret != -EBUSY)
+		return ret;

[Severity: High]
If mux_state_try_select() returns -EBUSY, this code ignores the error and returns success (0). Does this incorrectly pretend the lock was acquired when it wasn't, potentially causing a later mux_state_deselect() to corrupt the underlying semaphore?

Quoted 5 lines
drivers/iio/adc/ad4134.c +5 -0
+
+	return 0;
+}
+
+/*

drivers/iio/adc/ad4134.c static const struct regmap_access_table ad4134_regmap_wr_table = { · line 293

Quoted 10 lines
drivers/iio/adc/ad4134.c +10 -0
+ * When AD4134 SDO and DOUT0 pins are multiplexed, this function changes the
+ * multiplexer state to route DOUT0 to the SPI controller. On failure, fall
+ * back to routing SDO to the controller and return an errno.
+ */
+static int ad4134_set_sample_access(struct ad4134_state *st)
+{
+	int ret, ret2;
+
+	guard(mutex)(&st->access_mode_lock);
+	ret = mux_state_deselect(st->mux_st[AD4134_SDO_INPUT]);

[Severity: High]
Does this manual deselection of a devres-managed mux state corrupt the mux controller lock?

In ad4134_probe(), devm_mux_state_get_selected() is used to acquire st->mux_st[AD4134_SDO_INPUT]. That automatically selects the SDO_INPUT state and registers a devres action (devm_mux_state_release) to deselect it on driver unbind.

By manually calling mux_state_deselect() here, will devres unconditionally call mux_state_deselect() again on unbind, invoking up(&mux->lock) on an already-deselected state or on a state currently held by another driver?

drivers/iio/adc/ad4134.c static const struct regmap_access_table ad4134_regmap_wr_table = { · line 300

Quoted 7 lines
drivers/iio/adc/ad4134.c +7 -0
+	if (ret)
+		dev_err(&st->spi->dev, "error on SDO deselect: %d\n", ret);
+
+	ret = mux_state_try_select(st->mux_st[AD4134_DOUT0_INPUT]);
+	if (ret) {
+		dev_err(&st->spi->dev, "error on DOUT0 select: %d\n", ret);
+		return mux_state_select(st->mux_st[AD4134_SDO_INPUT]);

[Severity: High]
By returning the result of mux_state_select() directly, does this overwrite the original failure code with 0 (success)? Will this mask the failure to enter sample access mode, tricking the caller into reading data from the wrong hardware routing?

[ ... ]

Quoted 14 lines

static int ad4134_reg_read(void *context, unsigned int reg, unsigned int *val) {

drivers/iio/adc/ad4134.c +8 -2
 	struct ad4134_state *st = context;
+	int ret, ret2;
 
-	if (reg >= AD4134_CH_VREG(0))
-		return ad4134_data_read(st, reg, val);
+	if (reg >= AD4134_CH_VREG(0)) {
+		if (st->spi_mode == AD4134_SPI_MODE_4_WIRE) {
+			ret = ad4134_set_sample_access(st);
+			if (ret)
+				return ret;
+		}
+

drivers/iio/adc/ad4134.c static int ad4134_register_read(struct ad4134_state *st, unsigned int reg, · line 444

Quoted 10 lines
drivers/iio/adc/ad4134.c +10 -0
+		ret = ad4134_data_read(st, reg, val);
+
+		if (st->spi_mode == AD4134_SPI_MODE_4_WIRE) {
+			ret2 = ad4134_set_register_access(st);
+			if (ret2)
+				dev_err(&st->spi->dev, "access mode error: %d\n", ret2);
+		}
+
+		return ret;
+	}

[Severity: High]
Can this unconditionally restoring register access mode corrupt the hardware state expected by a concurrently active IIO buffer?

The function ad4134_debugfs_reg_access() (which eventually calls this) doesn't claim IIO direct mode. If a user reads a virtual register via debugfs while the IIO buffer is actively streaming, this will call ad4134_set_sample_access() and then unconditionally call ad4134_set_register_access(). Does this forcefully rip the hardware back into SPI_MODE_0 and SDO_INPUT, permanently breaking the active IIO buffer thread which requires SPI_MODE_1 and DOUT0_INPUT?

[Severity: Critical]
This is a pre-existing issue, but do incorrect loop bounds using IIO mask length and array sizes cause buffer overflows and ADC hardware desync?

In ad4134_data_read():

    for (i = 0; i < ARRAY_SIZE(ad4134_chan_set); i++) {
        ret = spi_write_then_read(st->spi, NULL, 0, st->rx_buf, ...

Here, the loop runs ARRAY_SIZE(ad4134_chan_set) (which is 5 due to the soft timestamp channel) times against a physical ADC that only has 4 channels. Does this send invalid extra SPI clocks that desynchronize the ADC?

Also, in ad4134_trigger_handler():

    for (unsigned int ch = 0; ch < iio_get_masklength(indio_dev); ch++) {
        ret = spi_write_then_read(st->spi, NULL, 0, &st->scan[ch], ...

When the timestamp channel is enabled, iio_get_masklength(indio_dev) evaluates to 5. Because st->scan is only sized for AD4134_NUM_CHANNELS (4 elements), does this cause an out-of-bounds write to &st->scan[4], corrupting adjacent fields?

[ ... ]

Quoted 6 lines
drivers/iio/adc/ad4134.c +0 -2
@@ -590,10 +710,42 @@ static int ad4134_probe(struct spi_device *spi)
 		return dev_err_probe(dev, PTR_ERR(st->regmap),
 				     "failed to initialize regmap");
 
-	ret = ad4134_min_io_mode_setup(st);
-	if (ret)

[ ... ]

drivers/iio/adc/ad4134.c static int ad4134_probe(struct spi_device *spi) · line 751

Quoted 10 lines
drivers/iio/adc/ad4134.c +7 -0
+		st->mux_st[AD4134_DOUT0_INPUT] = devm_mux_state_get(dev, "data_read");
+		if (IS_ERR(st->mux_st[AD4134_DOUT0_INPUT]))
+			return dev_err_probe(dev, PTR_ERR(st->mux_st[AD4134_DOUT0_INPUT]),
+					     "failed to get data_read mux-state\n");
+
+		indio_dev->setup_ops = &ad4134_buffer_setup_ops;
+	}
 
 	ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
 					      iio_pollfunc_store_time,

[Severity: High]
Does devm_iio_triggered_buffer_setup() silently overwrite the IIO buffer setup callbacks with NULL, breaking the 4-wire mode data acquisition?

The driver assigns indio_dev->setup_ops = &ad4134_buffer_setup_ops; and then immediately calls devm_iio_triggered_buffer_setup(..., NULL). Because the IIO core macro unconditionally executes indio_dev->setup_ops = setup_ops; inside, does it replace the driver's custom hooks with NULL? If so, the postenable and predisable hooks will never be invoked, preventing the hardware mux from ever switching to DOUT0_INPUT for buffered reads.

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=9
#33 lore raw

Re: [PATCH v1 09/13] iio: adc: ad4134: Support SPI 4-wire mode

In reply to Marcelo Schmitt
Quoted 6 lines · Marcelo Schmitt

AD4134 devices can be wired in a few different ways. So far, only minimum I/O mode was supported. While minimum I/O mode allows interfacing with AD4134 with a reduced number of wires, that wiring configuration is not optimal for high-throughput data acquisition.

Extend AD4134 support to enable interfacing in SPI 4-wire configuration.

...

Quoted 1 line

struct ad4134_state {

I hope on each stage you run pahole to confirm that this is the optimal layout.

Quoted 16 lines
drivers/iio/adc/ad4134.c +6 -0
 	struct gpio_desc *odr_gpio;
 	int refin_mv;
 	bool crc_en;
+	enum ad4134_spi_mode spi_mode;
+	struct mux_state *mux_st[2];
 	/*
 	 * Synchronize access to members the of driver state, and ensure
 	 * atomicity of consecutive register access operations.
 	 */
 	struct mutex lock;
+	/*
+	 * Ensure atomicity of access mode switch operations.
+	 */
+	struct mutex access_mode_lock;
 
 };

...

drivers/iio/adc/ad4134.c static const struct regmap_access_table ad4134_regmap_wr_table = { · line 266

Quoted 5 lines
drivers/iio/adc/ad4134.c +5 -0
+static int ad4134_set_register_access(struct ad4134_state *st)
+{
+	int ret;
+
+	guard(mutex)(&st->access_mode_lock);

+ blank line.

drivers/iio/adc/ad4134.c static const struct regmap_access_table ad4134_regmap_wr_table = { · line 278

Quoted 12 lines
drivers/iio/adc/ad4134.c +11 -0
+	st->spi->mode = SPI_MODE_0;
+	ret = spi_setup(st->spi);
+	if (ret)
+		return ret;
+
+	ret = mux_state_deselect(st->mux_st[AD4134_DOUT0_INPUT]);
+	if (ret)
+		dev_err(&st->spi->dev, "error on DOUT0 deselect: %d\n", ret);
 
+	ret = mux_state_try_select(st->mux_st[AD4134_SDO_INPUT]);
+	if (ret && ret != -EBUSY)
+		return ret;

Reading this without a comment about EBUSY is difficult. Interpreting BUSY as occupied mux channel, why do we return success?

Quoted 2 lines
(quoted diff) +2 -0
+	return 0;
+}

...

drivers/iio/adc/ad4134.c static const struct regmap_access_table ad4134_regmap_wr_table = { · line 289

Quoted 2 lines
drivers/iio/adc/ad4134.c +2 -0
+static int ad4134_set_sample_access(struct ad4134_state *st)
+{
	struct device *dev = &st->spi->dev;

Review

Quoted 1 line
(quoted diff) +1 -0
+	int ret, ret2;

I would go with

	int mux_state_ret;
	int ret;
Quoted 32 lines
drivers/iio/adc/ad4134.c +32 -0
+	guard(mutex)(&st->access_mode_lock);
+	ret = mux_state_deselect(st->mux_st[AD4134_SDO_INPUT]);
+	if (ret)
+		dev_err(&st->spi->dev, "error on SDO deselect: %d\n", ret);
+
+	ret = mux_state_try_select(st->mux_st[AD4134_DOUT0_INPUT]);
+	if (ret) {
+		dev_err(&st->spi->dev, "error on DOUT0 select: %d\n", ret);
+		return mux_state_select(st->mux_st[AD4134_SDO_INPUT]);
+	}
+
+	/*
+	 * Data output on the DOUT lines is sampled on the falling edge
+	 * (SPI mode 1).
+	 */
+	st->spi->mode = SPI_MODE_1;
+	ret = spi_setup(st->spi);
+	if (ret) {
+		dev_err(&st->spi->dev, "failed to setup SPI mode 1: %d\n", ret);
+		ret2 = mux_state_deselect(st->mux_st[AD4134_DOUT0_INPUT]);
+		if (ret2)
+			dev_err(&st->spi->dev, "error on DOUT0 deselect: %d\n", ret2);
+
+		ret2 = mux_state_select(st->mux_st[AD4134_SDO_INPUT]);
+		if (ret2)
+			dev_err(&st->spi->dev, "error on SDO select: %d\n", ret2);
+
+		return ret;
+	}
+
+	return 0;
+}

...

Quoted 11 lines

static int ad4134_reg_read(void *context, unsigned int reg, unsigned int *val) {

drivers/iio/adc/ad4134.c +5 -2
 	struct ad4134_state *st = context;
+	int ret, ret2;
 
-	if (reg >= AD4134_CH_VREG(0))
-		return ad4134_data_read(st, reg, val);
+	if (reg >= AD4134_CH_VREG(0)) {
+		if (st->spi_mode == AD4134_SPI_MODE_4_WIRE) {
+			ret = ad4134_set_sample_access(st);
+			if (ret)

drivers/iio/adc/ad4134.c static int ad4134_register_read(struct ad4134_state *st, unsigned int reg, · line 441

Quoted 10 lines
drivers/iio/adc/ad4134.c +10 -0
+				return ret;
+		}
+
+		ret = ad4134_data_read(st, reg, val);
+
+		if (st->spi_mode == AD4134_SPI_MODE_4_WIRE) {
+			ret2 = ad4134_set_register_access(st);
+			if (ret2)
+				dev_err(&st->spi->dev, "access mode error: %d\n", ret2);
+		}

I would go with duplication of _data_read() call but better flow

		if (...) {
			_set_sample_()
			ret = _data_read();
			_set_register_()
		} else {
			ret = _data_read();
		}
Quoted 2 lines
(quoted diff) +2 -0
+		return ret;
+	}

...

drivers/iio/adc/ad4134.c static int ad4134_probe(struct spi_device *spi) · line 717

Quoted 5 lines
drivers/iio/adc/ad4134.c +5 -0
+	ret = device_property_match_property_string(dev, "adi,spi-mode",
+						    ad4134_spi_modes,
+						    ARRAY_SIZE(ad4134_spi_modes));
+	/* Default to "no-cs" mode if adi,spi-mode is not specified */
+	if (ret == -EINVAL)

No, use device_property_present() instead.

Quoted 7 lines
drivers/iio/adc/ad4134.c +5 -1
+		st->spi_mode = AD4134_SPI_MODE_NO_CS;
+	else if (ret < 0)
 		return dev_err_probe(dev, ret,
-				     "failed to setup minimum I/O mode\n");
+				     "getting adi,spi-mode property failed\n");
+	else
+		st->spi_mode = ret;
Signature · 2 lines
With Best Regards,
Andy Shevchenko
author maintainer
#34 lore raw

PATCH 10/13 dt-bindings: iio: adc: adi,ad4134: Document PWM usage

In reply to Marcelo Schmitt

Advenced setups may connect a PWM signal to AD4134 ODR pin for faster output data rates.

---
 Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml | 4 ++++
 1 file changed, 4 insertions(+)
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +4 -0
index d843c02a394a..34043f89730b 100644
@@ -104,6 +104,10 @@ properties:
       GPIO connected to ODR pin. Used to sample ADC data in minimum I/O mode.
     maxItems: 1
 
+  pwms:
+    description: PWM signal connected to the ODR pin.
+    maxItems: 1
+
   adi,asrc-mode:
     $ref: /schemas/types.yaml#/definitions/string
     description:
Signature · 1 line
2.53.0
author maintainer
#36 lore raw

PATCH 11/13 dt-bindings: iio: adc: adi,ad4134: Add high data throughput example

In reply to Marcelo Schmitt

Add device tree example for AD4134 operation in 4-wire SPI mode with 4 lines to transfer data samples to the host controller.

---
The reason for the input multiplexer is enable both register access and multi-lane read. Before coming to the current solution, we tried the following configuration.

  +-----------------------+                           +-----------------+
  |       AD4134          |                           | SPI Controller  |
  |                       |                           |                 |
  | SPI interface         |                           |                 |
  | for register     SCLK |<--------------------------| SCLK            |
  | access             CS |<--------------------------| CS              |
  |                   SDI |<--------------------------| SDO             |
  |                   SDO |---+                       |                 |
  |                       |   |                       |                 |
  | Data interface  DOUT0 |---+---------------------->| SDI0            |
  | for ADC data    DOUT1 |-------------------------->| SDI1            |
  | read back       DOUT2 |-------------------------->| SDI2            |
  |                 DOUT3 |-------------------------->| SDI3            |
  |                 DCLK  |<--------------------------| DCLK
  |                 ODR   |<------------------+    +->| Offload Trigger |
  +-----------------------+                   |    |  +-----------------+
                                              |    +--| PWM1            |
                                              +-------| PWM0            |
                                              +-------| GPIO            |
                                                      +-----------------+

Though, because DOUT0 never goes high-Z, the DOUT0 pin keeps driving the data line, causing register read to fail (always get 0xFF). Another solution would be to connect SDO to SDI0 and DOUT pins to SDI1, SDI2, SDI3, SDI4. That would then require a special multi-lane mode.

Please, see patch 13 for a better view of how the proposed setup works.

 .../bindings/iio/adc/adi,ad4134.yaml          | 42 +++++++++++++++++++
 1 file changed, 42 insertions(+)
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +42 -0
index 34043f89730b..6f0b4346426a 100644
@@ -214,4 +214,46 @@ examples:
 
         };
     };
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+
+    ad4134_sdo_dout0_mux: mux-controller {
+        compatible = "gpio-mux";
+        #mux-state-cells = <1>;
+        mux-gpios = <&gpio0 100 GPIO_ACTIVE_HIGH>;
+    };
+
+    spi {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        adc@0 {
+            compatible = "adi,ad4134";
+            reg = <0>;
+
+            spi-max-frequency = <1000000>;
+            spi-rx-bus-width = <1>, <1>, <1>, <1>; /* 4 lanes of 1 bit each */
+
+            pwms = <&ad4134_odr_generator 1 1000000 0>;
+            reset-gpios = <&gpio0 86 GPIO_ACTIVE_LOW>;
+            odr-gpios = <&gpio0 87 GPIO_ACTIVE_HIGH>;
+            powerdown-gpios = <&gpio0 88 GPIO_ACTIVE_LOW>;
+
+            clocks = <&sys_clk>;
+            clock-names = "clkin";
+
+            avdd5-supply = <&avdd5>;
+            dvdd5-supply = <&dvdd5>;
+            iovdd-supply = <&iovdd>;
+            refin-supply = <&refin>;
+            avdd1v8-supply = <&avdd1v8>;
+            dvdd1v8-supply = <&dvdd1v8>;
+            clkvdd-supply = <&clkvdd>;
+
+            mux-states = <&ad4134_sdo_dout0_mux 0>, <&ad4134_sdo_dout0_mux 1>;
+            mux-state-names = "data_read", "reg_access";
+
+            adi,spi-mode = "4-wire";
+        };
+    };
 ...
Signature · 1 line
2.53.0
#37 lore raw

Re: [PATCH v1 11/13] dt-bindings: iio: adc: adi,ad4134: Add high data throughput example

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:

New issues:
- [Low] The newly added device tree example includes 'mux-states' and 'mux-state-names' properties, but these are not defined in the schema, causing schema validation to fail.

Pre-existing issues:
- [High] Out-of-bounds array write in ad4134_trigger_handler due to incorrect loop bounds over masklength.
- [High] Timestamp push fails with -ENOSPC because the buffer size passed to iio_push_to_buffers_with_ts is undersized. --

commit 9db0b7d2cda5447620683544f83d4587b18252b7
Author: Marcelo Schmitt <[email protected]>

dt-bindings: iio: adc: adi,ad4134: Add high data throughput example

Add device tree example for AD4134 operation in 4-wire SPI mode with 4 lines to transfer data samples to the host controller.

Quoted 4 lines
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +0 -0
index 34043f89730b2..6f0b4346426a0 100644

[ ... ]

Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml examples: · line 254

Quoted 13 lines
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +13 -0
+            clocks = <&sys_clk>;
+            clock-names = "clkin";
+
+            avdd5-supply = <&avdd5>;
+            dvdd5-supply = <&dvdd5>;
+            iovdd-supply = <&iovdd>;
+            refin-supply = <&refin>;
+            avdd1v8-supply = <&avdd1v8>;
+            dvdd1v8-supply = <&dvdd1v8>;
+            clkvdd-supply = <&clkvdd>;
+
+            mux-states = <&ad4134_sdo_dout0_mux 0>, <&ad4134_sdo_dout0_mux 1>;
+            mux-state-names = "data_read", "reg_access";

[Severity: Low]
Are the mux-states and mux-state-names properties fully documented in the schema definition?

The newly added device tree example includes these properties, but they do not appear to be defined in the schema properties section. Since the schema uses unevaluatedProperties: false, the example will fail schema validation during a dt_binding_check.

Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml examples: · line 258

Quoted 5 lines
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +4 -0
+
+            adi,spi-mode = "4-wire";
+        };
+    };
...

While reviewing this series, I also noticed a couple of pre-existing issues in the driver implementation:

drivers/iio/adc/ad4134.c:ad4134_trigger_handler()
{
[ ... ]

	for (unsigned int ch = 0; ch < iio_get_masklength(indio_dev); ch++) {
		ret = spi_write_then_read(st->spi, NULL, 0, &st->scan[ch],
					  BITS_TO_BYTES(AD4134_CHAN_PRECISION_BITS));

[ ... ]

[Severity: High]
This is a pre-existing issue, but does this loop overflow the st->scan array when the soft timestamp channel is enabled?

The loop unconditionally iterates up to iio_get_masklength(indio_dev). Because the soft timestamp channel is registered with scan_index = 4, the mask length evaluates to 5 whenever the timestamp is enabled.

Since st->scan is an array of size 4, when ch evaluates to 4, spi_write_then_read() will write 3 bytes out-of-bounds to &st->scan[4], corrupting adjacent memory.

[ ... ]

	iio_push_to_buffers_with_ts(indio_dev, &st->scan, sizeof(st->scan),
				    pf->timestamp);

[ ... ]

[Severity: High]
This is a pre-existing issue, but will the statically sized length passed here cause iio_push_to_buffers_with_ts() to fail with -ENOSPC?

The iio_push_to_buffers_with_ts() function requires the buffer size argument to be at least indio_dev->scan_bytes to accommodate all active channels plus the 8-byte timestamp.

The driver statically passes sizeof(st->scan), which is 16 bytes. When 3 or 4 channels plus the timestamp are active, the required size expands to 24 bytes (16 bytes of data + 8 bytes timestamp). This will cause the push to abort, resulting in lost samples.
}

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=11
author maintainer
#38 lore raw

PATCH 12/13 iio: adc: ad4134: Support high-speed data capture

In reply to Marcelo Schmitt

Make use of SPI transfer offloading to speed up data capture, enabling data acquisition at faster sample rates (up to 1.496 MSPS).

---
 drivers/iio/adc/Kconfig  |   5 +
 drivers/iio/adc/ad4134.c | 379 ++++++++++++++++++++++++++++++++++++++-
 2 files changed, 375 insertions(+), 9 deletions(-)
drivers/iio/adc/Kconfig +5 -0
index ef77ee60df4e..369cc0659073 100644
@@ -123,9 +123,14 @@ config AD4130
 config AD4134
 	tristate "Analog Devices AD4134 ADC Driver"
 	depends on SPI
+	depends on PWM
 	select REGMAP_SPI
+	select SPI_OFFLOAD
+	select SPI_OFFLOAD_TRIGGER_PWM
 	select CRC8
 	select IIO_BUFFER
+	select IIO_BUFFER_DMA
+	select IIO_BUFFER_DMAENGINE
 	select IIO_TRIGGERED_BUFFER
 	select MULTIPLEXER
 	help
drivers/iio/adc/ad4134.c +370 -9

463 lines not on this page · raw message

Signature · 1 line
2.53.0
#39 lore raw

Re: [PATCH v1 12/13] iio: adc: ad4134: Support high-speed data capture

Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider: - [Critical] Buffer overflow in `ad4134_trigger_handler` when iterating over the scan mask length. - [High]…

Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [Critical] Buffer overflow in ad4134_trigger_handler when iterating over the scan mask length.
- [High] NULL pointer dereference in ad4134_offload_buffer_postenable error path for AD4134_SPI_MODE_NO_CS.
- [High] Incorrect SPI transfer length in 1-lane offload mode causes buffer format mismatch and data corruption.
- [High] Hardware PWM resource leak on driver unbind due to missing disable action.
- [Medium] Data race on st->odr_hz in ad4134_read_raw due to missing lock.
--

commit d7cbe54fc38bde7020274d75b09e6803ffb16fca
Author: Marcelo Schmitt <[email protected]>

iio: adc: ad4134: Support high-speed data capture

This commit adds support for SPI transfer offloading to speed up data capture, enabling data acquisition at faster sample rates up to 1.496 MSPS.

Quoted 4 lines
drivers/iio/adc/ad4134.c +0 -0
index 8453b44ef368f..cf84d2b24417d 100644

[ ... ]

Quoted 7 lines
drivers/iio/adc/ad4134.c +3 -0
@@ -454,6 +509,90 @@ static const struct regmap_config ad4134_regmap_config = {
 	.max_register = AD4134_CH_VREG(ARRAY_SIZE(ad4134_chan_set)),
 };
 
+static int ad4134_update_conversion_rate(struct ad4134_state *st,
+					 unsigned int freq_Hz)
+{

[ ... ]

drivers/iio/adc/ad4134.c static const struct regmap_config ad4134_regmap_config = { · line 585

Quoted 1 line
drivers/iio/adc/ad4134.c +1 -0
+	ret = pwm_set_waveform_might_sleep(st->odr_pwm, &odr_wf, false);

[Severity: High]
This starts the ODR PWM hardware, but is there a corresponding cleanup action or devm callback registered to stop it on driver unbind? Does this leave the hardware toggling indefinitely if the driver is unbound or if an error occurs during probe?

Quoted 9 lines
drivers/iio/adc/ad4134.c +9 -0
+	if (ret)
+		return ret;
+
+	st->offload_trigger_config = config;
+	st->odr_wf = odr_wf;
+	st->odr_hz = DIV_ROUND_UP_ULL(NSEC_PER_SEC, odr_wf.period_length_ns);
+
+	return 0;
+}

[ ... ]

drivers/iio/adc/ad4134.c static int ad4134_read_raw(struct iio_dev *indio_dev, · line 681

Quoted 7 lines
drivers/iio/adc/ad4134.c +3 -0
@@ -537,6 +676,42 @@ static int ad4134_read_raw(struct iio_dev *indio_dev,
 		*val2 = AD4134_CHAN_PRECISION_BITS - 1;
 
 		return IIO_VAL_FRACTIONAL_LOG2;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		*val = st->odr_hz;
+		return IIO_VAL_INT;

[Severity: Medium]
Is it safe to read st->odr_hz locklessly here? Concurrent writes via ad4134_write_raw() hold st->lock while modifying this value, which could lead to a data race if userspace concurrently reads and writes the sampling frequency sysfs attribute.

Quoted 4 lines
drivers/iio/adc/ad4134.c +4 -0
+	default:
+		return -EINVAL;
+	}
+}

[ ... ]

Quoted 5 lines
drivers/iio/adc/ad4134.c +1 -0
@@ -588,6 +763,176 @@ static const struct iio_info ad4134_info = {
 	.debugfs_reg_access = ad4134_debugfs_reg_access,
 };
 
+static const struct iio_info ad4134_offload_info = {

[ ... ]

drivers/iio/adc/ad4134.c static const struct iio_info ad4134_info = { · line 781

Quoted 9 lines
drivers/iio/adc/ad4134.c +9 -0
+static void ad4134_prepare_offload_msg(struct iio_dev *indio_dev)
+{
+	struct ad4134_state *st = iio_priv(indio_dev);
+	unsigned int base_len = roundup_pow_of_two(BITS_TO_BYTES(AD4134_CHAN_PRECISION_BITS));
+	unsigned int bpw = AD4134_CHAN_PRECISION_BITS;
+
+	st->xfers.cs_off = 1;
+	st->xfers.bits_per_word = bpw;
+	st->xfers.len = base_len * st->spi->num_rx_lanes;

[Severity: High]
Since ad4134_scan_masks statically requires all 4 channels to be present via GENMASK(3, 0), meaning 16 bytes per trigger are required, will this length calculation of just 4 bytes in 1-lane mode cause the DMA to push incomplete frames and corrupt the IIO buffer?

Quoted 10 lines
drivers/iio/adc/ad4134.c +10 -0
+	if (st->spi->num_rx_lanes > 1)
+		st->xfers.multi_lane_mode = SPI_MULTI_LANE_MODE_STRIPE;
+
+	st->xfers.offload_flags = SPI_OFFLOAD_XFER_RX_STREAM;
+
+	spi_message_init_with_transfers(&st->msg, &st->xfers, 1);
+}
+
+static int ad4134_offload_buffer_postenable(struct iio_dev *indio_dev)
+{

[ ... ]

drivers/iio/adc/ad4134.c static const struct iio_info ad4134_info = { · line 818

Quoted 12 lines
drivers/iio/adc/ad4134.c +12 -0
+	ret = spi_offload_trigger_enable(st->offload, st->offload_trigger,
+					 &st->offload_trigger_config);
+	if (ret)
+		goto out_unoptimize;
+
+	return 0;
+
+out_unoptimize:
+	spi_unoptimize_message(&st->msg);
+
+out_set_register_input:
+	ret2 = ad4134_set_register_access(st);

[Severity: High]
If the SPI mode is AD4134_SPI_MODE_NO_CS, the mux control pointer st->mux_st[AD4134_DOUT0_INPUT] is never initialized. When jumping to out_set_register_input on an error path, will ad4134_set_register_access() blindly dereference the NULL mux state when calling mux_state_deselect(st->mux_st[AD4134_DOUT0_INPUT]), crashing the kernel?

Quoted 5 lines
drivers/iio/adc/ad4134.c +5 -0
+	if (ret2)
+		dev_err(&st->spi->dev, "reg input select error: %d\n", ret2);
+
+	return ret;
+}

[ ... ]

Quoted 11 lines
drivers/iio/adc/ad4134.c +1 -6
@@ -747,12 +1089,30 @@ static int ad4134_probe(struct spi_device *spi)
 		indio_dev->setup_ops = &ad4134_buffer_setup_ops;
 	}
 
-	ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
-					      iio_pollfunc_store_time,
-					      ad4134_trigger_handler,
-					      NULL);
-	if (ret)
-		return ret;
+	st->offload = devm_spi_offload_get(dev, spi, &ad4134_offload_config);

drivers/iio/adc/ad4134.c static int ad4134_probe(struct spi_device *spi) · line 1102

Quoted 10 lines
drivers/iio/adc/ad4134.c +10 -0
+	ret = PTR_ERR_OR_ZERO(st->offload);
+	/* Fall back to low speed usage when no SPI offload is available. */
+	if (ret == -ENODEV) {
+		indio_dev->info = &ad4134_info;
+		indio_dev->channels = ad4134_chan_set;
+		indio_dev->num_channels = ARRAY_SIZE(ad4134_chan_set);
+		ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
+						      iio_pollfunc_store_time,
+						      ad4134_trigger_handler,
+						      NULL);

[Severity: Critical]
When falling back to low speed usage, ad4134_chan_set configures 5 channels total (4 data channels plus IIO_CHAN_SOFT_TIMESTAMP). Inside ad4134_trigger_handler(), the code loops up to iio_get_masklength() which will be 5:

for (unsigned int ch = 0; ch < iio_get_masklength(indio_dev); ch++) {
        ret = spi_write_then_read(st->spi, NULL, 0, &st->scan[ch], ...);

But st->scan is only sized for AD4134_NUM_CHANNELS (4 elements). Does this cause an out-of-bounds write for the 5th channel, corrupting memory?

Quoted 3 lines
drivers/iio/adc/ad4134.c +3 -0
+		if (ret)
+			return ret;
+	} else if (ret) {

[ ... ]

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=12
#40 lore raw

Re: [PATCH v1 12/13] iio: adc: ad4134: Support high-speed data capture

In reply to Marcelo Schmitt
Quoted 2 lines · Marcelo Schmitt

Make use of SPI transfer offloading to speed up data capture, enabling data acquisition at faster sample rates (up to 1.496 MSPS).

...

drivers/iio/adc/ad4134.c static const struct regmap_config ad4134_regmap_config = { · line 521

Quoted 10 lines
drivers/iio/adc/ad4134.c +10 -0
+static int ad4134_update_conversion_rate(struct ad4134_state *st,
+					 unsigned int freq_Hz)
+{
+	struct spi_offload_trigger_config config = st->offload_trigger_config;
+	struct pwm_waveform odr_wf = { };
+	u64 offload_period_ns;
+	u64 offload_offset_ns;
+	u64 odr_high_time_ns;
+	unsigned int count;
+	u64 target = 10;

Split assignment and move it closer to its first user.

drivers/iio/adc/ad4134.c static const struct regmap_config ad4134_regmap_config = { · line 534

Quoted 13 lines
drivers/iio/adc/ad4134.c +13 -0
+	int ret;
+
+	if (!in_range(freq_Hz, AD4134_MIN_ODR_FREQ_HZ, AD4134_MAX_ODR_FREQ_HZ))
+		return -ERANGE;
+
+	odr_wf.period_length_ns = DIV_ROUND_UP_ULL(NSEC_PER_SEC, freq_Hz);
+	/*
+	 * Set the PWM duty cycle to keep ODR high for at least minimum required
+	 * time. If the rounded PWM's value is less than the minimum required,
+	 * increase the target value by 10 and attempt to round the waveform
+	 * again, until the minimum (or try count limit) is reached.
+	 */
+	odr_high_time_ns = div64_ul(6ULL * NSEC_PER_SEC, st->sys_clk_hz);
	target = 0;

Review

Quoted 2 lines
(quoted diff) +2 -0
+	count = 100;
+	do {
		target += 10; /* Increment by PWM duty cycle period */

drivers/iio/adc/ad4134.c static const struct regmap_config ad4134_regmap_config = { · line 541

Quoted 6 lines
drivers/iio/adc/ad4134.c +5 -0
+		odr_wf.duty_length_ns = target;
+		ret = pwm_round_waveform_might_sleep(st->odr_pwm, &odr_wf);
+		if (ret)
+			return ret;
 
+		target += 10; /* Increment by PWM duty cycle period */

In the above way I think it clarifies the initial setting to 10.

Shouldn't be target named as target_ns? Can we use odr_wf.duty_length_ns directly?

Quoted 21 lines
drivers/iio/adc/ad4134.c +21 -0
+	} while (count-- && odr_wf.duty_length_ns < odr_high_time_ns);
+
+	/* Check the minimum ODR high time is met */
+	if (odr_wf.duty_length_ns < odr_high_time_ns)
+		return -EDOM;
+
+	if (odr_wf.period_length_ns < 2 * odr_high_time_ns)
+		return -EDOM;
+
+	/*
+	 * Configure SPI offload PWM trigger.
+	 * For gated DCLK, the minimum required time between ODR rising edge
+	 * and DCLK rising edge is the sum of ODR high time and ODR falling
+	 * edge to DCLK rising edge time. Delay the offload trigger for at least
+	 * that amount of time so the ADC sample data will be available when the
+	 * SPI transfer begin.
+	 *
+	 * Use the same period as ODR PWM to avoid timing issues.
+	 * Convert back from period to frequency for the SPI offload API.
+	 */
+	offload_period_ns = odr_wf.period_length_ns;

drivers/iio/adc/ad4134.c static const struct regmap_config ad4134_regmap_config = { · line 572

Quoted 10 lines
drivers/iio/adc/ad4134.c +10 -0
+	config.periodic.frequency_hz = DIV_ROUND_UP_ULL(HZ_PER_GHZ, offload_period_ns);
+	offload_offset_ns = odr_high_time_ns + AD4134_DCLK_RISING_OFFSET_NS;
+	count = 100;
+	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;

Does this need the similar comment as per above?

Quoted 22 lines
drivers/iio/adc/ad4134.c +22 -0
+	} while (count-- && config.periodic.offset_ns < odr_high_time_ns +
+							AD4134_DCLK_RISING_OFFSET_NS);
+
+	/* Check the minimum ODR to DCLK delay is met */
+	if (config.periodic.offset_ns < odr_high_time_ns + AD4134_DCLK_RISING_OFFSET_NS)
+		return -EDOM;
+
+	/* Check the PWM periods remain the same */
+	offload_period_ns = DIV_ROUND_UP_ULL(HZ_PER_GHZ, config.periodic.frequency_hz);
+	if (odr_wf.period_length_ns != offload_period_ns)
+		return -EDOM;
+
+	ret = pwm_set_waveform_might_sleep(st->odr_pwm, &odr_wf, false);
+	if (ret)
+		return ret;
+
+	st->offload_trigger_config = config;
+	st->odr_wf = odr_wf;
+	st->odr_hz = DIV_ROUND_UP_ULL(NSEC_PER_SEC, odr_wf.period_length_ns);
+
+	return 0;
+}

...

drivers/iio/adc/ad4134.c static const struct iio_info ad4134_info = { · line 793

Quoted 4 lines
drivers/iio/adc/ad4134.c +4 -0
+static int ad4134_offload_buffer_postenable(struct iio_dev *indio_dev)
+{
+	struct ad4134_state *st = iio_priv(indio_dev);
+	int ret, ret2;

These ret2:s in the cases of _set_register_() can be named accordingly.

Quoted 29 lines
drivers/iio/adc/ad4134.c +29 -0
+	if (st->spi_mode == AD4134_SPI_MODE_4_WIRE) {
+		ret = ad4134_set_sample_access(st);
+		if (ret)
+			return ret;
+	}
+
+	ad4134_prepare_offload_msg(indio_dev);
+	st->msg.offload = st->offload;
+	ret = spi_optimize_message(st->spi, &st->msg);
+	if (ret)
+		goto out_set_register_input;
+
+	ret = spi_offload_trigger_enable(st->offload, st->offload_trigger,
+					 &st->offload_trigger_config);
+	if (ret)
+		goto out_unoptimize;
+
+	return 0;
+
+out_unoptimize:
+	spi_unoptimize_message(&st->msg);
+
+out_set_register_input:
+	ret2 = ad4134_set_register_access(st);
+	if (ret2)
+		dev_err(&st->spi->dev, "reg input select error: %d\n", ret2);
+
+	return ret;
+}

...

drivers/iio/adc/ad4134.c static const struct iio_info ad4134_info = { · line 887

Quoted 3 lines
drivers/iio/adc/ad4134.c +3 -0
+/* The chip converts and outputs all 4 channels on each sample request */
+static const unsigned long ad4134_scan_masks[] = {
+	GENMASK(3, 0),

IIRC Jonathan wants to see this as BIT(x) | BIT(y) | ... to clarify that each bit is semantically independent.

Quoted 2 lines
drivers/iio/adc/ad4134.c +2 -0
+	0
+};
Signature · 2 lines
With Best Regards,
Andy Shevchenko
author maintainer
#41 lore raw

PATCH 13/13 Docs: iio: Add AD4134

In reply to Marcelo Schmitt

Add initial documentation for the ad4134 IIO driver.

---
 Documentation/iio/ad4134.rst | 128 +++++++++++++++++++++++++++++++++++
 Documentation/iio/index.rst  |   1 +
 MAINTAINERS                  |   1 +
 3 files changed, 130 insertions(+)
 create mode 100644 Documentation/iio/ad4134.rst
Documentation/iio/ad4134.rst new file +128 -0
new file mode 100644
index 000000000000..4e93d670e2db
@@ -0,0 +1,128 @@
+.. SPDX-License-Identifier: GPL-2.0-only
+
+=============
+AD4134 driver
+=============
+
+Device driver for Analog Devices Inc. AD4134 and similar ADCs.
+
+Supported devices
+=================
+
+* `AD4134 <https://www.analog.com/AD4134>`_
+* `AD7134 <https://www.analog.com/AD7134>`_
+
+Wiring connections
+------------------
+
+AD4134 and similar ADCs can operate in a few different wiring configurations.
+Because AD4134 also supports control modes other than through SPI protocol,
+the following pins must be statically set for all of the wiring modes described
+below.
+
++----------------------------+----------------------+--------------------+
+| Pin Function               |         Level        | Description        |
++============================+======================+====================+
+| PIN/SPI                    |         High         | SPI control mode   |
++----------------------------+----------------------+--------------------+
+| MODE                       |         Low          | ASRC slave mode    |
++----------------------------+----------------------+--------------------+
+| DEC0/DCLKI                 |         Low          | DCLK input         |
++----------------------------+----------------------+--------------------+
+| DEC1/DCLKMODE              |         Low          | Gated DCLK         |
++----------------------------+----------------------+--------------------+
+
+Minimum I/O mode
+^^^^^^^^^^^^^^^^
+
+The minimum I/O mode wiring allows AD4134 register and data access with the
+conventional set of SPI bus lines. In this mode, the peripheral CS pin must be
+tied to GND. A possible connection schema that sets AD4134 digital interface for
+minimum I/O mode is::
+
+      +------------+         +-------------+
+      |  AD4134    |         | SPI         |
+      |            |         | Controller  |
+      |       DCLK |<--+     |             |
+      |       SCLK |<--+---- | SCLK        |
+      |        SDI |<--------| SDO         |
+      |        SDO |-------->| SDI         |
+      |        ODR |<--------| GPIO        |
+      |         CS |----+    |             |
+      +------------+    |    +-------------+
+                        V
+                       GND
+
+Set ``adi,spi-mode = "no-cs"`` in device tree to indicate the device is
+connected in minimum I/O wiring configuration.
+
+SPI 4-wire mode - single lane
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The conventional SPI 4-wire configuration except a multiplexer is used to
+select between SDO (for register data) and DOUT0 (for ADC sample data).::
+
+  +-----------------------+                         +-----------------+
+  |         AD4134        |                         | SPI Controller  |
+  |                       |                         |                 |
+  | SPI interface         |                         |                 |
+  | for register     SCLK |<------------------------| SCLK            |
+  | access             CS |<------------------------| CS              |
+  |                   SDI |<------------------------| SDO             |
+  |                   SDO |------->|¯¯¯¯\           |                 |
+  | Data interface        |        |MUX  >--------->| SDI             |
+  | for ADC sample  DOUT0 |------->|____/           |                 |
+  | data read             |          ^              |                 |
+  |                       |          +--------------| GPIO            |
+  |                  DCLK |<------------------------| DCLK            |
+  |                   ODR |<----------------+    +->| Offload Trigger |
+  +-----------------------+                 |    |  +-----------------+
+                                            |    +--| PWM1            |
+                                            +-------| PWM0            |
+                                            +-------| GPIO            |
+                                                    +-----------------+
+
+Set ``adi,spi-mode = "4-wire"`` in device tree to indicate the device is
+connected in SPI 4-wire configuration.
+
+For SPI offload operation, a PWM is connected to the ADC ODR pin. The ``pwms``
+firmware property specifies the PWM that is connected to the ADC. The SPI
+offload will have a ``trigger-sources`` property to indicate the SPI offload
+(PWM) trigger source.
+
+To achieve high sample rates while meeting ADC timing requirements, an offset
+must be added between the rising edges of PWM0 and PWM1 to delay the SPI
+transfer until ADC sample data is available. This requires a specialized PWM
+controller that can provide such an offset.  The `AD4134-FMC HDL project`_, for
+example, can be configured to sample AD4134 at high speed sample rates.
+
+.. _AD4134-FMC HDL project: https://analogdevicesinc.github.io/hdl/projects/ad4134_fmc/index.html
+
+SPI 4-wire mode - multi-lane
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Maximum througput rate can be achieved by reading 4 input lines simultaneously.::
+
+  +-----------------------+                         +-----------------+
+  |         AD4134        |                         | SPI Controller  |
+  |                       |                         |                 |
+  | SPI interface         |                         |                 |
+  | for register     SCLK |<------------------------| SCLK            |
+  | access             CS |<------------------------| CS              |
+  |                   SDI |<------------------------| SDO             |
+  |                   SDO |------->|¯¯¯¯\           |                 |
+  | Data interface        |        |MUX  >--------->| SDI0            |
+  | for ADC sample  DOUT0 |------->|____/<--------- | GPIO            |
+  | data read       DOUT1 |------------------------>| SDI1            |
+  |                 DOUT2 |------------------------>| SDI2            |
+  |                 DOUT3 |------------------------>| SDI3            |
+  |                  DCLK |<------------------------| DCLK            |
+  |                   ODR |<----------------+    +->| Offload Trigger |
+  +-----------------------+                 |    |  +-----------------+
+                                            |    +--| PWM1            |
+                                            +-------| PWM0            |
+                                            +-------| GPIO            |
+                                                    +-----------------+
+
+Each of SDI0 to SDI3 connect to a different SPI controller deserializer
+(``spi-rx-bus-width = <1>, <1>, <1>, <1>``).
Documentation/iio/index.rst +1 -0
index b02b879b053a..e4ec8a05dded 100644
@@ -23,6 +23,7 @@ Industrial I/O Kernel Drivers
    ad4000
    ad4030
    ad4062
+   ad4134
    ad4691
    ad4695
    ad7191
MAINTAINERS +1 -0
index f3be900e5b9d..7b972c1f9833 100644
@@ -1514,6 +1514,7 @@ L:	[email protected]
 S:	Supported
 W:	https://ez.analog.com/linux-software-drivers
 F:	Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml
+F:	Documentation/iio/ad4134.rst
 F:	drivers/iio/adc/ad4134.c
 
 ANALOG DEVICES INC AD4170-4 DRIVER
Signature · 1 line
2.53.0