[PATCH v4 9/9] iio: adc: ad7768-1: add support for multiple chip aggregation

From: Jonathan Santos

Date: Tue Oct 20 2026 - 21:59:48 EST


The AD7768-1 family is a single-channel ADC, but it is designed to allow
connecting multiple devices to the same SPI controller, each on a
dedicated CS and data lane, clocked synchronously, and sharing SDO and
SCLK. The number of aggregated devices is derived from the number of
CS.

The DRDY pins are combined to trigger the data interrupt when all
devices are ready, and since the synchronization pins are tied, they
stay in synchrony.

To reflect the multidevice setup, IIO channels are dynamically set
based on the number of devices. Restrict buffered capture to the
all-channels scan mask, since all devices sample in lockstep. Register
an ancillary SPI device per lane for individual direct reads, and enable
SPI_MULTI_LANE_MODE_STRIPE in offload mode to interleave samples from all
lanes into the DMA stream.

Since all devices must be in sync, all configurations that affect the
sampling rate are unified, so they always have the same sampling
frequency.

Signed-off-by: Jonathan Santos <Jonathan.Santos@xxxxxxxxxx>
---
Changes in v4:
* Fixed the st->offload_xfer.len calculation to account for multiple
devices.
* The number of aggregated devices is now defined by the number of CS
instead of number of lanes.
* Used devm_bitmap_zalloc() and bitmap_set() for the masks allocation
and definition, as requested.

Changes in v3:
* Modified channel mask allocation on ad7768_parse_aaf_gain() to get
a static value, Since we assume the family is single channel. Added a
comment explaining.

Changes in v2:
* New patch.
---
drivers/iio/adc/ad7768-1.c | 100 +++++++++++++++++++++++++++++++++----
1 file changed, 90 insertions(+), 10 deletions(-)

diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c
index 3972821c295a..064b4b394a2e 100644
--- a/drivers/iio/adc/ad7768-1.c
+++ b/drivers/iio/adc/ad7768-1.c
@@ -6,6 +6,7 @@
*/
#include <linux/array_size.h>
#include <linux/bitfield.h>
+#include <linux/bitmap.h>
#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/completion.h>
@@ -20,6 +21,7 @@
#include <linux/minmax.h>
#include <linux/module.h>
#include <linux/mutex.h>
+#include <linux/overflow.h>
#include <linux/rational.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
@@ -120,7 +122,8 @@

#define AD7768_TRIGGER_SOURCE_SYNC_IDX 0

-#define AD7768_MAX_CHANNELS 1
+#define AD7768_MAX_CHANNELS 1
+#define AD7768_MAX_AGGR_DEVICES 4

#define ADAQ7768_PGA_PINS 3

@@ -300,10 +303,12 @@ struct ad7768_chip_info {

struct ad7768_state {
struct spi_device *spi;
+ struct spi_device *spi_anc[AD7768_MAX_AGGR_DEVICES];
struct spi_offload *offload;
struct spi_offload_trigger *offload_trigger;
struct regmap *regmap;
struct regmap *regmap24;
+ struct regmap *regmap24_anc[AD7768_MAX_AGGR_DEVICES];
int vref_uv;
struct regulator_dev *vcm_rdev;
unsigned int vcm_output_sel;
@@ -322,11 +327,12 @@ struct ad7768_state {
struct gpio_descs *pga_gpios;
struct gpio_desc *gpio_sync_in;
struct gpio_desc *gpio_reset;
- const char *labels[AD7768_MAX_CHANNELS];
+ const char *labels[AD7768_MAX_CHANNELS * AD7768_MAX_AGGR_DEVICES];
struct gpio_chip gpiochip;
struct spi_transfer offload_xfer;
struct spi_message offload_msg;
const struct ad7768_chip_info *chip;
+ u8 num_devices;
bool en_spi_sync;
struct mutex pga_lock; /* protect device internal state (PGA) */
/*
@@ -335,7 +341,7 @@ struct ad7768_state {
*/
union {
struct {
- __be32 chan;
+ __be32 chan[AD7768_MAX_AGGR_DEVICES];
aligned_s64 timestamp;
} scan;
__be32 d32;
@@ -478,9 +484,10 @@ static int ad7768_set_mode(struct ad7768_state *st,
AD7768_CONV_MODE_MSK, AD7768_CONV_MODE(mode));
}

-static int ad7768_scan_direct(struct iio_dev *indio_dev)
+static int ad7768_scan_direct(struct iio_dev *indio_dev, unsigned int chan)
{
struct ad7768_state *st = iio_priv(indio_dev);
+ struct regmap *regmap;
int readval, ret;

reinit_completion(&st->completion);
@@ -492,7 +499,8 @@ static int ad7768_scan_direct(struct iio_dev *indio_dev)
if (!ret)
return -ETIMEDOUT;

- ret = regmap_read(st->regmap24, AD7768_REG24_ADC_DATA, &readval);
+ regmap = st->num_devices > 1 ? st->regmap24_anc[chan] : st->regmap24;
+ ret = regmap_read(regmap, AD7768_REG24_ADC_DATA, &readval);
if (ret)
return ret;

@@ -989,7 +997,7 @@ static int ad7768_read_raw(struct iio_dev *indio_dev,
if (!iio_device_claim_direct(indio_dev))
return -EBUSY;

- ret = ad7768_scan_direct(indio_dev);
+ ret = ad7768_scan_direct(indio_dev, chan->channel);

iio_device_release_direct(indio_dev);
if (ret < 0)
@@ -1388,9 +1396,11 @@ static int ad7768_offload_buffer_postenable(struct iio_dev *indio_dev)
if (IS_ERR(scan_type))
return PTR_ERR(scan_type);

- st->offload_xfer.len = spi_bpw_to_bytes(scan_type->realbits);
+ st->offload_xfer.len = spi_bpw_to_bytes(scan_type->realbits) * st->num_devices;
st->offload_xfer.bits_per_word = scan_type->realbits;
st->offload_xfer.offload_flags = SPI_OFFLOAD_XFER_RX_STREAM;
+ if (st->num_devices > 1)
+ st->offload_xfer.multi_lane_mode = SPI_MULTI_LANE_MODE_STRIPE;

spi_message_init_with_transfers(&st->offload_msg, &st->offload_xfer, 1);
st->offload_msg.offload = st->offload;
@@ -1694,6 +1704,63 @@ static int ad7768_parse_aaf_gain(struct device *dev, struct ad7768_state *st)
return 0;
}

+static int ad7768_probe_multidevices(struct iio_dev *indio_dev)
+{
+ struct ad7768_state *st = iio_priv(indio_dev);
+ struct device *dev = indio_dev->dev.parent;
+ struct iio_chan_spec *channels;
+ unsigned int mask_longs;
+ unsigned long *masks;
+ size_t num_chans;
+ unsigned int i;
+ u8 cs;
+
+ num_chans = size_mul(st->num_devices, st->chip->num_channels);
+ channels = devm_kcalloc(dev, num_chans, sizeof(*channels), GFP_KERNEL);
+ if (!channels)
+ return -ENOMEM;
+
+ indio_dev->num_channels = num_chans;
+ for (i = 0; i < num_chans; i++) {
+ struct iio_chan_spec *chan = &channels[i];
+
+ *chan = *st->chip->channel_spec;
+ chan->channel = i;
+ chan->scan_index = i;
+ }
+
+ indio_dev->channels = channels;
+
+ /*
+ * One scan mask with all devices enabled, plus a zero terminator. Each
+ * mask spans BITS_TO_LONGS(masklength) longs.
+ */
+ mask_longs = BITS_TO_LONGS(indio_dev->num_channels);
+ masks = devm_bitmap_zalloc(dev, 2 * mask_longs * BITS_PER_LONG, GFP_KERNEL);
+ if (!masks)
+ return -ENOMEM;
+
+ bitmap_set(masks, 0, num_chans);
+ indio_dev->available_scan_masks = masks;
+
+ /* Setup ancillary SPI devices for single device access */
+ for (i = 0; i < st->num_devices; i++) {
+ cs = spi_get_chipselect(st->spi, i);
+ st->spi_anc[i] = devm_spi_new_ancillary_device_with_lane(st->spi,
+ cs, i, 0);
+ if (IS_ERR(st->spi_anc[i]))
+ return dev_err_probe(dev, PTR_ERR(st->spi_anc[i]),
+ "failed to register ancillary device\n");
+
+ st->regmap24_anc[i] = devm_regmap_init_spi(st->spi_anc[i],
+ &ad7768_regmap24_config);
+ if (IS_ERR(st->regmap24_anc[i]))
+ return PTR_ERR(st->regmap24_anc[i]);
+ }
+
+ return 0;
+}
+
static bool ad7768_offload_trigger_match(struct spi_offload_trigger *trigger,
enum spi_offload_trigger_type type,
u64 *args, u32 nargs)
@@ -1833,6 +1900,12 @@ static int ad7768_probe(struct spi_device *spi)
return -ENODATA;

st->spi = spi;
+ /* Infer the number of devices from the number of CS */
+ st->num_devices = spi->num_chipselect;
+ if (st->num_devices > AD7768_MAX_AGGR_DEVICES)
+ return dev_err_probe(&spi->dev, -EINVAL,
+ "Too many devices (%u), max %d supported\n",
+ st->num_devices, AD7768_MAX_AGGR_DEVICES);

st->regmap = devm_regmap_init_spi(spi, &ad7768_regmap_config);
if (IS_ERR(st->regmap))
@@ -1856,11 +1929,18 @@ static int ad7768_probe(struct spi_device *spi)

st->mclk_freq = clk_get_rate(st->mclk);

- indio_dev->channels = st->chip->channel_spec;
- indio_dev->num_channels = st->chip->num_channels;
indio_dev->name = st->chip->name;
indio_dev->info = &ad7768_info;
indio_dev->modes = INDIO_DIRECT_MODE;
+ if (st->num_devices > 1) {
+ ret = ad7768_probe_multidevices(indio_dev);
+ if (ret)
+ return dev_err_probe(&spi->dev, ret,
+ "Failed to configure multidevice\n");
+ } else {
+ indio_dev->channels = st->chip->channel_spec;
+ indio_dev->num_channels = st->chip->num_channels;
+ }

/* Register VCM output regulator */
if (st->chip->has_vcm_regulator) {
@@ -1892,7 +1972,7 @@ static int ad7768_probe(struct spi_device *spi)
return ret;
}

- ret = ad7768_set_channel_label(indio_dev, st->chip->num_channels);
+ ret = ad7768_set_channel_label(indio_dev, st->num_devices);
if (ret)
return ret;

--
2.34.1