iio: adc: ad4134: Enable greater sample rate data capture
Subsystems (5)
Marcelo Schmitt
maintainerv3 cover iio: adc: ad4134: Enable greater sample rate data capture
Extend AD4134 support to enable greater sample rate data capture. To achieve that, provide control of digital filter type selection. The default filter type on device power up only supports sample rates up to 374 kSPS. In addition to that, enable interfacing with AD4134 in SPI 4-wire mode that can support reading ADC sample data through multiple wires. Finally, use SPI offloading to speed up data transfers at up to 1.49 MSPS.
Features being added:
- Data filter type selection.
- Triggered buffer data read.
- SPI 4-wire mode.
- High speed data capture with SPI offloading.
- Device tree doc updates to reflect previously missing chip characteristics.
Minor improvements (introduced before the new features):
- Adjusted register map range now prevents access to uninitialized local variable. [NEW PATCH]
- 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 v3 are intended to tackle all applicable suggestions from reviewers and from automated tests/reviews/AI.
Change log v2 -> v3:
[device tree]
- Adjusted spi-rx-bus-width constraints.
- Dropped mux provider from offload example.
- Dropped odr-gpios from offload example.
[IIO]
- Already applied fixes patches have been dropped.
- Fixed off-by-one mistake to avoid access to uninitialized local variable. [NEW PATCH]
- Now using IIO_DECLARE_BUFFER_WITH_TS macro to set properly sized triggered buffer storage that includes room for timestamp.
- Now using SPI_MODE_X_MASK to update CPOL/CPHA bits.
- Refactored access mode locking to avoid umpaired calls to mux_state_select()/deselect().
- Dropped unreachable code on offload setup.
- Fixed sampling frequency validation check.
- Avoided division by zero when external clock is not provided.
- Follow LIFO teardown order on offload buffer disable.
- Set correct buffer size to read all channels in offload mode.
- Disallowed single-read when setup for SPI offloading.
- Corrected AD4134 IIO Doc to only show the PWM connected to ODR on offload diagrams.
Previous submissions:
v1: https://lore.kernel.org/linux-iio/[email protected]/
v2: https://lore.kernel.org/linux-iio/[email protected]/
With best regards,
Marcelo
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 | 104 ++- Documentation/iio/ad4134.rst | 128 +++ Documentation/iio/index.rst | 1 + MAINTAINERS | 1 + drivers/iio/adc/Kconfig | 8 + drivers/iio/adc/ad4134.c | 820 +++++++++++++++++- 6 files changed, 1027 insertions(+), 35 deletions(-) create mode 100644 Documentation/iio/ad4134.rst
base-commit: a3b3580713f3ac5a32dc2874ee546828977a1d68
Signature · 1 line
2.53.0
Marcelo Schmitt
maintainerPATCH v3 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.
---
New patch in v3.
drivers/iio/adc/ad4134.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/iio/adc/ad4134.c +2 -2
@@ -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
Marcelo Schmitt
maintainerPATCH v3 2/13 iio: adc: ad4134: Sign extend sample data
In reply to Marcelo SchmittSign extend ADC sample data for correct delivery of negative ADC input difference.
---
No changes in v3.
drivers/iio/adc/ad4134.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/iio/adc/ad4134.c +3 -1
@@ -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
Re: [PATCH v3 02/13] iio: adc: ad4134: Sign extend sample data
Quoted 6 lines · On Tue, 29 Sep 2026 19:42:29 -0300 Marcelo Schmitt…
Sign extend ADC sample data for correct delivery of negative ADC input difference.
Fixes e0bc6d7e2584 ("iio: adc: Initial support for AD4134")Signed-off-by Marcelo Schmitt <[email protected]>---
Signature · 2 lines
Kind regards, Joshua Crofts
Marcelo Schmitt
maintainerPATCH v3 3/13 iio: adc: ad4134: Update include list to comply with IWYU principles
In reply to Marcelo SchmittAdd 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 v3.
drivers/iio/adc/ad4134.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/iio/adc/ad4134.c +3 -3
@@ -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
Marcelo Schmitt
maintainerPATCH v3 4/13 iio: adc: ad4134: Serialize single-read operations
In reply to Marcelo SchmittProtect 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 v2 -> v3:
- Renamed the mutex so it has a more distinguishable name from the mutex to be added on a follow up patch.
drivers/iio/adc/ad4134.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-)
drivers/iio/adc/ad4134.c +15 -1
@@ -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 members the of device state, 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
[email protected]
AI reviewRe: [PATCH v3 04/13] iio: adc: ad4134: Serialize single-read operations
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Low] typo in the new comment describing `sync_lock` --
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] typo in the new comment describing sync_lock
--
commit b5e93b2d37821a8e474f3fdacabd2e3e420e3376
Author: Marcelo Schmitt <[email protected]>
iio: adc: ad4134: Serialize single-read operations
This commit protects single-sample read operations from failing if two or more of them run concurrently. It serializes the data read operation to avoid single-sample read requests disrupting each other.
Quoted 4 lines
drivers/iio/adc/ad4134.c +0
-0
[ ... ]
drivers/iio/adc/ad4134.c struct ad4134_state { · line 104
Quoted 6 lines
drivers/iio/adc/ad4134.c +2
-0@@ -98,6 +100,11 @@ struct ad4134_state {struct regmap *regmap;unsigned long sys_clk_hz;struct gpio_desc *odr_gpio; +/* +* Synchronize access to members the of device state, and ensure
[Severity: Low]
This isn't a bug, but there is a typo in the comment here. Should "members the of" be written as "members of the"?
Quoted 6 lines
drivers/iio/adc/ad4134.c +3
-0+* atomicity of consecutive register access operations. +*/ +struct mutex sync_lock;int refin_mv;/* * DMA (thus cache coherency maintenance) requires the transfer buffers
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=4
Marcelo Schmitt
maintainerPATCH v3 5/13 iio: adc: ad4134: Run shorter transfers when CRC is disabled
In reply to Marcelo SchmittWhen 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.
---
No changes in v3.
drivers/iio/adc/ad4134.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
drivers/iio/adc/ad4134.c +6 -4
@@ -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
Marcelo Schmitt
maintainerPATCH v3 6/13 iio: adc: ad4134: Add support for digital filter type selection
In reply to Marcelo SchmittAD4134 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 v3.
drivers/iio/adc/ad4134.c | 76 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+)
drivers/iio/adc/ad4134.c +76 -0
@@ -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 0xA5static 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 , ®_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
Marcelo Schmitt
maintainerPATCH v3 7/13 iio: adc: ad4134: Support buffered data read
In reply to Marcelo SchmittEnable 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 v2 -> v3:
- Now using IIO_DECLARE_BUFFER_WITH_TS macro to set properly sized triggered buffer storage that includes room for timestamp.
drivers/iio/adc/Kconfig | 2 ++ drivers/iio/adc/ad4134.c | 61 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 62 insertions(+), 1 deletion(-)
drivers/iio/adc/Kconfig +2 -0
@@ -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 +60 -1
104 lines not on this page · raw message
Signature · 1 line
2.53.0
[email protected]
AI reviewRe: [PATCH v3 07/13] iio: adc: ad4134: Support buffered data read
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider: - [High] mm: concurrent use of shared DMA buffers st->rx_buf and st->tx_buf - [High] spi: cs_off = true in…
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] mm: concurrent use of shared DMA buffers st->rx_buf and st->tx_buf
- [High] spi: cs_off = true in triggered buffer breaks 4-wire mode communication
- [High] iio: ADC output frame resets due to looped SPI transfers
--
commit 29f8197d694e692f78d7a5142e0a389309c577b0
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
[ ... ]
drivers/iio/adc/ad4134.c static const struct regmap_config ad4134_regmap_config = { · line 354
Quoted 12 lines
drivers/iio/adc/ad4134.c +8
-0@@ -333,6 +344,43 @@ 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) = { }; +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,
[Severity: High]
If userspace reads or writes ADC registers via debugfs while the triggered buffer is running in minimum I/O mode (NO_CS), ad4134_debugfs_reg_access() can run concurrently with ad4134_trigger_handler().
Because the trigger handler does not acquire any locks to protect the shared DMA buffers, and while regmap acquires st->access_lock, this lock is explicitly not held during buffer capture in NO_CS mode (as setup_ops is NULL), both threads can use the shared st->rx_buf and st->tx_buf simultaneously.
Does this concurrent use cause DMA buffer corruption, potential kernel panics during concurrent DMA mappings, or incorrect data reads?
drivers/iio/adc/ad4134.c static const struct regmap_config ad4134_regmap_config = { · line 355
Quoted 1 line
drivers/iio/adc/ad4134.c +1
-0+ .cs_off = true,
[Severity: High]
When the driver is configured in 4-wire mode (adi,spi-mode = "4-wire") and falls back to the software trigger handler, this flag explicitly instructs the SPI controller to leave the chip select line inactive (high) for the duration of the transfer.
Since the AD4134 requires an active (low) chip select to frame the data in 4-wire mode, does this setting break 4-wire mode communication and prevent the device from outputting valid sample data?
drivers/iio/adc/ad4134.c static const struct regmap_config ad4134_regmap_config = { · line 366
Quoted 11 lines
drivers/iio/adc/ad4134.c +11
-0+ .len = BITS_TO_BYTES(AD4134_CHAN_PRECISION_BITS), + }; +int ret; + +gpiod_set_value_cansleep (st->odr_gpio,1 ); +fsleep (1 ); +gpiod_set_value_cansleep (st->odr_gpio,0 ); + +/* Execute transfers for all channels so the entire data frame is read. */ +for (int ch =0 , i =0 ; ch <AD4134_NUM_CHANNELS ; ch++) { + ret =spi_sync_transfer (st->spi, &xfer,1 );
[Severity: High]
In 4-wire mode, the AD4134 resets its data output frame if the chip select goes high or if the DCLK is idle for more than 250ns.
Does calling spi_sync_transfer() in a loop for each channel introduce software delays far exceeding 250ns and toggle the CS line between calls?
Could this violate the device's continuous clocking and CS timing requirements, causing the frame to reset on every iteration and reading Channel 0 repeatedly instead of streaming consecutive channels?
Should a single bulk SPI transfer be used here instead of a loop?
Quoted 16 lines
drivers/iio/adc/ad4134.c +16
-0+if (ret) + goto out; + +if (!test_bit (ch, indio_dev->active_scan_mask)) +continue ; + + channels[i++] =get_unaligned_be24 (st->rx_buf); + } + +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 · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=7
Re: [PATCH v3 07/13] iio: adc: ad4134: Support buffered data read
On 09/29, [email protected] wrote:
...
Quoted 5 lines
Quoted 5 lines
drivers/iio/adc/ad4134.c +5
-0+static irqreturn_t ad4134_trigger_handler (int irq,void *p) +{ + IIO_DECLARE_BUFFER_WITH_TS(u32, channels, AD4134_NUM_CHANNELS) = { }; +struct iio_poll_func *pf = p; +struct iio_dev *indio_dev = pf->indio_dev;
Quoted 9 lines
drivers/iio/adc/ad4134.c static const struct regmap_config ad4134_regmap_config = { · line 354
Quoted 3 lines
drivers/iio/adc/ad4134.c +3
-0+struct ad4134_state *st =iio_priv (indio_dev); +struct spi_transfer xfer = { + .rx_buf = st->rx_buf,[Severity: High]
If userspace reads or writes ADC registers via debugfs while the triggered buffer is running in minimum I/O mode (NO_CS),ad4134_debugfs_reg_access()can run concurrently withad4134_trigger_handler().
Yeah, debugfs is not safe to use like that. I believe claiming direct mode would solve the issue, although, the conclusion a while ago was that enforcing that for debug interface was not the way to go, IIRC.
I'll ignore complaints about issues related to debugfs unless asked otherwise.
Quoted 9 lines
[Severity: High]
When the driver is configured in 4-wire mode (adi,spi-mode = "4-wire") and falls back to the software trigger handler, this flag explicitly instructs the SPI controller to leave the chip select line inactive (high) for the duration of the transfer.Since the AD4134 requires an active (low) chip select to frame the data in 4-wire mode, does this setting break 4-wire mode communication and prevent the device from outputting valid sample data?
Doesn't apply to this specific device in 4-wire operation mode since the AD4134 data interface is read with CS off.
Quoted 16 lines
drivers/iio/adc/ad4134.c static const struct regmap_config ad4134_regmap_config = { · line 366
Quoted 12 lines
drivers/iio/adc/ad4134.c +11
-0+ .len = BITS_TO_BYTES(AD4134_CHAN_PRECISION_BITS), + }; +int ret; + +gpiod_set_value_cansleep (st->odr_gpio,1 ); +fsleep (1 ); +gpiod_set_value_cansleep (st->odr_gpio,0 ); + +/* Execute transfers for all channels so the entire data frame is read. */ +for (int ch =0 , i =0 ; ch <AD4134_NUM_CHANNELS ; ch++) { + ret =spi_sync_transfer (st->spi, &xfer,1 );[Severity: High]
In 4-wire mode, the AD4134 resets its data output frame if the chip select goes high or if the DCLK is idle for more than 250ns.
I have no idea where it supposedly found such information.
Quoted 9 lines
Does calling
spi_sync_transfer()in a loop for each channel introduce software delays far exceeding 250ns and toggle the CS line between calls?Could this violate the device's continuous clocking and CS timing requirements, causing the frame to reset on every iteration and reading Channel 0 repeatedly instead of streaming consecutive channels?
Should a single bulk SPI transfer be used here instead of a loop?
Anyways, running a longer transfer to get data all at once can indeed be done to minimize delays. So, I may do that on a v4.
Marcelo Schmitt
maintainerPATCH v3 8/13 dt-bindings: iio: adc: adi,ad4134: Document SPI connection mode
In reply to Marcelo SchmittDocument how AD4134 chips are connected to the host SPI controller according to different wiring configurations.
---
Change log v2 -> v3:
- Adjusted spi-rx-bus-width constraints.
Unfortunately, I missed SPI connection mode properties when introducing AD4134 dt-doc and the device driver defaulted to a no-CS configuration. Due to that, conventional 4-wire mode can't be made default without leading to a regression. Still, updating the SPI mode default to 4-wire is a sensible thing to do later on if acceptable.
.../bindings/iio/adc/adi,ad4134.yaml | 51 ++++++++++++++++--- 1 file changed, 44 insertions(+), 7 deletions(-)
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +44 -7
@@ -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,30 @@ 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: + const: 1, 1 + - properties: + '#daisy-chained-devices': false unevaluatedProperties: false
Signature · 1 line
2.53.0
[email protected]
AI reviewRe: [PATCH v3 08/13] dt-bindings: iio: adc: adi,ad4134: Document SPI connection mode
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider: - [Medium] dt-bindings: validation loophole bypasses #daisy-chained-devices requirement - [Medium]…
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Medium] dt-bindings: validation loophole bypasses #daisy-chained-devices requirement
- [Medium] dt-bindings: malformed YAML const constraint for spi-rx-bus-width array
- [Medium] dt-bindings: missing required enforcement for spi-rx-bus-width in chained mode --
commit 8253152c0a129fd35b9669cd3adc3c7039f4e2b2
Author: Marcelo Schmitt <[email protected]>
dt-bindings: iio: adc: adi,ad4134: Document SPI connection mode
This commit updates the binding to document how AD4134 chips are connected to the host SPI controller under different wiring configurations. It specifies the requirements for daisy-chained SPI modes and corresponding bus width constraints.
Quoted 4 lines
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +0
-0
[ ... ]
Quoted 1 line
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +0
-0@@ -141,13 +161,30 @@ required:
[ ... ]
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml required: · line 180
Quoted 8 lines
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +8
-0+ - 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']
[Severity: Medium]
Could this regression allow incomplete device trees to pass validation?
In JSON Schema, property value constraints only apply if the property is actually present in the node instance. Without including spi-rx-bus-width in the required array for the two-channel-chain branch, a node could omit the property entirely and bypass the multi-lane constraint, falling back to an incorrect 1-lane default at runtime.
Should spi-rx-bus-width be added to the required list here?
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml required: · line 185
Quoted 5 lines
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +5
-0+ properties: + adi,spi-mode: + const: two-channel-chain + spi-rx-bus-width: + const: 1, 1
[Severity: Medium]
Does this YAML constraint evaluation cause a regression where valid inputs are rejected?
In YAML, const: 1, 1 parses as the literal string "1, 1". Since spi-rx-bus-width is defined as a uint32-array, the JSON representation is parsed as an array. Comparing an array against a string using const always fails.
This would prevent valid hardware descriptions from passing dt_binding_check validation. Should this be formatted as an explicit array to match the type?
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml required: · line 187
Quoted 2 lines
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +2
-0+ - properties: + '#daisy-chained-devices': false
[Severity: Medium]
Does this regression in the fallback branch bypass the intended daisy chain property enforcement?
Using oneOf with a fallback that evaluates '#daisy-chained-devices': false allows any configuration missing this property to evaluate to true for this branch.
For instance, if adi,spi-mode is set to one-channel-chain but the daisy chain property is missing, the schema matches exactly this fallback subschema. This causes the oneOf requirement to pass entirely, skipping the intended validation.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=8
Re: [PATCH v3 08/13] dt-bindings: iio: adc: adi,ad4134: Document SPI connection mode
On 09/29, [email protected] wrote:
...
Quoted 14 lines
Quoted 1 line
(quoted diff) +0
-0@@ -141,13 +161,30 @@ required:[ ... ]
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml required: · line 180
Quoted 8 lines
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +8
-0+ - 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'][Severity: Medium]
Could this regression allow incomplete device trees to pass validation?
Quoted 7 lines
In JSON Schema, property value constraints only apply if the property is actually present in the node instance. Without including spi-rx-bus-width in the required array for the two-channel-chain branch, a node could omit the property entirely and bypass the multi-lane constraint, falling back to an incorrect 1-lane default at runtime.
Should spi-rx-bus-width be added to the required list here?
I'll do so and further test dt_binding_check catches any invalid combination of properties and values.
Quoted 11 lines
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml required: · line 185
Quoted 6 lines
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +5
-0+ properties: + adi,spi-mode: + const: two-channel-chain + spi-rx-bus-width: + const: 1, 1[Severity: Medium]
Does this YAML constraint evaluation cause a regression where valid inputs are rejected?
Quoted 7 lines
In YAML, const: 1, 1 parses as the literal string "1, 1". Since spi-rx-bus-width is defined as a uint32-array, the JSON representation is parsed as an array. Comparing an array against a string using const always fails.
This would prevent valid hardware descriptions from passing
dt_binding_checkvalidation. Should this be formatted as an explicit array to match the type?
Will fix that following the suggestion from Rob's review.
Quoted 8 lines
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml required: · line 187
Quoted 3 lines
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +2
-0+ - properties: + '#daisy-chained-devices': false[Severity: Medium]
Does this regression in the fallback branch bypass the intended daisy chain property enforcement?
Quoted 8 lines
Using oneOf with a fallback that evaluates '#daisy-chained-devices': false allows any configuration missing this property to evaluate to true for this branch.
For instance, if adi,spi-mode is set to one-channel-chain but the daisy chain property is missing, the schema matches exactly this fallback subschema. This causes the oneOf requirement to pass entirely, skipping the intended validation.
Will double check that and, if needed, change how the constraints are written.
Rob Herring (Arm)
maintainerRe: [PATCH v3 08/13] dt-bindings: iio: adc: adi,ad4134: Document SPI connection mode
In reply to Marcelo SchmittQuoted 8 lines · Marcelo Schmitt
Document how AD4134 chips are connected to the host SPI controller according to different wiring configurations.
Signed-off-by Marcelo Schmitt <[email protected]>---
Change log v2 -> v3:
- Adjusted spi-rx-bus-width constraints.
Quoted 9 lines
Unfortunately, I missed SPI connection mode properties when introducing AD4134 dt-doc and the device driver defaulted to a no-CS configuration. Due to that, conventional 4-wire mode can't be made default without leading to a regression. Still, updating the SPI mode default to 4-wire is a sensible thing to do later on if acceptable.
.../bindings/iio/adc/adi,ad4134.yaml | 51 ++++++++++++++++--- 1 file changed, 44 insertions(+), 7 deletions(-)
My bot found errors running 'make dt_binding_check' on your patch:
yamllint warnings/errors:./Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml:174:24: [warning] too few spaces after comma (commas) ./Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml:180:24: [warning] too few spaces after comma (commas)
dtschema/dtc warnings/errors:
doc reference errors (make refcheckdocs):
The base for the series is generally the latest rc1. A different dependency should be noted in *this* patch.
If you already ran 'make dt_binding_check' and didn't see the above error(s), then make sure 'yamllint' is installed and dt-schema is up to date:
pip3 install dtschema --upgrade
Please check and re-submit after running the above command yourself. Note that DT_SCHEMA_FILES can be set to your schema file to speed up checking your schema. However, it must be unset to test all examples with your schema.
Rob Herring
maintainerRe: [PATCH v3 08/13] dt-bindings: iio: adc: adi,ad4134: Document SPI connection mode
In reply to Marcelo SchmittQuoted 71 lines · Marcelo Schmitt
Document how AD4134 chips are connected to the host SPI controller according to different wiring configurations.
Signed-off-by Marcelo Schmitt <[email protected]>---
Change log v2 -> v3:
- Adjusted spi-rx-bus-width constraints.Unfortunately, I missed SPI connection mode properties when introducing AD4134 dt-doc and the device driver defaulted to a no-CS configuration. Due to that, conventional 4-wire mode can't be made default without leading to a regression. Still, updating the SPI mode default to 4-wire is a sensible thing to do later on if acceptable.
.../bindings/iio/adc/adi,ad4134.yaml | 51 ++++++++++++++++--- 1 file changed, 44 insertions(+), 7 deletions(-)Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +32
-7@@ -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,30 @@ 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:
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml required: · line 185
Quoted 10 lines
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +10
-0+ 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: + const: 1, 1
This is not valid. I think it evaluates to a string. You want:
items:
- const: 1
- const: 1
Rob
Re: [PATCH v3 08/13] dt-bindings: iio: adc: adi,ad4134: Document SPI connection mode
In reply to Marcelo SchmittQuoted 4 lines · Marcelo Schmitt
Document how AD4134 chips are connected to the host SPI controller according to different wiring configurations.
Signed-off-by Marcelo Schmitt <[email protected]>
Modulo the issue the bot flagged, I'm happy with this.
Quoted 9 lines
---
Change log v2 -> v3:
- Adjusted spi-rx-bus-width constraints.Unfortunately, I missed SPI connection mode properties when introducing AD4134 dt-doc and the device driver defaulted to a no-CS configuration. Due to that, conventional 4-wire mode can't be made default without leading to a regression. Still, updating the SPI mode default to 4-wire is a sensible thing to do later on if acceptable.
I dunno, it's probably not really a big deal to leave it as it is, it's just a default and it's probably just not worth affecting what users there may be.
Marcelo Schmitt
maintainerPATCH v3 9/13 dt-bindings: iio: adc: adi,ad4134: Document external multiplexer usage
In reply to Marcelo SchmittThe 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.
---
Change log v2 -> v3:
- Included the example right away with the doc update that documents it.
- Dropped mux provider from offload example.
Currently, SPI offloading is only supported in 4 wire mode. So, offloading wouldn't be usable if added before the 4-wire patch.
Detailed reasoning for the external multiplexer usage.
Before coming to the current solution, the following configuration was tried.
+-----------------------+ +-----------------+
| AD4134 | | SPI Controller |
| | | |
| SPI interface | | |
| for register SCLK |<--------------------------| SCLK |
| access CS |<--------------------------| CS |
| SDI |<--------------------------| SDO |
| SDO |---+ | |
| | | | |
| Data interface DOUT0 |---+---------------------->| SDI0 |
| for ADC data DOUT1 |-------------------------->| SDI1 |
| read back DOUT2 |-------------------------->| SDI2 |
| DOUT3 |-------------------------->| SDI3 |
| DCLK |<--------------------------| DCLK
| ODR |<------------------+ +->| Offload Trigger |
+-----------------------+ | | +-----------------+
| +--| PWM1 |
+-------| PWM0 |
+-------| GPIO |
+-----------------+Though, because DOUT0 never goes high-Z, the DOUT0 pin keeps driving the data line, causing register reads to fail.
Alternatively, we could have something like
+-----------------------+ +-----------------+
| AD4134 | | SPI Controller |
| | | |
| SPI interface | | |
| for register SCLK |<--------------------------| SCLK |
| access CS |<--------------------------| CS |
| SDI |<--------------------------| SDO |
| SDO |-------------------------->| SDI0 |
| | | |
| Data interface DOUT0 |-------------------------->| SDI1 |
| for ADC data DOUT1 |-------------------------->| SDI2 |
| read back DOUT2 |-------------------------->| SDI3 |
| DOUT3 |-------------------------->| SDI4 |
| DCLK |<--------------------------| DCLK
| ODR |<------------------+ +->| Offload Trigger |
+-----------------------+ | | +-----------------+
| +--| PWM1 |
+-------| PWM0 |
+-------| GPIO |
+-----------------+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 |
| +-------| GPIO0 |
+--------------| GPIO1 |
+-----------------+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 13).
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 |
+-------| GPIO |
+-----------------+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
@@ -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:
@@ -225,4 +239,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
Re: [PATCH v3 09/13] dt-bindings: iio: adc: adi,ad4134: Document external multiplexer usage
Quoted 134 lines · 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.
Signed-off-by Marcelo Schmitt <[email protected]>---
Change log v2 -> v3:
- Included the example right away with the doc update that documents it.
- Dropped mux provider from offload example.Currently, SPI offloading is only supported in 4 wire mode. So, offloading wouldn't be usable if added before the 4-wire patch.
Detailed reasoning for the external multiplexer usage.
Before coming to the current solution, the following configuration was tried.
+-----------------------+ +-----------------+ | AD4134 | | SPI Controller | | | | | | SPI interface | | | | for register SCLK |<--------------------------| SCLK | | access CS |<--------------------------| CS | | SDI |<--------------------------| SDO | | SDO |---+ | | | | | | | | Data interface DOUT0 |---+---------------------->| SDI0 | | for ADC data DOUT1 |-------------------------->| SDI1 | | read back DOUT2 |-------------------------->| SDI2 | | DOUT3 |-------------------------->| SDI3 | | DCLK |<--------------------------| DCLK | ODR |<------------------+ +->| Offload Trigger | +-----------------------+ | | +-----------------+ | +--| PWM1 | +-------| PWM0 | +-------| GPIO | +-----------------+Though, because DOUT0 never goes high-Z, the DOUT0 pin keeps driving the data line, causing register reads to fail.
Alternatively, we could have something like
+-----------------------+ +-----------------+ | AD4134 | | SPI Controller | | | | | | SPI interface | | | | for register SCLK |<--------------------------| SCLK | | access CS |<--------------------------| CS | | SDI |<--------------------------| SDO | | SDO |-------------------------->| SDI0 | | | | | | Data interface DOUT0 |-------------------------->| SDI1 | | for ADC data DOUT1 |-------------------------->| SDI2 | | read back DOUT2 |-------------------------->| SDI3 | | DOUT3 |-------------------------->| SDI4 | | DCLK |<--------------------------| DCLK | ODR |<------------------+ +->| Offload Trigger | +-----------------------+ | | +-----------------+ | +--| PWM1 | +-------| PWM0 | +-------| GPIO | +-----------------+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_STRIPEreads 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 | | +-------| GPIO0 | +--------------| GPIO1 | +-----------------+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 13).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 | +-------| GPIO | +-----------------+
Quoted 7 lines
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(+)
Marcelo Schmitt
maintainerPATCH v3 10/13 iio: adc: ad4134: Support SPI 4-wire mode
In reply to Marcelo SchmittAD4134 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 v2 -> v3:
- Now using SPI_MODE_X_MASK to update CPOL/CPHA bits.
- Refactored access mode locking to avoid umpaired calls to mux_state_select()/deselect().
Currently, SPI offloading is only supported in 4 wire mode. So, offloading wouldn't be usable if added before the 4-wire patch.
Detailed reasoning for the external multiplexer usage.
Before coming to the current solution, the following configuration was tried.
+-----------------------+ +-----------------+
| AD4134 | | SPI Controller |
| | | |
| SPI interface | | |
| for register SCLK |<--------------------------| SCLK |
| access CS |<--------------------------| CS |
| SDI |<--------------------------| SDO |
| SDO |---+ | |
| | | | |
| Data interface DOUT0 |---+---------------------->| SDI0 |
| for ADC data DOUT1 |-------------------------->| SDI1 |
| read back DOUT2 |-------------------------->| SDI2 |
| DOUT3 |-------------------------->| SDI3 |
| DCLK |<--------------------------| DCLK
| ODR |<------------------+ +->| Offload Trigger |
+-----------------------+ | | +-----------------+
| +--| PWM1 |
+-------| PWM0 |
+-------| GPIO |
+-----------------+Though, because DOUT0 never goes high-Z, the DOUT0 pin keeps driving the data line, causing register reads to fail.
Alternatively, we could have something like
+-----------------------+ +-----------------+
| AD4134 | | SPI Controller |
| | | |
| SPI interface | | |
| for register SCLK |<--------------------------| SCLK |
| access CS |<--------------------------| CS |
| SDI |<--------------------------| SDO |
| SDO |-------------------------->| SDI0 |
| | | |
| Data interface DOUT0 |-------------------------->| SDI1 |
| for ADC data DOUT1 |-------------------------->| SDI2 |
| read back 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 13).
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 | 260 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 248 insertions(+), 13 deletions(-)
drivers/iio/adc/Kconfig +1 -0
@@ -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 +247 -13
369 lines not on this page · raw message
Signature · 1 line
2.53.0
[email protected]
AI reviewRe: [PATCH v3 10/13] iio: adc: ad4134: Support SPI 4-wire mode
Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider: - [High] locking: mutex held across system calls in IIO buffer callbacks - [High] iio: broken multi-channel…
Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
- [High] locking: mutex held across system calls in IIO buffer callbacks
- [High] iio: broken multi-channel readback in 4-wire fallback mode
- [High] iio: ODR GPIO uninitialized in 4-wire mode preventing software triggers
- [High] iio: data race on shared rx_buf in NO_CS mode
- [Medium] spi: local mode state desynchronized on spi_setup() failure
- [Medium] regmap: data race on global static ad4134_regmap_config
--
commit 26369b61324efb5e168b91e351dda0ac9d6716f3
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
[ ... ]
Quoted 16 lines
drivers/iio/adc/ad4134.c +12
-0@@ -226,6 +246,90 @@ 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. Still, to prevent concurrent hardware interface +* configurations, callers must hold the access_lock. Finally, 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) __must_hold(&st->access_lock)
drivers/iio/adc/ad4134.c static const struct regmap_access_table ad4134_regmap_wr_table = { · line 270
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, the local spi->mode keeps the SPI_MODE_0 value but the hardware isn't updated. On the next call, cur_mode will match SPI_MODE_0, skipping spi_setup(). Could this leave the device permanently desynchronized from the controller?
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 14 lines
drivers/iio/adc/ad4134.c +5
-1@@ -268,7 +381,11 @@ static int ad4134_data_read(struct ad4134_state *st, unsigned int reg, {unsigned int i;u32 sample; -int ret; +int access_ret, ret; + + ret =ad4134_claim_sample_access (st); +if (ret) +return ret;/* * To be able to read data from all 4 channels through a single line, we
drivers/iio/adc/ad4134.c static int ad4134_data_read(struct ad4134_state *st, unsigned int reg, · line 402
Quoted 2 lines
drivers/iio/adc/ad4134.c +0
-0@@ -284,7 +401,7 @@ static int ad4134_data_read(struct ad4134_state *st, unsigned int reg, ret =spi_write_then_read (st->spi,NULL ,0 , st->rx_buf,BITS_TO_BYTES (AD4134_CHAN_PRECISION_BITS ));
[Severity: High]
Since ad4134_min_io_mode_setup() is not called in 4-wire mode, AD4134_DATA_FORMAT_SINGLE_CH_MODE is never set. Doesn't this mean ad4134_data_read() blindly assumes the data is serialized on DOUT0 when it isn't? Could this result in reading Channel 0 data four times instead of the other channels?
Quoted 3 lines
drivers/iio/adc/ad4134.c +1
-1if (ret) -return ret; + goto out_data_read_release;
[ ... ]
Quoted 20 lines
drivers/iio/adc/ad4134.c +16
-0@@ -381,6 +526,41 @@ static irqreturn_t ad4134_trigger_handler(int irq, void *p)return IRQ_HANDLED ; } +static int ad4134_buffer_postenable (struct iio_dev *indio_dev) +{ +struct ad4134_state *st =iio_priv (indio_dev); +int ret; + +mutex_lock (&st->access_lock); + + ret =ad4134_claim_sample_access (st); +if (ret) + goto out_unlock; + +return 0 ; + +out_unlock: +mutex_unlock (&st->access_lock); +return ret;
drivers/iio/adc/ad4134.c static irqreturn_t ad4134_trigger_handler(int irq, void *p) · line 554
Quoted 10 lines
drivers/iio/adc/ad4134.c +10
-0+} + +static int ad4134_buffer_predisable (struct iio_dev *indio_dev) +{ +struct ad4134_state *st =iio_priv (indio_dev); +int ret; + + ret =ad4134_release_sample_access (st); + +mutex_unlock (&st->access_lock);
[Severity: High]
Is it intentional to hold st->access_lock across system calls here? Returning to user space with the mutex held violates lock ownership semantics and can trigger lockdep splats. Furthermore, could this deadlock any subsequent sysfs regmap accesses while the buffer is enabled?
Quoted 3 lines
drivers/iio/adc/ad4134.c +3
-0+ +return ret; +}
[ ... ]
drivers/iio/adc/ad4134.c static int ad4134_probe(struct spi_device *spi) · line 776
Quoted 10 lines
drivers/iio/adc/ad4134.c +5
-0@@ -588,15 +768,69 @@ static int ad4134_probe(struct spi_device *spi)if (ret)return ret; + ret =devm_mutex_init (dev, &st->access_lock); +if (ret) +return ret; + + ad4134_regmap_config.lock_arg = st; st->regmap =devm_regmap_init (dev,NULL , st, &ad4134_regmap_config);
[Severity: Medium]
Is it safe to modify the global ad4134_regmap_config structure during probe? If multiple devices probe concurrently, could this cause a data race where one device's lock_arg overwrites another's before devm_regmap_init() copies it?
Quoted 3 lines
drivers/iio/adc/ad4134.c +0
-0if (IS_ERR (st->regmap))return dev_err_probe (dev,PTR_ERR (st->regmap),"failed to initialize regmap" );
[ ... ]
Quoted 10 lines
drivers/iio/adc/ad4134.c +10
-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] =
drivers/iio/adc/ad4134.c static int ad4134_probe(struct spi_device *spi) · line 817
Quoted 10 lines
drivers/iio/adc/ad4134.c +10
-0+devm_mux_state_get_optional_selected (dev,"reg_access" ); +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 {
[Severity: High]
In 4-wire mode, ad4134_min_io_mode_setup() is bypassed. Since st->odr_gpio is only retrieved inside ad4134_min_io_mode_setup(), won't it remain uninitialized (NULL)? Will this cause all software triggers using gpiod_set_value_cansleep(st->odr_gpio, ...) to silently fail in 4-wire mode?
Quoted 6 lines
drivers/iio/adc/ad4134.c +6
-0+/* +* This controls a multiplexer OUTSIDE OF AD4134 SILICON. +* See AD4134 IIO documentation for details. +*/ + st->mux_st[AD4134_SDO_INPUT ] =devm_mux_state_get (dev,"reg_access" ); +if (IS_ERR (st->mux_st[AD4134_SDO_INPUT ]))
drivers/iio/adc/ad4134.c static int ad4134_probe(struct spi_device *spi) · line 833
Quoted 10 lines
drivers/iio/adc/ad4134.c +10
-0+return dev_err_probe (dev,PTR_ERR (st->mux_st[AD4134_SDO_INPUT ]), +"failed to get reg_access mux-state\n" ); + + st->mux_st[AD4134_DOUT0_INPUT ] =devm_mux_state_get (dev,"data_read" ); +if (IS_ERR (st->mux_st[AD4134_DOUT0_INPUT ])) +return dev_err_probe (dev,PTR_ERR (st->mux_st[AD4134_DOUT0_INPUT ]), +"failed to get data_read mux-state\n" ); + + indio_dev->setup_ops = &ad4134_buffer_setup_ops; + }
[Severity: High]
Since setup_ops is only assigned for 4-wire mode, won't NO_CS mode bypass ad4134_buffer_postenable() entirely? If so, doesn't that mean ad4134_trigger_handler() uses st->rx_buf without holding st->access_lock, creating a data race with concurrent sysfs regmap accesses?
Quoted 3 lines
drivers/iio/adc/ad4134.c +0
-0ret = devm_iio_triggered_buffer_setup(dev, indio_dev, iio_pollfunc_store_time,
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=10
Re: [PATCH v3 10/13] iio: adc: ad4134: Support SPI 4-wire mode
On 09/29, [email protected] wrote:
...
Quoted 20 lines
Quoted 20 lines
drivers/iio/adc/ad4134.c +20
-0+/* +* 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. Still, to prevent concurrent hardware interface +* configurations, callers must hold the access_lock. Finally, 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) __must_hold(&st->access_lock) +{ +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);
Quoted 9 lines
Review
Quoted 2 lines
(quoted diff) +2
-0+ if (ret) + return ret;[Severity: Medium]
Ifspi_setup()fails, the localspi->modekeeps theSPI_MODE_0value but the hardware isn't updated. On the next call,cur_modewill matchSPI_MODE_0, skippingspi_setup(). Could this leave the device permanently desynchronized from the controller?
If spi_setup() fails it will be tried again on the next register or sample read. So, the device would be desynchronized only when not being used.
...
Quoted 4 lines
Quoted 4 lines
drivers/iio/adc/ad4134.c +0
-0/* * To be able to read data from all 4 channels through a single line, we @@ -284,7 +401,7 @@ static int ad4134_data_read(struct ad4134_state *st, unsigned int reg, ret = spi_write_then_read(st->spi, NULL, 0, st->rx_buf,
Quoted 8 lines
drivers/iio/adc/ad4134.c static int ad4134_data_read(struct ad4134_state *st, unsigned int reg, · line 402
Quoted 1 line
drivers/iio/adc/ad4134.c +0
-0BITS_TO_BYTES(AD4134_CHAN_PRECISION_BITS));[Severity: High]
Sincead4134_min_io_mode_setup()is not called in 4-wire mode,AD4134_DATA_FORMAT_SINGLE_CH_MODEis never set. Doesn't this meanad4134_data_read()blindly assumes the data is serialized on DOUT0 when it isn't? Could this result in reading Channel 0 data four times instead of the other channels?
The default on device reset is to output data from all four channels serialized through DOUT0. Anyways, will make the configuration explicit in case the device is not reset.
Quoted 6 lines
Quoted 6 lines
drivers/iio/adc/ad4134.c +6
-0+static int ad4134_buffer_predisable (struct iio_dev *indio_dev) +{ +struct ad4134_state *st =iio_priv (indio_dev); +int ret; + + ret =ad4134_release_sample_access (st);
Quoted 8 lines
Review
Quoted 2 lines
(quoted diff) +2
-0+ + mutex_unlock(&st->access_lock);[Severity: High]
Is it intentional to holdst->access_lockacross system calls here? Returning to user space with the mutex held violates lock ownership semantics and can trigger lockdep splats. Furthermore, could this deadlock any subsequent sysfs regmap accesses while the buffer is enabled?
I'm not sure about this one. The intent is to prevent sysfs regmap access while the buffer is enabled. IIO direct/buffer mode locking should provide that, no? The rationale for the two mutexes is for access_lock to avoid concurrent updates to the external multiplexer and for sync_lock to protect read/modify/write sequences. Maybe IIO direct/buffer mode locking + sync_lock is enough?
Quoted 9 lines
Quoted 4 lines
drivers/iio/adc/ad4134.c +3
-0+ +return ret; +}[ ... ]
Quoted 4 lines
drivers/iio/adc/ad4134.c +0
-0@@ -588,15 +768,69 @@ static int ad4134_probe(struct spi_device *spi)if (ret)return ret;
Quoted 12 lines
drivers/iio/adc/ad4134.c static int ad4134_probe(struct spi_device *spi) · line 776
Quoted 6 lines
drivers/iio/adc/ad4134.c +5
-0+ ret =devm_mutex_init (dev, &st->access_lock); +if (ret) +return ret; + + ad4134_regmap_config.lock_arg = st; st->regmap =devm_regmap_init (dev,NULL , st, &ad4134_regmap_config);[Severity: Medium]
Is it safe to modify the globalad4134_regmap_configstructure during probe? If multiple devices probe concurrently, could this cause a data race where one device'slock_argoverwrites another's beforedevm_regmap_init()copies it?
Not sure. Should it lock on a mutex before editing the regmap_config. Maybe I get rid of access_lock and make regmap_config const again.
Quoted 5 lines
[Severity: High]
In 4-wire mode,ad4134_min_io_mode_setup()is bypassed. Sincest->odr_gpiois only retrieved insidead4134_min_io_mode_setup(), won't it remain uninitialized (NULL)? Will this cause all software triggers usinggpiod_set_value_cansleep(st->odr_gpio, ...)to silently fail in 4-wire mode?
Okay, that seems to be an issue. Will make the device request the GPIO if offload/PWM is not available.
Quoted 15 lines
Quoted 15 lines
drivers/iio/adc/ad4134.c +14
-0+/* +* This controls a multiplexer OUTSIDE OF AD4134 SILICON. +* See AD4134 IIO documentation for details. +*/ + st->mux_st[AD4134_SDO_INPUT ] =devm_mux_state_get (dev,"reg_access" ); +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" ); + + st->mux_st[AD4134_DOUT0_INPUT ] =devm_mux_state_get (dev,"data_read" ); +if (IS_ERR (st->mux_st[AD4134_DOUT0_INPUT ])) +return dev_err_probe (dev,PTR_ERR (st->mux_st[AD4134_DOUT0_INPUT ]), +"failed to get data_read mux-state\n" ); +
Quoted 9 lines
drivers/iio/adc/ad4134.c static int ad4134_probe(struct spi_device *spi) · line 833
Quoted 2 lines
drivers/iio/adc/ad4134.c +2
-0+ indio_dev->setup_ops = &ad4134_buffer_setup_ops; + }[Severity: High]
Sincesetup_opsis only assigned for 4-wire mode, won'tNO_CSmode bypassad4134_buffer_postenable()entirely? If so, doesn't that meanad4134_trigger_handler()usesst->rx_bufwithout holdingst->access_lock, creating a data race with concurrent sysfs regmap accesses?
NO_CS/minimum I/O mode doesn't need to constantly switch the external multiplexer and can leave that in reg_access state. Also, since minimum I/O always operate in SPI mode 0, nothing that access_lock protects is really used.
Jonathan Cameron
maintainerRe: [PATCH v3 10/13] iio: adc: ad4134: Support SPI 4-wire mode
Quoted 16 lines
Quoted 15 lines
drivers/iio/adc/ad4134.c static irqreturn_t ad4134_trigger_handler(int irq, void *p) · line 554
Quoted 9 lines
drivers/iio/adc/ad4134.c +8
-0+static int ad4134_buffer_predisable (struct iio_dev *indio_dev) +{ +struct ad4134_state *st =iio_priv (indio_dev); +int ret; + + ret =ad4134_release_sample_access (st); + +mutex_unlock (&st->access_lock);[Severity: High]
Is it intentional to holdst->access_lockacross system calls here? Returning to user space with the mutex held violates lock ownership semantics and can trigger lockdep splats. Furthermore, could this deadlock any subsequent sysfs regmap accesses while the buffer is enabled?
Quoted 5 lines
I'm not sure about this one. The intent is to prevent sysfs regmap access while the buffer is enabled. IIO direct/buffer mode locking should provide that, no? The rationale for the two mutexes is for
access_lockto avoid concurrent updates to the external multiplexer and forsync_lockto protect read/modify/write sequences. Maybe IIO direct/buffer mode locking +sync_lockis enough?
Technically claiming mode would be enough and if the locking is only coupled to "in buffered mode or not in buffered mode" I'm fine with that. However, if you need to serialize for other reasons we probably need to grow a more complex solution with a lock and a flag (similar to what the IIO mode stuff is doing) so as to avoid holding a lock across syscalls as this points out.
Quoted 22 lines
Quoted 10 lines
Quoted 5 lines
drivers/iio/adc/ad4134.c +3
-0+ +return ret; +}[ ... ]
Quoted 4 lines
drivers/iio/adc/ad4134.c +0
-0@@ -588,15 +768,69 @@ static int ad4134_probe(struct spi_device *spi)if (ret)return ret;Quoted 12 lines
drivers/iio/adc/ad4134.c static int ad4134_probe(struct spi_device *spi) · line 776
Quoted 6 lines
drivers/iio/adc/ad4134.c +5
-0+ ret =devm_mutex_init (dev, &st->access_lock); +if (ret) +return ret; + + ad4134_regmap_config.lock_arg = st; st->regmap =devm_regmap_init (dev,NULL , st, &ad4134_regmap_config);[Severity: Medium]
Is it safe to modify the globalad4134_regmap_configstructure during probe? If multiple devices probe concurrently, could this cause a data race where one device'slock_argoverwrites another's beforedevm_regmap_init()copies it?
Quoted 2 lines
Not sure. Should it lock on a mutex before editing the
regmap_config. Maybe I get rid ofaccess_lockand makeregmap_configconst again.
Good catch here.
You shouldn't be modifying the global. The mutex solution works because devm_regmap_init() doesn't keep any references to the config anyway but I'd just use a local copy instead. One on the stack should be fine.
Jonathan
Marcelo Schmitt
maintainerPATCH v3 11/13 dt-bindings: iio: adc: adi,ad4134: Document PWM usage
In reply to Marcelo SchmittAdvanced setups may connect a PWM signal to AD4134 ODR pin for faster output data rates.
---
Change log v2 -> v3:
- Dropped odr-gpios from offload example.
- Now that the 4-wire example comes earlier, the pwm is only now added to that.
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml | 6 ++++++ 1 file changed, 6 insertions(+)
Documentation/devicetree/bindings/iio/adc/adi,ad4134.yaml +6 -0
@@ -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
@@ -251,9 +255,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
Marcelo Schmitt
maintainerPATCH v3 12/13 iio: adc: ad4134: Support high-speed data capture
In reply to Marcelo SchmittMake use of SPI transfer offloading to speed up data capture, enabling data acquisition at faster sample rates (up to 1.496 MSPS).
---
Change log v2 -> v3:
- Dropped unreachable code on offload setup.
- Fixed sampling frequency validation check.
- Avoided division by zero when external clock is not provided.
- Follow LIFO teardown order on offload buffer disable.
- Set correct buffer size to read all channels in offload mode.
- Disallowed single-read when setup for SPI offloading.
drivers/iio/adc/Kconfig | 5 + drivers/iio/adc/ad4134.c | 395 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 391 insertions(+), 9 deletions(-)
drivers/iio/adc/Kconfig +5 -0
@@ -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 +386 -9
491 lines not on this page · raw message
Signature · 1 line
2.53.0
[email protected]
AI reviewRe: [PATCH v3 12/13] iio: adc: ad4134: Support high-speed data capture
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider: - [Medium] iio: adc: ad4134: off-by-one error rejects maximum sample rate - [Medium] iio: adc: ad4134: PWM…
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Medium] iio: adc: ad4134: off-by-one error rejects maximum sample rate
- [Medium] iio: adc: ad4134: PWM left running on driver unbind
- [Low] iio: adc: ad4134: exposing unsupported IIO_CHAN_INFO_RAW in offload mode --
commit e47f312fc16187aac53abe53836e642d8e031a66
Author: Marcelo Schmitt <[email protected]>
iio: adc: ad4134: Support high-speed data capture
This commit introduces SPI transfer offloading to speed up data capture for the AD4134 ADC. This enhancement enables data acquisition at faster sample rates up to 1.496 MSPS.
Quoted 4 lines
drivers/iio/adc/ad4134.c +0
-0
[ ... ]
drivers/iio/adc/ad4134.c static const struct iio_chan_spec ad4134_chan_set[] = { · line 185
Quoted 13 lines
drivers/iio/adc/ad4134.c +9
-0@@ -160,6 +174,39 @@ static const struct iio_chan_spec ad4134_chan_set[] = { IIO_CHAN_SOFT_TIMESTAMP(4), }; +/* +* Hardcoded 32-bit storagebits and CPU endianness because the currently +* available HDL only supports that configuration. +*/ +#define AD4134_OFFLOAD_CHANNEL (_index) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = (_index), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
[Severity: Low]
Is it intentional to expose the raw voltage attribute for offload channels?
The IIO_CHAN_INFO_RAW bit is set in the info_mask_separate here, exposing the sysfs attribute. However, ad4134_read_raw() is modified later in this patch to unconditionally return -EPROTONOSUPPORT for raw reads when offload is enabled. Does this clutter the interface with an attribute that is guaranteed to always fail?
Quoted 2 lines
drivers/iio/adc/ad4134.c +2
-0+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \
[ ... ]
Quoted 9 lines
drivers/iio/adc/ad4134.c +5
-0@@ -489,6 +544,92 @@ static struct regmap_config ad4134_regmap_config = { .max_register = AD4134_CH_VREG(ARRAY_SIZE(ad4134_chan_set) - 1), }; +static int ad4134_update_conversion_rate (struct ad4134_state *st, +unsigned int freq_Hz) +{ +struct spi_offload_trigger_config config = st->offload_trigger_config; +struct pwm_waveform odr_wf = { };
drivers/iio/adc/ad4134.c static struct regmap_config ad4134_regmap_config = { · line 561
Quoted 10 lines
drivers/iio/adc/ad4134.c +10
-0+u64 offload_period_ns; +u64 offload_offset_ns; +u64 odr_high_time_ns; +unsigned int count; +u64 target_ns; +int ret; + +if (!in_range (freq_Hz,AD4134_MIN_ODR_FREQ_HZ , +AD4134_MAX_ODR_FREQ_HZ -AD4134_MIN_ODR_FREQ_HZ )) +return -ERANGE ;
[Severity: Medium]
Does this validation check inadvertently reject the maximum supported frequency?
The in_range(val, start, len) macro strictly checks if val < start + len. If a user requests exactly AD4134_MAX_ODR_FREQ_HZ, the condition evaluates to MAX < MAX (which is false) and incorrectly returns -ERANGE.
Quoted 2 lines
drivers/iio/adc/ad4134.c +2
-0+ + odr_wf.period_length_ns =DIV_ROUND_UP_ULL (NSEC_PER_SEC , freq_Hz);
[ ... ]
drivers/iio/adc/ad4134.c static struct regmap_config ad4134_regmap_config = { · line 622
Quoted 6 lines
drivers/iio/adc/ad4134.c +6
-0+/* Check the PWM periods remain the same */ + offload_period_ns =DIV_ROUND_UP_ULL (HZ_PER_GHZ , config.periodic.frequency_hz); +if (odr_wf.period_length_ns != offload_period_ns) +return -EDOM ; + + ret =pwm_set_waveform_might_sleep (st->odr_pwm, &odr_wf, false);
[Severity: Medium]
Could this leave the PWM hardware running indefinitely after the driver unbinds?
The ODR PWM is retrieved via devm_pwm_get() and started here, but no explicit cleanup callback or devm action is registered to stop the waveform. When the driver unloads, pwm_put() will drop the reference, but the hardware could continue running, resulting in a resource leak.
Quoted 9 lines
drivers/iio/adc/ad4134.c +9
-0+if (ret) +return ret; + + st->offload_trigger_config = config; + st->odr_wf = odr_wf; + st->odr_hz =DIV_ROUND_UP_ULL (NSEC_PER_SEC , odr_wf.period_length_ns); + +return 0 ; +}
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=12
Re: [PATCH v3 12/13] iio: adc: ad4134: Support high-speed data capture
On 09/29, [email protected] wrote:
...
Quoted 9 lines
drivers/iio/adc/ad4134.c static const struct iio_chan_spec ad4134_chan_set[] = { · line 185
Quoted 5 lines
drivers/iio/adc/ad4134.c +5
-0+#define AD4134_OFFLOAD_CHANNEL (_index) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = (_index), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \[Severity: Low]
Is it intentional to expose the raw voltage attribute for offload channels?
Quoted 5 lines
The
IIO_CHAN_INFO_RAWbit is set in theinfo_mask_separatehere, exposing the sysfs attribute. However,ad4134_read_raw()is modified later in this patch to unconditionally return-EPROTONOSUPPORTfor raw reads when offload is enabled. Does this clutter the interface with an attribute that is guaranteed to always fail?
Oh, I should've done that. Will change accordingly.
Quoted 8 lines
drivers/iio/adc/ad4134.c static struct regmap_config ad4134_regmap_config = { · line 561
Quoted 3 lines
drivers/iio/adc/ad4134.c +3
-0+if (!in_range (freq_Hz,AD4134_MIN_ODR_FREQ_HZ , +AD4134_MAX_ODR_FREQ_HZ -AD4134_MIN_ODR_FREQ_HZ )) +return -ERANGE ;[Severity: Medium]
Does this validation check inadvertently reject the maximum supported frequency?
Quoted 4 lines
The
in_range(val, start, len)macro strictly checks if val < start + len. If a user requests exactlyAD4134_MAX_ODR_FREQ_HZ, the condition evaluates to MAX < MAX (which is false) and incorrectly returns-ERANGE.
For cases where the range doesn't start with 0 or 1, in_range() becomes a bit harder to read.
if (freq_Hz < AD4134_MIN_ODR_FREQ_HZ || freq_Hz > AD4134_MAX_ODR_FREQ_HZ)
return -ERANGE;
would have been simpler, IMHO.
Anyways, will fix this and all other issues reported.
Re: [PATCH v3 12/13] iio: adc: ad4134: Support high-speed data capture
In reply to Marcelo SchmittQuoted 2 lines · Marcelo Schmitt
Make use of SPI transfer offloading to speed up data capture, enabling data acquisition at faster sample rates (up to 1.496 MSPS).
...
Quoted 7 lines
drivers/iio/adc/ad4134.c +7
-0+ odr_wf.period_length_ns =DIV_ROUND_UP_ULL (NSEC_PER_SEC , freq_Hz); +/* +* Set the PWM duty cycle to keep ODR high for at least minimum required +* time. If the rounded PWM's value is less than the minimum required, +* increase the target value by 10 and attempt to round the waveform +* again, until the minimum (or try count limit) is reached. +*/
drivers/iio/adc/ad4134.c static struct regmap_config ad4134_regmap_config = { · line 579
Quoted 10 lines
drivers/iio/adc/ad4134.c +10
-0+ odr_high_time_ns =div64_ul (6ULL *NSEC_PER_SEC , st->sys_clk_hz); + target_ns =0 ; + count =100 ; +do { + target_ns +=10 ;/* Increment by PWM duty cycle period */ + odr_wf.duty_length_ns = target_ns; + ret =pwm_round_waveform_might_sleep (st->odr_pwm, &odr_wf); +if (ret) +return ret; + }while (count-- && odr_wf.duty_length_ns < odr_high_time_ns);
In do {} while () cases the counter check should be --count, otherwise it's off-by-one (non-critical) mistake, you will have 101 iterations instead of 100.
Quoted 21 lines
drivers/iio/adc/ad4134.c +21
-0+/* Check the minimum ODR high time is met */ +if (odr_wf.duty_length_ns < odr_high_time_ns) +return -EDOM ; + +if (odr_wf.period_length_ns <2 * odr_high_time_ns) +return -EDOM ; + +/* +* Configure SPI offload PWM trigger. +* For gated DCLK, the minimum required time between ODR rising edge +* and DCLK rising edge is the sum of ODR high time and ODR falling +* edge to DCLK rising edge time. Delay the offload trigger for at least +* that amount of time so the ADC sample data will be available when the +* SPI transfer begin. +* +* Use the same period as ODR PWM to avoid timing issues. +* Convert back from period to frequency for the SPI offload API. +*/ + offload_period_ns = odr_wf.period_length_ns; + config.periodic.frequency_hz =DIV_ROUND_UP_ULL (HZ_PER_GHZ , offload_period_ns); + offload_offset_ns = odr_high_time_ns +AD4134_DCLK_RISING_OFFSET_NS ;
drivers/iio/adc/ad4134.c static struct regmap_config ad4134_regmap_config = { · line 611
Quoted 10 lines
drivers/iio/adc/ad4134.c +10
-0+ count =100 ; +do { + config.periodic.offset_ns = offload_offset_ns; + ret =spi_offload_trigger_validate (st->offload_trigger, &config); +if (ret) +return ret; + + offload_offset_ns +=10 ; + }while (count-- && config.periodic.offset_ns < odr_high_time_ns + +AD4134_DCLK_RISING_OFFSET_NS );
Ditto.
...
drivers/iio/adc/ad4134.c static int ad4134_clock_select(struct ad4134_state *st) · line 1082
Quoted 2 lines
drivers/iio/adc/ad4134.c +2
-0+if (!st->sys_clk_hz) +return dev_err_probe (dev, -EINVAL ,"0 Hz external clock\n" );
Perhaps -ERANGE?
...
Address the above only if you need a new version, otherwise they are not a big deal.
Signature · 2 lines
With Best Regards, Andy Shevchenko
Marcelo Schmitt
maintainerPATCH v3 13/13 Docs: iio: Add AD4134
In reply to Marcelo SchmittAdd initial documentation for the ad4134 IIO driver.
---
Change log v2 -> v3:
- Corrected AD4134 IIO Doc to only show the PWM connected to ODR on offload diagrams.
Documentation/iio/ad4134.rst | 128 +++++++++++++++++++++++++++++++++++ Documentation/iio/index.rst | 1 + MAINTAINERS | 1 + 3 files changed, 130 insertions(+) create mode 100644 Documentation/iio/ad4134.rst
Documentation/iio/ad4134.rst new file +128 -0
@@ -0,0 +1,128 @@ +.. SPDX-License-Identifier: GPL-2.0-only + +============= +AD4134 driver +============= + +Device driver for Analog Devices Inc. AD4134 and similar ADCs. + +Supported devices +================= + +* `AD4134 <https://www.analog.com/AD4134>`_ +* `AD7134 <https://www.analog.com/AD7134>`_ + +Wiring connections +------------------ + +AD4134 and similar ADCs can operate in a few different wiring configurations. +Because AD4134 also supports control modes other than through SPI protocol, +the following pins must be statically set for all of the wiring modes described +below. + ++----------------------------+----------------------+--------------------+ +| Pin Function | Level | Description | ++============================+======================+====================+ +| PIN/SPI | High | SPI control mode | ++----------------------------+----------------------+--------------------+ +| MODE | Low | ASRC slave mode | ++----------------------------+----------------------+--------------------+ +| DEC0/DCLKI | Low | DCLK input | ++----------------------------+----------------------+--------------------+ +| DEC1/DCLKMODE | Low | Gated DCLK | ++----------------------------+----------------------+--------------------+ + +Minimum I/O mode +^^^^^^^^^^^^^^^^ + +The minimum I/O mode wiring allows AD4134 register and data access with the +conventional set of SPI bus lines. In this mode, the peripheral CS pin must be +tied to GND. A possible connection schema that sets AD4134 digital interface for +minimum I/O mode is:: + + +------------+ +-------------+ + | AD4134 | | SPI | + | | | Controller | + | DCLK |<--+ | | + | SCLK |<--+---- | SCLK | + | SDI |<--------| SDO | + | SDO |-------->| SDI | + | ODR |<--------| GPIO | + | CS |----+ | | + +------------+ | +-------------+ + V + GND + +Set ``adi,spi-mode = "no-cs"`` in device tree to indicate the device is +connected in minimum I/O wiring configuration. + +SPI 4-wire mode - single lane +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The conventional SPI 4-wire configuration except a multiplexer is used to +select between SDO (for register data) and DOUT0 (for ADC sample data).:: + + +-----------------------+ +-----------------+ + | AD4134 | | SPI Controller | + | | | | + | SPI interface | | | + | for register SCLK |<------------------------| SCLK | + | access CS |<------------------------| CS | + | SDI |<------------------------| SDO | + | SDO |------->|¯¯¯¯\ | | + | Data interface | |MUX >--------->| SDI | + | for ADC sample DOUT0 |------->|____/ | | + | data read | ^ | | + | | | | | + | 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
@@ -23,6 +23,7 @@ Industrial I/O Kernel Drivers ad4000 ad4030 ad4062 + ad4134 ad4691 ad4695 ad7191
MAINTAINERS +1 -0
@@ -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