Skip to contentSkip to conversation

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

PATCH Superseded Marcelo Schmitt 6 participants 40 messages Oct 6 – Oct 17

Subsystems (5)

v4 of 6 Superseded Latest is v6 →

lore
Share & tools
lore

Marcelo Schmitt

author maintainer
#0 lore raw

v4 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.

Minor improvements (introduced before the new features):
- Sign extend sample data.
- Update include list to comply with IWYU principles.
- Serialize single-read operations.
- Run shorter transfers when CRC is disabled.

The updates in v4 are tackles all applicable suggestions from reviewers and from automated tests/reviews/AI.

Change log v3 -> v4:
[device tree]
- Properly specified vendor custom property, avoiding 'too few spaces after comma' warn.
- Correctly restrained the value/number of spi-rx-bus-width lanes for two-channel-chain use case.
- Improved the constraint to also prevent specifying one-channel-chain or two-channel-chain without #daisy-chained-devices.
[IIO]
- Fixed typo in code comment.
- Now grabbing the whole data scan with a single SPI transfer.
- Also request ODR GPIO for 4-wire mode when offload is not available.
- Dropped second driver state mutex (access_lock). Triggered buffer handler is already protected by IIO device mode lock.
- Adjusted PWM approximation loop counter decrement.
- No longer providing IIO channel separate INFO_RAW on offload setup.
- Adjusted in_range() check to not error on maximum sample rate.
- Minor adjust to AD4134 IIO Doc that made that 1 line shorter.

Previous submissions:
v1: https://lore.kernel.org/linux-iio/[email protected]/
v2: https://lore.kernel.org/linux-iio/[email protected]/
v3: https://lore.kernel.org/linux-iio/[email protected]/

Marcelo Schmitt (13):
iio: adc: ad4134: Adjust register map range
iio: adc: ad4134: Sign extend sample data
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
dt-bindings: iio: adc: adi,ad4134: Document external multiplexer usage
iio: adc: ad4134: Support SPI 4-wire mode
dt-bindings: iio: adc: adi,ad4134: Document PWM usage
iio: adc: ad4134: Support high-speed data capture
Docs: iio: Add AD4134

 .../bindings/iio/adc/adi,ad4134.yaml          | 110 ++-
 Documentation/iio/ad4134.rst                  | 127 +++
 Documentation/iio/index.rst                   |   1 +
 MAINTAINERS                                   |   1 +
 drivers/iio/adc/Kconfig                       |   8 +
 drivers/iio/adc/ad4134.c                      | 773 +++++++++++++++++-
 6 files changed, 980 insertions(+), 40 deletions(-)
 create mode 100644 Documentation/iio/ad4134.rst

base-commit: 04434a1d0f311d76b1f15fa987918b471a0b8c6a

Signature · 1 line
2.53.0
author maintainer
#1 lore raw

PATCH v4 1/13 iio: adc: ad4134: Adjust register map range

Due to a off-by-one mistake, privileged users would be able to read from an unsupported register address when reading device registers through a debug interface. Correct the off-by-one mistake at the high register map range to prevent access of unsupported addresses.

Fixes e0bc6d7e2584 ("iio: adc: Initial support for AD4134")

---
No changes in v4.

 drivers/iio/adc/ad4134.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/iio/adc/ad4134.c +2 -2
index 70f80bf1825f..e53c10b9a44a 100644
@@ -111,7 +111,7 @@ 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),
 	regmap_reg_range(AD4134_DEVICE_STATUS_REG, AD4134_AIN_OR_ERROR_REG),
-	regmap_reg_range(AD4134_CH_VREG(0), AD4134_CH_VREG(AD4134_NUM_CHANNELS)),
+	regmap_reg_range(AD4134_CH_VREG(0), AD4134_CH_VREG(AD4134_NUM_CHANNELS - 1)),
 };
 
 static const struct regmap_range ad4134_regmap_wr_range[] = {
@@ -244,7 +244,7 @@ static const struct regmap_config ad4134_regmap_config = {
 	.reg_write = ad4134_reg_write,
 	.rd_table = &ad4134_regmap_rd_table,
 	.wr_table = &ad4134_regmap_wr_table,
-	.max_register = AD4134_CH_VREG(ARRAY_SIZE(ad4134_chan_set)),
+	.max_register = AD4134_CH_VREG(ARRAY_SIZE(ad4134_chan_set) - 1),
 };
 
 static int ad4134_read_raw(struct iio_dev *indio_dev,
Signature · 1 line
2.53.0
author maintainer
#3 lore raw

PATCH v4 2/13 iio: adc: ad4134: Sign extend sample data

In reply to Marcelo Schmitt

Sign extend ADC sample data for correct delivery of negative ADC input difference.

Fixes e0bc6d7e2584 ("iio: adc: Initial support for AD4134")

---
No changes in v4.

 drivers/iio/adc/ad4134.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/iio/adc/ad4134.c +3 -1
index e53c10b9a44a..6fdeb27d7a42 100644
@@ -172,6 +172,7 @@ static int ad4134_data_read(struct ad4134_state *st, unsigned int reg,
 			    unsigned int *val)
 {
 	unsigned int i;
+	u32 sample;
 	int ret;
 
 	/*
@@ -196,8 +197,9 @@ static int ad4134_data_read(struct ad4134_state *st, unsigned int reg,
 		 * Clock out data from all channels to avoid that.
 		 */
 		if (i == AD4134_VREG_CH(reg))
-			*val = get_unaligned_be24(st->rx_buf);
+			sample = get_unaligned_be24(st->rx_buf);
 	}
+	*val = sign_extend32(sample, AD4134_CHAN_PRECISION_BITS - 1);
 
 	return 0;
 }
Signature · 1 line
2.53.0
author maintainer
#7 lore raw

PATCH v4 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 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.

---
No changes in v4.

 drivers/iio/adc/ad4134.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/iio/adc/ad4134.c +3 -3
index 6fdeb27d7a42..4c8adb8efe4e 100644
@@ -14,18 +14,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
author maintainer
#9 lore raw

PATCH v4 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.

---
Change log v3 -> v4:
- Fixed typo in code comment.

 drivers/iio/adc/ad4134.c | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)
drivers/iio/adc/ad4134.c +15 -1
index 4c8adb8efe4e..a0113fff4b71 100644
@@ -7,6 +7,7 @@
 #include <linux/array_size.h>
 #include <linux/bitfield.h>
 #include <linux/bitops.h>
+#include <linux/cleanup.h>
 #include <linux/clk.h>
 #include <linux/crc8.h>
 #include <linux/delay.h>
@@ -15,6 +16,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>
@@ -98,6 +100,11 @@ struct ad4134_state {
 	struct regmap *regmap;
 	unsigned long sys_clk_hz;
 	struct gpio_desc *odr_gpio;
+	/*
+	 * Synchronize access to device state fields and ensure atomicity of
+	 * consecutive register access operations.
+	 */
+	struct mutex sync_lock;
 	int refin_mv;
 	/*
 	 * DMA (thus cache coherency maintenance) requires the transfer buffers
@@ -257,7 +264,9 @@ static int ad4134_read_raw(struct iio_dev *indio_dev,
 	int ret;
 
 	switch (info) {
-	case IIO_CHAN_INFO_RAW:
+	case IIO_CHAN_INFO_RAW: {
+		guard(mutex)(&st->sync_lock);
+
 		gpiod_set_value_cansleep(st->odr_gpio, 1);
 		/*
 		 * For slave mode gated DCLK (data sheet page 11), the minimum
@@ -276,6 +285,7 @@ static int ad4134_read_raw(struct iio_dev *indio_dev,
 			return ret;
 
 		return IIO_VAL_INT;
+	}
 	case IIO_CHAN_INFO_SCALE:
 		*val = st->refin_mv;
 		*val2 = AD4134_CHAN_PRECISION_BITS - 1;
@@ -444,6 +454,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->sync_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
author maintainer
#11 lore raw

PATCH v4 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 a0113fff4b71..85fa16321d74 100644
@@ -106,6 +106,7 @@ struct ad4134_state {
 	 */
 	struct mutex sync_lock;
 	int refin_mv;
+	bool crc_en;
 	/*
 	 * DMA (thus cache coherency maintenance) requires the transfer buffers
 	 * to live in their own cache lines.
@@ -159,7 +160,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;
 
@@ -169,7 +170,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;
@@ -217,7 +218,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;
@@ -232,7 +233,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;
@@ -313,6 +314,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
author maintainer
#16 lore raw

PATCH v4 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.

---
No changes in v4.

 drivers/iio/adc/ad4134.c | 76 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 76 insertions(+)
drivers/iio/adc/ad4134.c +76 -0
index 85fa16321d74..3048e61a3cb1 100644
@@ -63,6 +63,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
 
@@ -80,12 +83,47 @@
 #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[] = {
@@ -115,6 +153,44 @@ 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->sync_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);
+	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);
+	return field_get(mask, reg_val);
+}
+
 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
author maintainer
#18 lore raw

PATCH v4 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.

---
Change log v3 -> v4:
- Now grabbing the whole data scan with a single SPI transfer.

 drivers/iio/adc/Kconfig  |  2 ++
 drivers/iio/adc/ad4134.c | 64 ++++++++++++++++++++++++++++++++++++++--
 2 files changed, 64 insertions(+), 2 deletions(-)
drivers/iio/adc/Kconfig +2 -0
index a802d8ee4dd9..fc7de0bb400a 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 +62 -2

113 lines not on this page · raw message

Signature · 1 line
2.53.0
author maintainer
#23 lore raw

PATCH v4 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.

---
Change log v3 -> v4:
- Properly specified vendor custom property, avoiding 'too few spaces after comma' warn.
- Correctly restrained the value/number of spi-rx-bus-width lanes for two-channel-chain use case.
- Improved the constraint to also prevent specifying one-channel-chain or two-channel-chain without #daisy-chained-devices.

 .../bindings/iio/adc/adi,ad4134.yaml          | 57 ++++++++++++++++---
 1 file changed, 50 insertions(+), 7 deletions(-)
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +50 -7
index ea6d7e026419..970e7adb2405 100644
@@ -131,6 +131,26 @@ 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 ]
+    default: no-cs
+    description: |
+      This property indicates the SPI wiring configuration.
+      * 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.
+
+  '#daisy-chained-devices': true
+
 required:
   - compatible
   - reg
@@ -141,13 +161,36 @@ required:
   - clocks
   - clock-names
 
-oneOf:
-  - required:
-      - ldoin-supply
-  - required:
-      - avdd1v8-supply
-      - dvdd1v8-supply
-      - clkvdd-supply
+allOf:
+  - oneOf:
+      - required:
+          - ldoin-supply
+      - required:
+          - avdd1v8-supply
+          - dvdd1v8-supply
+          - clkvdd-supply
+
+  - oneOf:
+      - required: ['adi,spi-mode', '#daisy-chained-devices']
+        properties:
+          adi,spi-mode:
+            const: one-channel-chain
+          spi-rx-bus-width:
+            const: 1
+      - required: ['adi,spi-mode', '#daisy-chained-devices']
+        properties:
+          adi,spi-mode:
+            const: two-channel-chain
+          spi-rx-bus-width:
+            items:
+              - const: 1
+              - const: 1
+      - properties:
+          '#daisy-chained-devices': false
+          adi,spi-mode:
+            enum:
+              - no-cs
+              - 4-wire
 
 unevaluatedProperties: false
 
Signature · 1 line
2.53.0
author maintainer
#27 lore raw

PATCH v4 9/13 dt-bindings: iio: adc: adi,ad4134: Document external multiplexer usage

In reply to Marcelo Schmitt

The AD4134 design has two data interfaces. One interface allows register access for device configuration while the other (separate interface) provides ADC sample data. One way of handling both peripheral interfaces is to merge them into a single SPI interface by switching between register access and sample access according to device user requests. Though, such solution requires extra hardware, external to the ADC chip. The access mode switch can be done with an external multiplexer selecting either AD4134 SDO or AD4134 DOUT0 to connect to the controller. The external multiplexer becomes part of hardware requested for AD4134 device operation and thus must be provided for operating the peripheral in such merged interface schema. Still, there are alternative ways of handling the two AD4134 data interfaces so the multiplexer is not always required.

---
No changes in v4.

Detailed reasoning for the external multiplexer usage.

Before coming to the current solution, the following configuration was tried.

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

Though, because DOUT0 never goes high-Z, the DOUT0 pin keeps driving the data line, causing register reads to fail.

Alternatively, we could have something like

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

The downside of the above is the peripheral would need fine-grained config of controller SDI lines to only read SDI0 for register access, and only read SDI1, SDI2, SDI3, SDI4 for ADC sample data (currently available SPI_MULTI_LANE_MODE_STRIPE reads from all SDI lines).

The currently proposed solution looks like the following

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

By being able to mux between AD4134 SDO and AD4134 DOUT0, the peripheral can be connected to a single bus such that controllers able to read from multiple lines will be able to gather ADC sample data from all SDI lines (SPI_MULTI_LANE_MODE_STRIPE). With that, AD4134 maximum data throughput can be supported with what is already available from the SPI core. See additional details on the AD4134 IIO documentation (patch 15).

Yet another possibility would be to have the peripheral sitting in two buses.

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

That may be a fallback option if what's currently being proposed fails to comply to Linux code standards.

 .../bindings/iio/adc/adi,ad4134.yaml          | 47 +++++++++++++++++++
 1 file changed, 47 insertions(+)
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +47 -0
index 970e7adb2405..c70b9113cd67 100644
@@ -104,6 +104,20 @@ properties:
       GPIO connected to ODR pin. Used to sample ADC data in minimum I/O mode.
     maxItems: 1
 
+  mux-states:
+    description:
+      mux controller node to route SDO and DOUT0 signals from peripheral to
+      controller.
+    maxItems: 2
+
+  mux-state-names:
+    description:
+      mux state names for routing SDO and DOUT0 signals from peripheral to
+      controller.
+    items:
+      - const: data_read
+      - const: reg_access
+
   adi,asrc-mode:
     $ref: /schemas/types.yaml#/definitions/string
     description:
@@ -231,4 +245,37 @@ examples:
 
         };
     };
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+
+    spi {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        adc@0 {
+            compatible = "adi,ad4134";
+            reg = <0>;
+
+            spi-max-frequency = <1000000>;
+
+            reset-gpios = <&gpio0 86 GPIO_ACTIVE_LOW>;
+            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
author maintainer
#29 lore raw

PATCH v4 10/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 suitable for high-throughput data acquisition.

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

---
Change log v3 -> v4:
- Also request ODR GPIO for 4-wire mode when offload is not available.
- Dropped second driver state mutex (access_lock). Triggered buffer handler is already protected by IIO device mode lock.

Detailed reasoning for the external multiplexer usage.

Before coming to the current solution, the following configuration was tried.

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

Though, because DOUT0 never goes high-Z, the DOUT0 pin keeps driving the data line, causing register reads to fail.

Alternatively, we could have something like

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

The downside of the above is the peripheral would need fine-grained config of controller SDI lines to only read SDI0 for register access, and only read SDI1, SDI2, SDI3, SDI4 for ADC sample data (currently available SPI_MULTI_LANE_MODE_STRIPE reads from all SDI lines).

The currently proposed solution looks like the following

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

By being able to mux between AD4134 SDO and AD4134 DOUT0, the peripheral can be connected to a single bus such that controllers able to read from multiple lines will be able to gather ADC sample data from all SDI lines (SPI_MULTI_LANE_MODE_STRIPE). With that, AD4134 maximum data throughput can be supported with what is already available from the SPI core. See additional details on the AD4134 IIO documentation (patch 15).

Yet another possibility would be to have the peripheral sitting in two buses.

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

That may be a fallback option if what's currently being proposed fails to comply to Linux code standards.

 drivers/iio/adc/Kconfig  |   1 +
 drivers/iio/adc/ad4134.c | 222 ++++++++++++++++++++++++++++++++++++---
 2 files changed, 206 insertions(+), 17 deletions(-)
drivers/iio/adc/Kconfig +1 -0
index fc7de0bb400a..21bb16f66bc9 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 +205 -17

322 lines not on this page · raw message

Signature · 1 line
2.53.0
author maintainer
#35 lore raw

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

In reply to Marcelo Schmitt

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

---
No changes in v4.

 Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml | 6 ++++++
 1 file changed, 6 insertions(+)
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +6 -0
index c70b9113cd67..6a190b7a9311 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
+
   mux-states:
     description:
       mux controller node to route SDO and DOUT0 signals from peripheral to
@@ -257,9 +261,11 @@ examples:
             reg = <0>;
 
             spi-max-frequency = <1000000>;
+            spi-rx-bus-width = <1>, <1>, <1>, <1>; /* 4 lanes of 1 bit each */
 
             reset-gpios = <&gpio0 86 GPIO_ACTIVE_LOW>;
             powerdown-gpios = <&gpio0 88 GPIO_ACTIVE_LOW>;
+            pwms = <&ad4134_odr_generator 1 1000000 0>;
 
             clocks = <&sys_clk>;
             clock-names = "clkin";
Signature · 1 line
2.53.0
author maintainer
#37 lore raw

PATCH v4 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).

---
Change log v3 -> v4:
- Adjusted PWM approximation loop counter decrement.
- No longer providing IIO channel separate INFO_RAW on offload setup.
- Adjusted in_range() check to not error on maximum sample rate.

 drivers/iio/adc/Kconfig  |   5 +
 drivers/iio/adc/ad4134.c | 391 +++++++++++++++++++++++++++++++++++++--
 2 files changed, 383 insertions(+), 13 deletions(-)
drivers/iio/adc/Kconfig +5 -0
index 21bb16f66bc9..c5b321b5f4d8 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 +378 -13

488 lines not on this page · raw message

Signature · 1 line
2.53.0
author maintainer
#39 lore raw

PATCH v4 13/13 Docs: iio: Add AD4134

In reply to Marcelo Schmitt

Add initial documentation for the ad4134 IIO driver.

---
Change log v3 -> v4:
- Minor adjust to AD4134 IIO Doc that made the doc 1 line shorter.

 Documentation/iio/ad4134.rst | 127 +++++++++++++++++++++++++++++++++++
 Documentation/iio/index.rst  |   1 +
 MAINTAINERS                  |   1 +
 3 files changed, 129 insertions(+)
 create mode 100644 Documentation/iio/ad4134.rst
Documentation/iio/ad4134.rst new file +127 -0
new file mode 100644
index 000000000000..c0889a21cd77
@@ -0,0 +1,127 @@
+.. 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    SCLK |<------------------------| SCLK            |
+  | for register       CS |<------------------------| CS              |
+  | access            SDI |<------------------------| SDO             |
+  |                   SDO |------->|¯¯¯¯\           |                 |
+  |                       |        |MUX  >--------->| SDI             |
+  | Data interface DOUT0  |------->|____/           |                 |
+  | for ADC sample        |          ^              |                 |
+  | data read             |          |              |                 |
+  |                  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 throughput rate can be achieved by reading 4 input lines simultaneously.::
+
+  +-----------------------+                         +-----------------+
+  |         AD4134        |                         | SPI Controller  |
+  |                       |                         |                 |
+  | SPI interface    SCLK |<------------------------| SCLK            |
+  | for register       CS |<------------------------| CS              |
+  | access            SDI |<------------------------| SDO             |
+  |                   SDO |------->|¯¯¯¯\           |                 |
+  |                       |        |MUX  >--------->| SDI0            |
+  | Data interface  DOUT0 |------->|____/           |                 |
+  | for ADC sample        |          ^              |                 |
+  | 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 d0fb32f4b80f..3a49e08a2366 100644
@@ -23,6 +23,7 @@ Industrial I/O Kernel Drivers
    ad4000
    ad4030
    ad4062
+   ad4134
    ad4691
    ad4695
    ad7191
MAINTAINERS +1 -0
index 3a2dfd1a4fd8..82a810ac788e 100644
@@ -1533,6 +1533,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
#36 lore raw

Re: [PATCH v4 11/13] dt-bindings: iio: adc: adi,ad4134: Document PWM usage

In reply to Marcelo Schmitt
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Low] dt-bindings: missing mutual exclusivity between pwms and odr-gpios --

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] dt-bindings: missing mutual exclusivity between pwms and odr-gpios --

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

dt-bindings: iio: adc: adi,ad4134: Document PWM usage

This patch updates the AD4134 binding schema to document the use of a PWM signal connected to the ODR pin for faster output data rates. It adds the pwms property to the device tree bindings.

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

Quoted 11 lines
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +3 -0
index c70b9113cd677..6a190b7a93114 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

[Severity: Low]
Does the schema allow specifying both pwms and odr-gpios simultaneously?

Since both properties describe a physical connection driving the exact same ODR pin on the AD4134, specifying both in a device tree could result in an invalid hardware state.

Should a oneOf or not constraint be added to the schema to enforce mutual exclusivity between pwms and odr-gpios?

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

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

In reply to Marcelo Schmitt
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Low] dt-bindings: invalid and incomplete constraints for spi-rx-bus-width --

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] dt-bindings: invalid and incomplete constraints for spi-rx-bus-width --

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

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

This commit updates the AD4134 device tree bindings to document different SPI connection modes. It introduces the adi,spi-mode and #daisy-chained-devices properties along with corresponding constraints for different wiring configurations.

Quoted 4 lines
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +0 -0
index ea6d7e0264190..970e7adb2405b 100644

[ ... ]

Quoted 12 lines
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +1 -7
@@ -141,13 +161,36 @@ required:
   - clocks
   - clock-names
 
-oneOf:
-  - required:
-      - ldoin-supply
-  - required:
-      - avdd1v8-supply
-      - dvdd1v8-supply
-      - clkvdd-supply
+allOf:

Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml required: · line 174

Quoted 10 lines
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +10 -0
+  - oneOf:
+      - required:
+          - ldoin-supply
+      - required:
+          - avdd1v8-supply
+          - dvdd1v8-supply
+          - clkvdd-supply
+
+  - oneOf:
+      - required: ['adi,spi-mode', '#daisy-chained-devices']

[Severity: Low]
Neither chain configuration includes spi-rx-bus-width in the required list.

Since JSON Schema property constraints only evaluate when the property is present, omitting spi-rx-bus-width from a chain node bypasses the hardware constraint.

Should spi-rx-bus-width be added to the required lists so the SPI controller doesn't silently initialize with a single receive lane?

Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml required: · line 179

Quoted 5 lines
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +5 -0
+        properties:
+          adi,spi-mode:
+            const: one-channel-chain
+          spi-rx-bus-width:
+            const: 1

[Severity: Low]
Because the core SPI bindings define spi-rx-bus-width as a uint32-array, evaluating a device tree value (such as <1>, parsed internally as the JSON array [1]) against a scalar causes a strict type mismatch.

Could this falsely reject valid configurations during dt_binding_check?

Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml required: · line 187

Quoted 8 lines
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +8 -0
+      - required: ['adi,spi-mode', '#daisy-chained-devices']
+        properties:
+          adi,spi-mode:
+            const: two-channel-chain
+          spi-rx-bus-width:
+            items:
+              - const: 1
+              - const: 1

[Severity: Low]
This array items constraint validates the first two lanes, but it lacks bounds checks.

Does this need minItems: 2 and maxItems: 2 to properly restrict the overall length of the array?

Quoted 6 lines
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +6 -0
+      - properties:
+          '#daisy-chained-devices': false
+          adi,spi-mode:
+            enum:
+              - no-cs
+              - 4-wire
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=8
#28 lore raw

Re: [PATCH v4 09/13] dt-bindings: iio: adc: adi,ad4134: Document external multiplexer usage

In reply to Marcelo Schmitt
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Low] iio: redundant use of sync_lock mutex --

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] iio: redundant use of sync_lock mutex
--

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

iio: adc: ad4134: Support buffered data read

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.

Quoted 4 lines
drivers/iio/adc/ad4134.c +0 -0
index 3048e61a3cb13..b5207f16054e4 100644

[ ... ]

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

Quoted 9 lines
drivers/iio/adc/ad4134.c +4 -0
@@ -342,6 +391,10 @@ static int ad4134_read_raw(struct iio_dev *indio_dev,
 
 	switch (info) {
 	case IIO_CHAN_INFO_RAW: {
+		IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim);
+		if (IIO_DEV_ACQUIRE_FAILED(claim))
+			return -EBUSY;
+
 		guard(mutex)(&st->sync_lock);

[Severity: Low]
Is the st->sync_lock mutex still needed here?

Because the IIO direct mode macro inherently acquires the global indio_dev->mlock, it already serializes callbacks like ad4134_read_raw(), ad4134_write_raw(), and ad4134_set_filter_type() against each other, and prevents execution while the buffer is active.

Since st->sync_lock is always acquired immediately after successfully calling IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim) in these locations, it doesn't seem to provide any additional synchronization.

Could st->sync_lock be removed to reduce locking overhead and complexity?

Quoted 2 lines
drivers/iio/adc/ad4134.c +0 -0
 		gpiod_set_value_cansleep(st->odr_gpio, 1);
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=9
#12 lore raw

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

In reply to Marcelo Schmitt
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: - [Medium] iio: adc: ad4134: broken SPI read CRC calculation and ignored failures - [Medium] iio: adc…

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] iio: adc: ad4134: broken SPI read CRC calculation and ignored failures
- [Medium] iio: adc: missing delay after reset deassertion in probe
--

commit 5284b96efc125640c497213951d3fabe580894ec
Author: Marcelo Schmitt <[email protected]>

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

This commit conditionally reduces the SPI transfer length when the AD4134 CRC feature is disabled. It introduces a crc_en flag in the driver state to skip the CRC validation check and send fewer bytes when CRC is inactive.

Quoted 4 lines
drivers/iio/adc/ad4134.c +0 -0
index a0113fff4b715..85fa16321d744 100644

[ ... ]

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

Quoted 9 lines
drivers/iio/adc/ad4134.c +1 -1
@@ -232,7 +233,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;

[Severity: Medium]
Does this CRC validation logic reliably verify the read data?

In ad4134_register_read(), the master's CRC (st->tx_buf[2]) is computed using the command byte and a dummy payload (0x00). However, the slave returns its CRC (st->rx_buf[2]) computed over the command byte and the actual register value being read (st->rx_buf[1]). Comparing st->rx_buf[2] != st->tx_buf[2] will spuriously fail for any read where the register value is non-zero.

Additionally, both the read and write paths merely log a dev_dbg() message on CRC mismatch and return success (0) instead of returning an error code (such as -EIO). Can this allow corrupted data to be used by the caller, rendering the CRC feature ineffective for data integrity?

[ ... ]

drivers/iio/adc/ad4134.c static int ad4134_min_io_mode_setup(struct ad4134_state *st) · line 318

Quoted 6 lines
drivers/iio/adc/ad4134.c +1 -0
@@ -313,6 +314,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);

[Severity: Medium]
Does the AD4134 device require a stabilization delay before interacting with it over SPI?

In ad4134_probe(), devm_reset_control_get_optional_exclusive_deasserted() is called to deassert the reset line. Execution then proceeds directly to regmap initialization and SPI transfers without any hardware stabilization delay:

	rst = devm_reset_control_get_optional_exclusive_deasserted(dev, NULL);
	if (IS_ERR(rst))
		return dev_err_probe(dev, PTR_ERR(rst),
				     "failed to get and deassert reset\n");

	crc8_populate_msb(ad4134_spi_crc_table, AD4134_SPI_CRC_POLYNOM);

	ret = devm_mutex_init(dev, &st->sync_lock);
	if (ret)
		return ret;

	st->regmap = devm_regmap_init(dev, NULL, st, &ad4134_regmap_config);

Without a delay, could the first SPI transactions during probe drop or return invalid data, causing initialization to fail?

The driver defines AD4134_RESET_TIME_US as 10 seconds (10 * USEC_PER_SEC) but never uses it to invoke any sleep function.

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

Re: [PATCH v4 02/13] iio: adc: ad4134: Sign extend sample data

In reply to Marcelo Schmitt
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Low] build: -Wmaybe-uninitialized warning for conditionally assigned 'sample' --

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] build: -Wmaybe-uninitialized warning for conditionally assigned 'sample' --

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

iio: adc: ad4134: Sign extend sample data

Sign extend ADC sample data for correct delivery of negative ADC input difference.

Quoted 13 lines
drivers/iio/adc/ad4134.c +1 -0
index e53c10b9a44a9..6fdeb27d7a42b 100644
@@ -172,6 +172,7 @@ static int ad4134_data_read(struct ad4134_state *st, unsigned int reg,
 			    unsigned int *val)
 {
 	unsigned int i;
+	u32 sample;
 	int ret;
 
 	/*

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

Quoted 7 lines
drivers/iio/adc/ad4134.c +2 -1
@@ -196,8 +197,9 @@ static int ad4134_data_read(struct ad4134_state *st, unsigned int reg,
 		 * Clock out data from all channels to avoid that.
 		 */
 		if (i == AD4134_VREG_CH(reg))
-			*val = get_unaligned_be24(st->rx_buf);
+			sample = get_unaligned_be24(st->rx_buf);
 	}
+	*val = sign_extend32(sample, AD4134_CHAN_PRECISION_BITS - 1);
                             ^^^^^^

[Severity: Low]
Does this code trigger a -Wmaybe-uninitialized compiler warning?

The local variable sample is declared without initialization and is only assigned conditionally if i == AD4134_VREG_CH(reg). While the regmap core strictly validates reg before invoking the read callback, the compiler analyzes ad4134_data_read() locally and cannot statically deduce this external bounds guarantee.

Consequently, the compiler evaluates a theoretical path where the condition is never met, leaving sample unassigned before it is passed to sign_extend32().

This can cause build failures in kernel configurations with CONFIG_WERROR enabled. Explicitly initializing u32 sample = 0; or unconditionally performing the sign extension inside the if block would resolve this.

Quoted 3 lines
drivers/iio/adc/ad4134.c +0 -0
 	return 0;
 }
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
#30 lore raw

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

In reply to Marcelo Schmitt
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider: - [High] iio: ad4134: deadlock during probe due to recursive multiplexer locking in NO_CS mode - [High]…

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] iio: ad4134: deadlock during probe due to recursive multiplexer locking in NO_CS mode
- [High] iio: adc: ad4134: debugfs reg access corrupts SPI mode during active capture
- [Medium] iio: ad4134: SPI mode state becomes permanently desynchronized on spi_setup() failure --

commit f0535fb17ce60953154f2703e6049afff8114c19
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 suitable 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 b5207f16054e4..debc2ff027051 100644

[ ... ]

Quoted 15 lines
drivers/iio/adc/ad4134.c +11 -0
@@ -226,6 +244,85 @@ static const struct regmap_access_table ad4134_regmap_wr_table = {
 	.n_yes_ranges = ARRAY_SIZE(ad4134_regmap_wr_range),
 };
 
+/*
+ * When operating in modes other than minimum I/O mode, AD4134 register data on
+ * the SDO line is sampled on SCLK rising edge (SPI mode 0). In addition to
+ * that, when AD4134 SDO and DOUT0 pins are multiplexed by hardware OUTSIDE
+ * AD4134 SILICON, the multiplexer state must be set to route SDO to the SPI
+ * controller. With both SPI mode and multiplexer state properly set, register
+ * access runs as usual. Successful calls to this function must be balanced with
+ * calls to ad4134_release_reg_access() so to release the mux state lock. See
+ * AD4134 IIO documentation for details.
+ */
+static int ad4134_claim_reg_access(struct ad4134_state *st)

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

Quoted 10 lines
drivers/iio/adc/ad4134.c +10 -0
+{
+	unsigned int cur_mode = st->spi->mode & SPI_MODE_X_MASK;
+	int ret;
+
+	if (st->spi_mode != AD4134_SPI_MODE_NO_CS && cur_mode != SPI_MODE_0) {
+		st->spi->mode &= ~SPI_MODE_X_MASK;
+		st->spi->mode |= SPI_MODE_0;
+		ret = spi_setup(st->spi);
+		if (ret)
+			return ret;

[Severity: Medium]
If spi_setup() fails here, we return the error but st->spi->mode remains modified. On subsequent calls, cur_mode != SPI_MODE_0 will evaluate to false because the cached mode reflects the requested state.

Can this cause the driver to bypass spi_setup() on subsequent calls and attempt to communicate with the device while the SPI hardware remains incorrectly configured?

[Severity: High]
Can ad4134_debugfs_reg_access() execute concurrently with the active triggered buffer capture?

ad4134_debugfs_reg_access() performs register operations without acquiring the IIO direct mode lock. If executed concurrently with an active capture, it will call ad4134_claim_reg_access() which modifies st->spi->mode and calls spi_setup() without protection.

This abruptly alters the SPI hardware configuration while ad4134_trigger_handler() is actively executing spi_sync_transfer(), corrupting the ADC data stream and SPI transaction state.

Furthermore, if the "reg_access" and "data_read" mux states belong to different hardware mux-controllers, the mux_state_select() call will not block, causing concurrent, unprotected use of st->tx_buf and st->rx_buf across threads.

Quoted 7 lines
drivers/iio/adc/ad4134.c +7 -0
+	}
+
+	if (st->mux_st[AD4134_SDO_INPUT])
+		return mux_state_select(st->mux_st[AD4134_SDO_INPUT]);
+
+	return 0;
+}

[ ... ]

Quoted 1 line
drivers/iio/adc/ad4134.c +0 -0
@@ -594,10 +728,64 @@ static int ad4134_probe(struct spi_device *spi)

[ ... ]

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

Quoted 11 lines
drivers/iio/adc/ad4134.c +11 -0
+	if (st->spi_mode == AD4134_SPI_MODE_NO_CS) {
+		/*
+		 * The support hardware for AD4134 may have a multiplexer for
+		 * selecting between AD4134 SDO and AD4134 DOUT0. If that mux
+		 * is set but the user still wants to run AD4134 in minimum I/O
+		 * mode, then DOUT0 is not used and the multiplexer OUTSIDE OF
+		 * AD4134 SILICON must be set to select AD4134 SDO. See AD4134
+		 * IIO documentation for details.
+		 */
+		st->mux_st[AD4134_SDO_INPUT] =
+			devm_mux_state_get_optional_selected(dev, "reg_access");

[Severity: High]
Does this cause a deadlock during device probe in NO_CS mode?

Here the driver acquires and permanently selects the SDO multiplexer via devm_mux_state_get_optional_selected(), which acquires the multiplexer's non-recursive semaphore.

Immediately after, probe calls ad4134_min_io_mode_setup(), which writes to device registers via regmap_update_bits(). This triggers the following call chain:

ad4134_min_io_mode_setup()
regmap_update_bits()

    ad4134_reg_write()
      ad4134_claim_reg_access()

ad4134_claim_reg_access() unconditionally calls mux_state_select(), which will attempt to acquire the exact same semaphore already held by the current task, causing a deadlock.

Furthermore, ad4134_release_reg_access() then unconditionally calls mux_state_deselect(), which would prematurely release the probe-acquired lock.

Quoted 10 lines
drivers/iio/adc/ad4134.c +10 -0
+		if (IS_ERR(st->mux_st[AD4134_SDO_INPUT]))
+			return dev_err_probe(dev, PTR_ERR(st->mux_st[AD4134_SDO_INPUT]),
+					     "failed to get reg_access mux-state\n");
+
+		ret = ad4134_min_io_mode_setup(st);
+		if (ret)
+			return dev_err_probe(dev, ret,
+					     "failed to setup minimum I/O mode\n");
+	} else {
+		/*
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=10
#38 lore raw

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

In reply to Marcelo Schmitt
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider: - [High] ad4134: ODR PWM is left running on probe failure and device unbind - [High] iio: adc: ad4134…

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] ad4134: ODR PWM is left running on probe failure and device unbind
- [High] iio: adc: ad4134: debugfs_reg_access corrupts active SPI offload capture
- [Low] ad4134: Incorrect macro HZ_PER_GHZ used for nanosecond time math
--

commit 646edf6c83770fad0c88592b752978f3561b3e9e
Author: Marcelo Schmitt <[email protected]>
Subject: iio: adc: ad4134: Support high-speed data capture

This commit implements SPI transfer offloading for the AD4134 ADC. It enables faster data acquisition at sample rates up to 1.496 MSPS.

Quoted 4 lines
drivers/iio/adc/ad4134.c +0 -0
index debc2ff027051..aa8abe5715c4b 100644

[ ... ]

Quoted 4 lines
drivers/iio/adc/ad4134.c +3 -0
@@ -517,6 +522,92 @@ ...
+static int ad4134_update_conversion_rate(struct ad4134_state *st,
+					 unsigned int freq_Hz)
+{

[ ... ]

Quoted 3 lines
drivers/iio/adc/ad4134.c +3 -0
+	/*
+	 * Configure SPI offload PWM trigger.
+	 * For gated DCLK, the minimum required time between ODR rising edge

[ ... ]

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

Quoted 3 lines
drivers/iio/adc/ad4134.c +3 -0
+	 */
+	offload_period_ns = odr_wf.period_length_ns;
+	config.periodic.frequency_hz = DIV_ROUND_UP_ULL(HZ_PER_GHZ, offload_period_ns);

[Severity: Low]
This isn't a bug, but should this use NSEC_PER_SEC instead of HZ_PER_GHZ?

While both macros are numerically identical, the calculation here is dividing by a period in nanoseconds to get a frequency in Hertz, so NSEC_PER_SEC seems to be the semantically correct unit scaling factor to use here.

[ ... ]

drivers/iio/adc/ad4134.c ... · line 791

Quoted 6 lines
drivers/iio/adc/ad4134.c +5 -0
@@ -606,6 +787,166 @@ ...
+static const struct iio_info ad4134_offload_info = {
+	.read_raw = ad4134_read_raw,
+	.read_avail = ad4134_read_avail,
+	.write_raw = ad4134_write_raw,
+	.debugfs_reg_access = ad4134_debugfs_reg_access,

[Severity: High]
Can this corrupt an ongoing SPI offload capture?

It looks like ad4134_debugfs_reg_access() issues regmap_read() and regmap_write() operations without calling iio_device_claim_direct_mode(). If a privileged user accesses direct_reg_access via debugfs while an offload engine is actively streaming data, this could dynamically alter the SPI controller mode to SPI_MODE_0 and shift the pin mux.

Since ad4134_release_reg_access() does not restore the SPI mode to SPI_MODE_1, would this permanently corrupt the capture stream until it is restarted?

Quoted 1 line
drivers/iio/adc/ad4134.c +1 -0
+};

[ ... ]

Quoted 11 lines
drivers/iio/adc/ad4134.c +11 -0
+static int ad4134_offload_setup(struct iio_dev *indio_dev, struct ad4134_state *st)
+{
+	struct device *dev = &st->spi->dev;
+	int ret;
+
+	ret = ad4134_pwm_get(st);
+	if (ret)
+		return ret;
+
+	ret = ad4134_offload_buffer_setup(indio_dev, st->spi);
+	if (ret)

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

Quoted 10 lines
drivers/iio/adc/ad4134.c +10 -0
+		return ret;
+
+	/*
+	 * Start with a sampling rate slower than 374 kSPS because that is the
+	 * maximum rate supported with wideband filter (default on power up).
+	 */
+	st->odr_hz = 250 * HZ_PER_KHZ;
+	ret = ad4134_update_conversion_rate(st, st->odr_hz);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to set sampling freq\n");

[Severity: High]
Will the ODR PWM be left running if probe fails later or the device is unbound?

The call to ad4134_update_conversion_rate() actively starts the PWM generation by calling pwm_set_waveform_might_sleep(). The PWM is acquired via devm_pwm_get() earlier in ad4134_offload_setup(), so devres will call pwm_put() during cleanup. However, pwm_put() only frees the software resource and does not stop the physical PWM output.

Should there be a devm_add_action_or_reset() handler registered to explicitly disable the PWM or set the duty cycle to zero on teardown?

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

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

In reply to Marcelo Schmitt
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider: - [High] iio: data race on rx_buf between trigger handler and regmap debugfs - [Medium] iio: stack memory…

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] iio: data race on rx_buf between trigger handler and regmap debugfs
- [Medium] iio: stack memory leak via regmap due to ARRAY_SIZE(ad4134_chan_set) increase
- [Medium] iio: adc: ad4134: DMA buffers rx_buf and tx_buf share the same cacheline --

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

iio: adc: ad4134: Support buffered data read

This commit enables buffered data captures triggered by the IIO trigger device and adds an IIO timestamp channel. It also requires single-read operations to be in IIO device direct access mode to prevent buffered and single-shot captures from disrupting each other.

Quoted 14 lines
drivers/iio/adc/ad4134.c +1 -0
index 3048e61a3cb13..b5207f16054e4 100644
[ ... ]
@@ -131,6 +141,7 @@ static const struct iio_chan_spec ad4134_chan_set[] = {
 	AD4134_CHANNEL(1),
 	AD4134_CHANNEL(2),
 	AD4134_CHANNEL(3),
+	IIO_CHAN_SOFT_TIMESTAMP(4),
 };
 
 struct ad4134_state {

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

Quoted 7 lines
drivers/iio/adc/ad4134.c +1 -1
@@ -149,7 +160,7 @@ 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);
+	u8 rx_buf[AD4134_SPI_MAX_XFER_LEN * AD4134_NUM_CHANNELS] __aligned(IIO_DMA_MINALIGN);
 	u8 tx_buf[AD4134_SPI_MAX_XFER_LEN];
 };

[Severity: Medium]
Do tx_buf and rx_buf end up sharing the same cacheline here?

Because rx_buf is only 12 bytes long (assuming AD4134_SPI_MAX_XFER_LEN is 3 and AD4134_NUM_CHANNELS is 4), tx_buf will be placed immediately after it at offset 12. Since tx_buf lacks __aligned(IIO_DMA_MINALIGN), they will occupy the same cacheline.

If the CPU writes to tx_buf during a debugfs operation while the SPI core is concurrently mapping rx_buf for a triggered read, could the DMA FROM_DEVICE cache invalidation discard the CPU's writes to tx_buf and corrupt memory?

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

Quoted 9 lines

[ ... ]

drivers/iio/adc/ad4134.c +1 -1
@@ -269,7 +280,7 @@ static int ad4134_data_read(struct ad4134_state *st, unsigned int reg,
 	 * interface. Now we read data from all channels but keep only the bits
 	 * from the requested one.
 	 */
-	for (i = 0; i < ARRAY_SIZE(ad4134_chan_set); i++) {
+	for (i = 0; i < AD4134_NUM_CHANNELS; i++) {
 		ret = spi_write_then_read(st->spi, NULL, 0, st->rx_buf,
 					  BITS_TO_BYTES(AD4134_CHAN_PRECISION_BITS));

[Severity: Medium]
Could this leak uninitialized stack memory to userspace if accessed via the regmap debugfs interface?

The patch adds IIO_CHAN_SOFT_TIMESTAMP(4) to ad4134_chan_set, which increases its ARRAY_SIZE from 4 to 5. The max_register calculation for the regmap configuration uses ARRAY_SIZE(ad4134_chan_set) - 1.

If userspace reads this new max register (0x54) via the regmap debugfs interface, it will call ad4134_data_read(). Inside this loop, it only iterates up to AD4134_NUM_CHANNELS (which is 4).

Since AD4134_VREG_CH(reg) would evaluate to 4, the condition if (i == AD4134_VREG_CH(reg)) never matches, leaving the stack variable 'sample' uninitialized before it is sign-extended and returned.

Quoted 15 lines

[ ... ]

drivers/iio/adc/ad4134.c +10 -0
@@ -333,6 +344,44 @@ static const struct regmap_config ad4134_regmap_config = {
 	.max_register = AD4134_CH_VREG(ARRAY_SIZE(ad4134_chan_set) - 1),
 };
 
+static irqreturn_t ad4134_trigger_handler(int irq, void *p)
+{
+	IIO_DECLARE_BUFFER_WITH_TS(u32, channels, AD4134_NUM_CHANNELS) = { };
+	unsigned int chan_bytes = BITS_TO_BYTES(AD4134_CHAN_PRECISION_BITS);
+	struct iio_poll_func *pf = p;
+	struct iio_dev *indio_dev = pf->indio_dev;
+	struct ad4134_state *st = iio_priv(indio_dev);
+	struct spi_transfer xfer = {
+		.rx_buf = st->rx_buf,
+		.cs_off = true,

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
+		.len = chan_bytes * AD4134_NUM_CHANNELS,
+	};
+	int ret;
+
+	gpiod_set_value_cansleep(st->odr_gpio, 1);
+	fsleep(1);
+	gpiod_set_value_cansleep(st->odr_gpio, 0);
+
+	/* Run enough DCLK cycles to match the data frame length. */
+	ret = spi_sync_transfer(st->spi, &xfer, 1);

[Severity: High]
Does this introduce a data race on st->rx_buf?

The trigger handler runs asynchronously and uses st->rx_buf directly in spi_sync_transfer() without taking any locks.

Meanwhile, if userspace reads from the regmap debugfs node, the regmap core takes its internal lock and calls ad4134_data_read(), which invokes spi_write_then_read() using the exact same st->rx_buf.

Because regmap debugfs access does not claim IIO direct mode, and the trigger handler bypasses the regmap lock, could both paths execute concurrently and cause concurrent DMA mapping of the same buffer?

Quoted 1 line

[ ... ]

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

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

In reply to Marcelo Schmitt
Quoted 5 lines · 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.

...

Quoted 16 lines
drivers/iio/adc/ad4134.c +16 -0
+static irqreturn_t ad4134_trigger_handler(int irq, void *p)
+{
+	IIO_DECLARE_BUFFER_WITH_TS(u32, channels, AD4134_NUM_CHANNELS) = { };
+	unsigned int chan_bytes = BITS_TO_BYTES(AD4134_CHAN_PRECISION_BITS);
+	struct iio_poll_func *pf = p;
+	struct iio_dev *indio_dev = pf->indio_dev;
+	struct ad4134_state *st = iio_priv(indio_dev);
+	struct spi_transfer xfer = {
+		.rx_buf = st->rx_buf,
+		.cs_off = true,
+		.len = chan_bytes * AD4134_NUM_CHANNELS,
+	};
+	int ret;
+
+	gpiod_set_value_cansleep(st->odr_gpio, 1);
+	fsleep(1);

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

Quoted 10 lines
drivers/iio/adc/ad4134.c +9 -0
+	gpiod_set_value_cansleep(st->odr_gpio, 0);
+
+	/* Run enough DCLK cycles to match the data frame length. */
+	ret = spi_sync_transfer(st->spi, &xfer, 1);
+	if (ret)
+		goto out;
 
+	for (int ch = 0, i = 0; ch < AD4134_NUM_CHANNELS; ch++) {
+		if (!test_bit(ch, indio_dev->active_scan_mask))
+			continue;

for_each_set_bit() ?

Quoted 10 lines
drivers/iio/adc/ad4134.c +10 -0
+		channels[i++] = get_unaligned_be24(&st->rx_buf[ch * chan_bytes]);
+	}
+
+	iio_push_to_buffers_with_ts(indio_dev, channels, sizeof(channels),
+				    pf->timestamp);
+
+out:
+	iio_trigger_notify_done(indio_dev->trig);
+	return IRQ_HANDLED;
+}
Signature · 2 lines
With Best Regards,
Andy Shevchenko
#5 lore raw

Re: [PATCH v4 02/13] iio: adc: ad4134: Sign extend sample data

In reply to [email protected]
Quoted 43 lines · On 10/06, [email protected] wrote:

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] build: -Wmaybe-uninitialized warning for conditionally assigned 'sample' --

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

iio: adc: ad4134: Sign extend sample data

Sign extend ADC sample data for correct delivery of negative ADC input difference.

Quoted 13 lines
drivers/iio/adc/ad4134.c +1 -0
index e53c10b9a44a9..6fdeb27d7a42b 100644
@@ -172,6 +172,7 @@ static int ad4134_data_read(struct ad4134_state *st, unsigned int reg,
 			    unsigned int *val)
 {
 	unsigned int i;
+	u32 sample;
 	int ret;
 
 	/*

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

Quoted 7 lines
drivers/iio/adc/ad4134.c +2 -1
@@ -196,8 +197,9 @@ static int ad4134_data_read(struct ad4134_state *st, unsigned int reg,
 		 * Clock out data from all channels to avoid that.
 		 */
 		if (i == AD4134_VREG_CH(reg))
-			*val = get_unaligned_be24(st->rx_buf);
+			sample = get_unaligned_be24(st->rx_buf);
 	}
+	*val = sign_extend32(sample, AD4134_CHAN_PRECISION_BITS - 1);
                             ^^^^^^

[Severity: Low]
Does this code trigger a -Wmaybe-uninitialized compiler warning?

The local variable sample is declared without initialization and is only assigned conditionally if i == AD4134_VREG_CH(reg). While the regmap core strictly validates reg before invoking the read callback, the compiler analyzes ad4134_data_read() locally and cannot statically deduce this external bounds guarantee.

Quoted 6 lines

Consequently, the compiler evaluates a theoretical path where the condition is never met, leaving sample unassigned before it is passed to sign_extend32().

This can cause build failures in kernel configurations with CONFIG_WERROR enabled. Explicitly initializing u32 sample = 0; or unconditionally performing the sign extension inside the if block would resolve this.

Okay, u32 sample = 0 is what I've chosen for v5.

Quoted 4 lines
Quoted 4 lines
drivers/iio/adc/ad4134.c +0 -0
 	return 0;
 }
#13 lore raw

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

In reply to [email protected]
Quoted 27 lines · On 10/06, [email protected] wrote:

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] iio: adc: ad4134: broken SPI read CRC calculation and ignored failures
- [Medium] iio: adc: missing delay after reset deassertion in probe
--

commit 5284b96efc125640c497213951d3fabe580894ec
Author: Marcelo Schmitt <[email protected]>

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

This commit conditionally reduces the SPI transfer length when the AD4134 CRC feature is disabled. It introduces a crc_en flag in the driver state to skip the CRC validation check and send fewer bytes when CRC is inactive.

Quoted 4 lines
drivers/iio/adc/ad4134.c +0 -0
index a0113fff4b715..85fa16321d744 100644

[ ... ]

Quoted 8 lines
drivers/iio/adc/ad4134.c +1 -1
@@ -232,7 +233,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");
 
Quoted 4 lines

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

Quoted 1 line
drivers/iio/adc/ad4134.c +0 -0
 	return 0;

[Severity: Medium]
Does this CRC validation logic reliably verify the read data?

It would require mid-transfer data CRC calculation to properly implement AD4134 CRC feature. That would probably require changes to the SPI core or even more unusual hacks. Fixing the CRC is not part of this series and I don't want to extend it further.

...

Quoted 28 lines

drivers/iio/adc/ad4134.c static int ad4134_min_io_mode_setup(struct ad4134_state *st) · line 318

Quoted 6 lines
drivers/iio/adc/ad4134.c +1 -0
@@ -313,6 +314,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);

[Severity: Medium]
Does the AD4134 device require a stabilization delay before interacting with it over SPI?

In ad4134_probe(), devm_reset_control_get_optional_exclusive_deasserted() is called to deassert the reset line. Execution then proceeds directly to regmap initialization and SPI transfers without any hardware stabilization delay:

	rst = devm_reset_control_get_optional_exclusive_deasserted(dev, NULL);
	if (IS_ERR(rst))
		return dev_err_probe(dev, PTR_ERR(rst),
				     "failed to get and deassert reset\n");

	crc8_populate_msb(ad4134_spi_crc_table, AD4134_SPI_CRC_POLYNOM);

	ret = devm_mutex_init(dev, &st->sync_lock);
	if (ret)
		return ret;

	st->regmap = devm_regmap_init(dev, NULL, st, &ad4134_regmap_config);
Quoted 2 lines

Without a delay, could the first SPI transactions during probe drop or return invalid data, causing initialization to fail?

Has never been an issue during tests. Though, I guess it's easier to add fsleep(AD4134_RESET_TIME_US) than to keep replying to bots.

#25 lore raw

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

In reply to [email protected]
Quoted 45 lines · On 10/06, [email protected] wrote:

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] dt-bindings: invalid and incomplete constraints for spi-rx-bus-width --

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

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

This commit updates the AD4134 device tree bindings to document different SPI connection modes. It introduces the adi,spi-mode and #daisy-chained-devices properties along with corresponding constraints for different wiring configurations.

Quoted 4 lines
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +0 -0
index ea6d7e0264190..970e7adb2405b 100644

[ ... ]

Quoted 12 lines
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +1 -7
@@ -141,13 +161,36 @@ required:
   - clocks
   - clock-names
 
-oneOf:
-  - required:
-      - ldoin-supply
-  - required:
-      - avdd1v8-supply
-      - dvdd1v8-supply
-      - clkvdd-supply
+allOf:

Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml required: · line 174

Quoted 10 lines
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +10 -0
+  - oneOf:
+      - required:
+          - ldoin-supply
+      - required:
+          - avdd1v8-supply
+          - dvdd1v8-supply
+          - clkvdd-supply
+
+  - oneOf:
+      - required: ['adi,spi-mode', '#daisy-chained-devices']

[Severity: Low]
Neither chain configuration includes spi-rx-bus-width in the required list.

Quoted 6 lines

Since JSON Schema property constraints only evaluate when the property is present, omitting spi-rx-bus-width from a chain node bypasses the hardware constraint.

Should spi-rx-bus-width be added to the required lists so the SPI controller doesn't silently initialize with a single receive lane?

I don't think that would necessarily be a problem.

Quoted 7 lines

Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml required: · line 179

Quoted 6 lines
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +5 -0
+        properties:
+          adi,spi-mode:
+            const: one-channel-chain
+          spi-rx-bus-width:
+            const: 1
Quoted 6 lines

[Severity: Low]
Because the core SPI bindings define spi-rx-bus-width as a uint32-array, evaluating a device tree value (such as <1>, parsed internally as the JSON array [1]) against a scalar causes a strict type mismatch.

Could this falsely reject valid configurations during dt_binding_check?

When spi-rx-bus-width = <1>; the property can be omitted and the pair #daisy-chained-devices = <N>;
adi,spi-mode = "one-channel-chain";
passes dt_binding_check.

Quoted 10 lines

Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml required: · line 187

Quoted 9 lines
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +8 -0
+      - required: ['adi,spi-mode', '#daisy-chained-devices']
+        properties:
+          adi,spi-mode:
+            const: two-channel-chain
+          spi-rx-bus-width:
+            items:
+              - const: 1
+              - const: 1
Quoted 6 lines

[Severity: Low]
This array items constraint validates the first two lanes, but it lacks bounds checks.

Does this need minItems: 2 and maxItems: 2 to properly restrict the overall length of the array?

I've tried that before preparing v4 and the result was dt_binding_check hints. 'hint: "maxItems" is not needed with an "items" list'
'hint: "minItems" is only needed if less than the "items" list length'

Quoted 10 lines
Quoted 7 lines
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +6 -0
+      - properties:
+          '#daisy-chained-devices': false
+          adi,spi-mode:
+            enum:
+              - no-cs
+              - 4-wire
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=8
#31 lore raw

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

In reply to [email protected]

On 10/06, [email protected] wrote:
...

Quoted 8 lines

[Severity: Medium]
If spi_setup() fails here, we return the error but st->spi->mode remains modified. On subsequent calls, cur_mode != SPI_MODE_0 will evaluate to false because the cached mode reflects the requested state.

Can this cause the driver to bypass spi_setup() on subsequent calls and attempt to communicate with the device while the SPI hardware remains incorrectly configured?

Seems to make sense. Will double check and fix if needed.

...

Quoted 16 lines

[Severity: High]
Does this cause a deadlock during device probe in NO_CS mode?

Here the driver acquires and permanently selects the SDO multiplexer via devm_mux_state_get_optional_selected(), which acquires the multiplexer's non-recursive semaphore.

Immediately after, probe calls ad4134_min_io_mode_setup(), which writes to device registers via regmap_update_bits(). This triggers the following call chain:

ad4134_min_io_mode_setup()
regmap_update_bits()

    ad4134_reg_write()
      ad4134_claim_reg_access()
Quoted 7 lines

ad4134_claim_reg_access() unconditionally calls mux_state_select(), which will attempt to acquire the exact same semaphore already held by the current task, causing a deadlock.

Furthermore, ad4134_release_reg_access() then unconditionally calls mux_state_deselect(), which would prematurely release the probe-acquired lock.

Seems plausible. Will double check and fix if needed.

Other LLM comments don't seem to apply either because they are related to debug interface usage or marginal issues.

#21 lore raw

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

In reply to Andy Shevchenko
Quoted 32 lines · Andy Shevchenko
Quoted 5 lines · 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.

...

Quoted 22 lines
drivers/iio/adc/ad4134.c +22 -0
+static irqreturn_t ad4134_trigger_handler(int irq, void *p)
+{
+	IIO_DECLARE_BUFFER_WITH_TS(u32, channels, AD4134_NUM_CHANNELS) = { };
+	unsigned int chan_bytes = BITS_TO_BYTES(AD4134_CHAN_PRECISION_BITS);
+	struct iio_poll_func *pf = p;
+	struct iio_dev *indio_dev = pf->indio_dev;
+	struct ad4134_state *st = iio_priv(indio_dev);
+	struct spi_transfer xfer = {
+		.rx_buf = st->rx_buf,
+		.cs_off = true,
+		.len = chan_bytes * AD4134_NUM_CHANNELS,
+	};
+	int ret;
+
+	gpiod_set_value_cansleep(st->odr_gpio, 1);
+	fsleep(1);
+	gpiod_set_value_cansleep(st->odr_gpio, 0);
+
+	/* Run enough DCLK cycles to match the data frame length. */
+	ret = spi_sync_transfer(st->spi, &xfer, 1);
+	if (ret)
+		goto out;
Quoted 5 lines

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

Quoted 3 lines
drivers/iio/adc/ad4134.c +3 -0
+	for (int ch = 0, i = 0; ch < AD4134_NUM_CHANNELS; ch++) {
+		if (!test_bit(ch, indio_dev->active_scan_mask))
+			continue;

for_each_set_bit() ?

Will use that for v5 (or maybe even iio_for_each_active_channel()).

Thanks,
Marcelo

maintainer
#14 lore raw

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

In reply to Marcelo Schmitt
Quoted 49 lines · Marcelo Schmitt
Quoted 10 lines · On 10/06, [email protected] wrote:

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] iio: adc: ad4134: broken SPI read CRC calculation and ignored failures
- [Medium] iio: adc: missing delay after reset deassertion in probe
--

commit 5284b96efc125640c497213951d3fabe580894ec
Author: Marcelo Schmitt <[email protected]>

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

Quoted 8 lines

This commit conditionally reduces the SPI transfer length when the AD4134 CRC feature is disabled. It introduces a crc_en flag in the driver state to skip the CRC validation check and send fewer bytes when CRC is inactive.

[ ... ]

[Severity: Medium]
Does this CRC validation logic reliably verify the read data?

It would require mid-transfer data CRC calculation to properly implement AD4134 CRC feature. That would probably require changes to the SPI core or even more unusual hacks. Fixing the CRC is not part of this series and I don't want to extend it further.

...

Quoted 21 lines

Review static int ad4134_min_io_mode_setup(struct ad4134_state *st)

Quoted 1 line
(quoted diff) +0 -0
@@ -313,6 +314,7 @@ static int ad4134_min_io_mode_setup(struct ad4134_state *st)

[Severity: Medium]
Does the AD4134 device require a stabilization delay before interacting with it over SPI?

In ad4134_probe(), devm_reset_control_get_optional_exclusive_deasserted() is called to deassert the reset line. Execution then proceeds directly to regmap initialization and SPI transfers without any hardware stabilization delay:

	rst = devm_reset_control_get_optional_exclusive_deasserted(dev, NULL);
	if (IS_ERR(rst))
		return dev_err_probe(dev, PTR_ERR(rst),
				     "failed to get and deassert reset\n");

	crc8_populate_msb(ad4134_spi_crc_table, AD4134_SPI_CRC_POLYNOM);

	ret = devm_mutex_init(dev, &st->sync_lock);
	if (ret)
		return ret;
Quoted 7 lines
Quoted 4 lines
	st->regmap = devm_regmap_init(dev, NULL, st, &ad4134_regmap_config);

Without a delay, could the first SPI transactions during probe drop or return invalid data, causing initialization to fail?

Has never been an issue during tests. Though, I guess it's easier to add fsleep(AD4134_RESET_TIME_US) than to keep replying to bots.

If the datasheet has any specification about this, then it make sense to have it. But as another patch (could even be a fix).

maintainer
#2 lore raw

Re: [PATCH v4 01/13] iio: adc: ad4134: Adjust register map range

In reply to Marcelo Schmitt

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

Quoted 10 lines · Marcelo Schmitt
drivers/iio/adc/ad4134.c +1 -1
index 70f80bf1825f..e53c10b9a44a 100644
@@ -244,7 +244,7 @@ static const struct regmap_config ad4134_regmap_config = {
 	.reg_write = ad4134_reg_write,
 	.rd_table = &ad4134_regmap_rd_table,
 	.wr_table = &ad4134_regmap_wr_table,
-	.max_register = AD4134_CH_VREG(ARRAY_SIZE(ad4134_chan_set)),
+	.max_register = AD4134_CH_VREG(ARRAY_SIZE(ad4134_chan_set) - 1),

Can't we just use AD4134_NUM_CHANNELS? sashiko seems to have a point in the othe patch comment.

- Nuno Sá

Signature · 1 line
Nuno Sá <[email protected]>
maintainer Reviewed-by on v4 2/13
#6 lore raw

Re: [PATCH v4 02/13] iio: adc: ad4134: Sign extend sample data

In reply to Marcelo Schmitt
Quoted 6 lines · Marcelo Schmitt

Sign extend ADC sample data for correct delivery of negative ADC input difference.

Fixes e0bc6d7e2584 ("iio: adc: Initial support for AD4134")

With sashiko issue addressed:

Signature · 1 line
Nuno Sá <[email protected]>
maintainer Reviewed-by on v4 3/13
#8 lore raw

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

In reply to Marcelo Schmitt
Quoted 8 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 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.

[...]

Signature · 1 line
Nuno Sá <[email protected]>
maintainer Reviewed-by on v4 4/13
#10 lore raw

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

In reply to Marcelo Schmitt
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.

Signature · 1 line
Nuno Sá <[email protected]>
maintainer Reviewed-by on v4 5/13
#15 lore raw

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

In reply to Marcelo Schmitt
Quoted 5 lines · 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.

Hmm, still don't get the crc story... Are you saying crc just does not work as it is? What's the point then :)? I think it should very much be fixed. And It's indeed odd to compare the crc over different payloads. The normal way is that on receive, you compute it again and compare it against what you got from the device. Pretty sure that's what the device is doing (or at least it should). Might be missing something but not sure why we would need spi core changes. See this for example:

https://elixir.bootlin.com/linux/v7.2.10/source/drivers/iio/imu/adis16550.c#L193

Anyways not related to this patch so:

Signature · 1 line
Nuno Sá <[email protected]>
maintainer
#17 lore raw

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

In reply to Marcelo Schmitt

drivers/iio/adc/ad4134.c line 106

Quoted 12 lines · Marcelo Schmitt
drivers/iio/adc/ad4134.c +0 -0
index 85fa16321d74..3048e61a3cb1 100644
@@ -80,12 +83,47 @@

[ ... skip 18 lines ... ]

drivers/iio/adc/ad4134.c +6 -0
+				  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);
+

Please don't do the above. Arrange the code properly instead.

Signature · 1 line
Nuno Sá <[email protected]>
maintainer
#22 lore raw

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

In reply to Marcelo Schmitt

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

Quoted 12 lines · Marcelo Schmitt
drivers/iio/adc/ad4134.c +1 -1
index 3048e61a3cb1..b5207f16054e 100644
@@ -149,7 +160,7 @@ 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);
+	u8 rx_buf[AD4134_SPI_MAX_XFER_LEN * AD4134_NUM_CHANNELS] __aligned(IIO_DMA_MINALIGN);
 	u8 tx_buf[AD4134_SPI_MAX_XFER_LEN];
 };

The above is indeed a possible issue! Not just about dma but also about concurrency on the buffers.

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

Quoted 8 lines
drivers/iio/adc/ad4134.c +0 -0
@@ -333,6 +344,44 @@ static const struct regmap_config ad4134_regmap_config = {

[ ... skip 17 lines ... ]

drivers/iio/adc/ad4134.c +6 -0
+	gpiod_set_value_cansleep(st->odr_gpio, 1);
+	fsleep(1);
+	gpiod_set_value_cansleep(st->odr_gpio, 0);
+
+	/* Run enough DCLK cycles to match the data frame length. */
+	ret = spi_sync_transfer(st->spi, &xfer, 1);

Yeah the above needs to be sync with debugfs. Either by not allowing debugfs when buffering (which can be odd tbh) or just by using the sync lock around both places or even by just using a dedicated buffer (that can even allocated with devm during probe - or on the setup buffer op depending on the scan_mask) so that no locking is needed.

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

Quoted 6 lines
drivers/iio/adc/ad4134.c +6 -0
+	if (ret)
+		goto out;
+
+	for (int ch = 0, i = 0; ch < AD4134_NUM_CHANNELS; ch++) {
+		if (!test_bit(ch, indio_dev->active_scan_mask))
+			continue;

As you already noted, please use the proper IIO helper.

Signature · 1 line
Nuno Sá <[email protected]>
maintainer
#33 lore raw

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

In reply to Marcelo Schmitt
Quoted 5 lines · Marcelo Schmitt
drivers/iio/adc/ad4134.c +0 -0
index b5207f16054e..debc2ff02705 100644

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

Quoted 9 lines
drivers/iio/adc/ad4134.c +5 -1
@@ -308,14 +423,18 @@ static int ad4134_register_read(struct ad4134_state *st, unsigned int reg,
 		.len = st->crc_en ? AD4134_SPI_MAX_XFER_LEN : 2,
 	};
 	unsigned int inst;
-	int ret;
+	int access_ret, ret;
+
+	ret = ad4134_claim_reg_access(st);
+	if (ret)
+		return ret;

Do we really need to claim/release for every register read? Can't we just select register mode at probe and leave it in that position by default? Then when starting to buffer, we deselect + select sample mode and when exiting do the reverse. Seems even more appropriate when the dt mode property does not want to use DOUT at all which means that all this select + deselect is really unneeded.

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

Quoted 8 lines
drivers/iio/adc/ad4134.c +0 -0
@@ -594,10 +728,64 @@ static int ad4134_probe(struct spi_device *spi)

[ ... skip 16 lines ... ]

drivers/iio/adc/ad4134.c +4 -1
 		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;
+	}

Andy has a better idea but I think the way we want to handle the above in IIO nowadays is like:

if (device_property_present()) {
	ret = device_property_match_property_string();
	if (ret < 0)
		return ret;
	
	...
} else {
	st->spi_mode = AD4134_SPI_MODE_NO_CS
}

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

Quoted 12 lines
drivers/iio/adc/ad4134.c +12 -0
+
+	if (st->spi_mode == AD4134_SPI_MODE_NO_CS) {
+		/*
+		 * The support hardware for AD4134 may have a multiplexer for
+		 * selecting between AD4134 SDO and AD4134 DOUT0. If that mux
+		 * is set but the user still wants to run AD4134 in minimum I/O
+		 * mode, then DOUT0 is not used and the multiplexer OUTSIDE OF
+		 * AD4134 SILICON must be set to select AD4134 SDO. See AD4134
+		 * IIO documentation for details.
+		 */
+		st->mux_st[AD4134_SDO_INPUT] =
+			devm_mux_state_get_optional_selected(dev, "reg_access");

Seems like an issue indeed. But with I propose above, stops being one I think.

Signature · 1 line
Nuno Sá <[email protected]>
maintainer
#32 lore raw

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

In reply to Marcelo Schmitt
Quoted 38 lines · Marcelo Schmitt

On 10/06, [email protected] wrote:
...

Quoted 8 lines

[Severity: Medium]
If spi_setup() fails here, we return the error but st->spi->mode remains modified. On subsequent calls, cur_mode != SPI_MODE_0 will evaluate to false because the cached mode reflects the requested state.

Can this cause the driver to bypass spi_setup() on subsequent calls and attempt to communicate with the device while the SPI hardware remains incorrectly configured?

Seems to make sense. Will double check and fix if needed.

...

Quoted 16 lines

[Severity: High]
Does this cause a deadlock during device probe in NO_CS mode?

Here the driver acquires and permanently selects the SDO multiplexer via devm_mux_state_get_optional_selected(), which acquires the multiplexer's non-recursive semaphore.

Immediately after, probe calls ad4134_min_io_mode_setup(), which writes to device registers via regmap_update_bits(). This triggers the following call chain:

ad4134_min_io_mode_setup()
regmap_update_bits()

    ad4134_reg_write()
      ad4134_claim_reg_access()
Quoted 7 lines

ad4134_claim_reg_access() unconditionally calls mux_state_select(), which will attempt to acquire the exact same semaphore already held by the current task, causing a deadlock.

Furthermore, ad4134_release_reg_access() then unconditionally calls mux_state_deselect(), which would prematurely release the probe-acquired lock.

Quoted 5 lines

Seems plausible. Will double check and fix if needed.

Other LLM comments don't seem to apply either because they are related to debug interface usage or marginal issues.

Hmm don't agree. Don't disregard debugfs claim just because it's a debug interface. Looks like a real issue to me (very easy to trigger) that needs fixing (same as the other patch).

- Nuno Sá

#34 lore raw

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

In reply to Nuno Sá
Quoted 11 lines · Nuno Sá
Quoted 10 lines · Marcelo Schmitt
drivers/iio/adc/ad4134.c +1 -1
index b5207f16054e..debc2ff02705 100644
@@ -308,14 +423,18 @@ static int ad4134_register_read(struct ad4134_state *st, unsigned int reg,
 		.len = st->crc_en ? AD4134_SPI_MAX_XFER_LEN : 2,
 	};
 	unsigned int inst;
-	int ret;
+	int access_ret, ret;
Quoted 8 lines

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

Quoted 4 lines
drivers/iio/adc/ad4134.c +4 -0
+
+	ret = ad4134_claim_reg_access(st);
+	if (ret)
+		return ret;

Do we really need to claim/release for every register read? Can't we just select register mode at probe and leave it in that position by default?

Yeah, we could have it that way but then the error paths get trickier to handle. For example, we might deselect reg mode and then fail to select sample mode. Because of that, we would need to keep track of what mux_states we hold lock to avoid deselecting a state that is not selected.

After sample read, we are susceptible to succeed sample mode deselect and fail reg mode select, so we actually also need to check we have reg mode selected before register access anyway.

Not to mention we would need a driver .remove callback to check which (if any) mode we have selected to correctly deselect any multiplexer state on driver detach.

Quoted 5 lines

Then when starting to buffer, we deselect + select sample mode and when exiting do the reverse. Seems even more appropriate when the dt mode property does not want to use DOUT at all which means that all this select + deselect is really unneeded.

The select/deselect dance is not needed for minimum I/O mode (no CS wiring) so I made it skip the multiplexer switching entirely for that mode.

Thanks,
Marcelo