public inbox for devicetree@vger.kernel.org
 help / color / mirror / Atom feed
From: "Nuno Sá" <noname.nuno@gmail.com>
To: "Antoniu Miclaus" <antoniu.miclaus@analog.com>,
	"Lars-Peter Clausen" <lars@metafoo.de>,
	"Michael Hennerich" <Michael.Hennerich@analog.com>,
	"Jonathan Cameron" <jic23@kernel.org>,
	"David Lechner" <dlechner@baylibre.com>,
	"Nuno Sá" <nuno.sa@analog.com>,
	"Andy Shevchenko" <andy@kernel.org>,
	"Rob Herring" <robh@kernel.org>,
	"Krzysztof Kozlowski" <krzk+dt@kernel.org>,
	"Conor Dooley" <conor+dt@kernel.org>,
	"Olivier Moysan" <olivier.moysan@foss.st.com>,
	"Mark Brown" <broonie@kernel.org>,
	linux-iio@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-spi@vger.kernel.org
Subject: Re: [PATCH v3 5/5] iio: adc: ad4080: add support for AD4880 dual-channel ADC
Date: Fri, 13 Feb 2026 16:43:01 +0000	[thread overview]
Message-ID: <562d21574f46214cbb02433519e4e52b1520a916.camel@gmail.com> (raw)
In-Reply-To: <20260213144742.16394-6-antoniu.miclaus@analog.com>

On Fri, 2026-02-13 at 16:47 +0200, Antoniu Miclaus wrote:
> Add support for the AD4880, a dual-channel 20-bit 40MSPS SAR ADC with
> integrated fully differential amplifiers (FDA).
> 
> The AD4880 has two independent ADC channels, each with its own SPI
> configuration interface. The driver uses spi_new_ancillary_device() to
> create an additional SPI device for the second channel, allowing both
> channels to share the same SPI bus with different chip selects.
> 
> Reviewed-by: David Lechner <dlechner@baylibre.com>
> Signed-off-by: Antoniu Miclaus <antoniu.miclaus@analog.com>
> ---

Reviewed-by: Nuno Sá <nuno.sa@analog.com>

> Changes in v3:
>   - Use devm_spi_new_ancillary_device() instead of manual
>     spi_new_ancillary_device() + devm_add_action_or_reset()
>   - Remove ad4080_unregister_ancillary() cleanup function
>   - Generalize ancillary device setup with loop instead of
>     hardcoding channel 1
> 
>  drivers/iio/adc/ad4080.c | 248 +++++++++++++++++++++++++++++++--------
>  1 file changed, 197 insertions(+), 51 deletions(-)
> 
> diff --git a/drivers/iio/adc/ad4080.c b/drivers/iio/adc/ad4080.c
> index 7cf3b6ed7940..36a265ded80d 100644
> --- a/drivers/iio/adc/ad4080.c
> +++ b/drivers/iio/adc/ad4080.c
> @@ -16,6 +16,7 @@
>  #include <linux/mod_devicetable.h>
>  #include <linux/module.h>
>  #include <linux/mutex.h>
> +#include <linux/property.h>
>  #include <linux/regmap.h>
>  #include <linux/regulator/consumer.h>
>  #include <linux/spi/spi.h>
> @@ -131,6 +132,9 @@
>  #define AD4084_CHIP_ID						0x0054
>  #define AD4086_CHIP_ID						0x0056
>  #define AD4087_CHIP_ID						0x0057
> +#define AD4880_CHIP_ID						0x0750
> +
> +#define AD4080_MAX_CHANNELS					2
>  
>  #define AD4080_LVDS_CNV_CLK_CNT_MAX				7
>  
> @@ -176,8 +180,9 @@ struct ad4080_chip_info {
>  };
>  
>  struct ad4080_state {
> -	struct regmap			*regmap;
> -	struct iio_backend		*back;
> +	struct spi_device		*spi[AD4080_MAX_CHANNELS];
> +	struct regmap			*regmap[AD4080_MAX_CHANNELS];
> +	struct iio_backend		*back[AD4080_MAX_CHANNELS];
>  	const struct ad4080_chip_info	*info;
>  	/*
>  	 * Synchronize access to members the of driver state, and ensure
> @@ -203,10 +208,11 @@ static int ad4080_reg_access(struct iio_dev *indio_dev, unsigned int reg,
>  {
>  	struct ad4080_state *st = iio_priv(indio_dev);
>  
> +	/* Use channel 0 regmap for debugfs access */
>  	if (readval)
> -		return regmap_read(st->regmap, reg, readval);
> +		return regmap_read(st->regmap[0], reg, readval);
>  
> -	return regmap_write(st->regmap, reg, writeval);
> +	return regmap_write(st->regmap[0], reg, writeval);
>  }
>  
>  static int ad4080_get_scale(struct ad4080_state *st, int *val, int *val2)
> @@ -227,8 +233,9 @@ static unsigned int ad4080_get_dec_rate(struct iio_dev *dev,
>  	struct ad4080_state *st = iio_priv(dev);
>  	int ret;
>  	unsigned int data;
> +	unsigned int ch = chan->channel;
>  
> -	ret = regmap_read(st->regmap, AD4080_REG_FILTER_CONFIG, &data);
> +	ret = regmap_read(st->regmap[ch], AD4080_REG_FILTER_CONFIG, &data);
>  	if (ret)
>  		return ret;
>  
> @@ -240,13 +247,14 @@ static int ad4080_set_dec_rate(struct iio_dev *dev,
>  			       unsigned int mode)
>  {
>  	struct ad4080_state *st = iio_priv(dev);
> +	unsigned int ch = chan->channel;
>  
>  	guard(mutex)(&st->lock);
>  
>  	if ((st->filter_type >= SINC_5 && mode >= 512) || mode < 2)
>  		return -EINVAL;
>  
> -	return regmap_update_bits(st->regmap, AD4080_REG_FILTER_CONFIG,
> +	return regmap_update_bits(st->regmap[ch], AD4080_REG_FILTER_CONFIG,
>  				  AD4080_FILTER_CONFIG_SINC_DEC_RATE_MSK,
>  				  FIELD_PREP(AD4080_FILTER_CONFIG_SINC_DEC_RATE_MSK,
>  					     (ilog2(mode) - 1)));
> @@ -304,23 +312,23 @@ static int ad4080_write_raw(struct iio_dev *indio_dev,
>  	}
>  }
>  
> -static int ad4080_lvds_sync_write(struct ad4080_state *st)
> +static int ad4080_lvds_sync_write(struct ad4080_state *st, unsigned int ch)
>  {
> -	struct device *dev = regmap_get_device(st->regmap);
> +	struct device *dev = regmap_get_device(st->regmap[ch]);
>  	int ret;
>  
> -	ret = regmap_set_bits(st->regmap, AD4080_REG_ADC_DATA_INTF_CONFIG_A,
> +	ret = regmap_set_bits(st->regmap[ch], AD4080_REG_ADC_DATA_INTF_CONFIG_A,
>  			      AD4080_ADC_DATA_INTF_CONFIG_A_INTF_CHK_EN);
>  	if (ret)
>  		return ret;
>  
> -	ret = iio_backend_interface_data_align(st->back, 10000);
> +	ret = iio_backend_interface_data_align(st->back[ch], 10000);
>  	if (ret)
>  		return dev_err_probe(dev, ret,
>  				     "Data alignment process failed\n");
>  
>  	dev_dbg(dev, "Success: Pattern correct and Locked!\n");
> -	return regmap_clear_bits(st->regmap, AD4080_REG_ADC_DATA_INTF_CONFIG_A,
> +	return regmap_clear_bits(st->regmap[ch], AD4080_REG_ADC_DATA_INTF_CONFIG_A,
>  				 AD4080_ADC_DATA_INTF_CONFIG_A_INTF_CHK_EN);
>  }
>  
> @@ -329,9 +337,10 @@ static int ad4080_get_filter_type(struct iio_dev *dev,
>  {
>  	struct ad4080_state *st = iio_priv(dev);
>  	unsigned int data;
> +	unsigned int ch = chan->channel;
>  	int ret;
>  
> -	ret = regmap_read(st->regmap, AD4080_REG_FILTER_CONFIG, &data);
> +	ret = regmap_read(st->regmap[ch], AD4080_REG_FILTER_CONFIG, &data);
>  	if (ret)
>  		return ret;
>  
> @@ -343,6 +352,7 @@ static int ad4080_set_filter_type(struct iio_dev *dev,
>  				  unsigned int mode)
>  {
>  	struct ad4080_state *st = iio_priv(dev);
> +	unsigned int ch = chan->channel;
>  	int dec_rate;
>  	int ret;
>  
> @@ -355,11 +365,11 @@ static int ad4080_set_filter_type(struct iio_dev *dev,
>  	if (mode >= SINC_5 && dec_rate >= 512)
>  		return -EINVAL;
>  
> -	ret = iio_backend_filter_type_set(st->back, mode);
> +	ret = iio_backend_filter_type_set(st->back[ch], mode);
>  	if (ret)
>  		return ret;
>  
> -	ret = regmap_update_bits(st->regmap, AD4080_REG_FILTER_CONFIG,
> +	ret = regmap_update_bits(st->regmap[ch], AD4080_REG_FILTER_CONFIG,
>  				 AD4080_FILTER_CONFIG_FILTER_SEL_MSK,
>  				 FIELD_PREP(AD4080_FILTER_CONFIG_FILTER_SEL_MSK,
>  					    mode));
> @@ -399,6 +409,29 @@ static int ad4080_read_avail(struct iio_dev *indio_dev,
>  	}
>  }
>  
> +static int ad4880_update_scan_mode(struct iio_dev *indio_dev,
> +				   const unsigned long *scan_mask)
> +{
> +	struct ad4080_state *st = iio_priv(indio_dev);
> +	unsigned int ch;
> +	int ret;
> +
> +	for (ch = 0; ch < st->info->num_channels; ch++) {
> +		/*
> +		 * Each backend has a single channel (channel 0 from the
> +		 * backend's perspective), so always use channel index 0.
> +		 */
> +		if (test_bit(ch, scan_mask))
> +			ret = iio_backend_chan_enable(st->back[ch], 0);
> +		else
> +			ret = iio_backend_chan_disable(st->back[ch], 0);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
>  static const struct iio_info ad4080_iio_info = {
>  	.debugfs_reg_access = ad4080_reg_access,
>  	.read_raw = ad4080_read_raw,
> @@ -406,6 +439,19 @@ static const struct iio_info ad4080_iio_info = {
>  	.read_avail = ad4080_read_avail,
>  };
>  
> +/*
> + * AD4880 needs update_scan_mode to enable/disable individual backend channels.
> + * Single-channel devices don't need this as their backends may not implement
> + * chan_enable/chan_disable operations.
> + */
> +static const struct iio_info ad4880_iio_info = {
> +	.debugfs_reg_access = ad4080_reg_access,
> +	.read_raw = ad4080_read_raw,
> +	.write_raw = ad4080_write_raw,
> +	.read_avail = ad4080_read_avail,
> +	.update_scan_mode = ad4880_update_scan_mode,
> +};
> +
>  static const struct iio_enum ad4080_filter_type_enum = {
>  	.items = ad4080_filter_type_iio_enum,
>  	.num_items = ARRAY_SIZE(ad4080_filter_type_iio_enum),
> @@ -420,17 +466,51 @@ static struct iio_chan_spec_ext_info ad4080_ext_info[] = {
>  	{ }
>  };
>  
> -#define AD4080_CHANNEL_DEFINE(bits, storage) {				\
> +/*
> + * AD4880 needs per-channel filter configuration since each channel has
> + * its own independent ADC with separate SPI interface.
> + */
> +static struct iio_chan_spec_ext_info ad4880_ext_info[] = {
> +	IIO_ENUM("filter_type", IIO_SEPARATE, &ad4080_filter_type_enum),
> +	IIO_ENUM_AVAILABLE("filter_type", IIO_SEPARATE,
> +			   &ad4080_filter_type_enum),
> +	{ }
> +};
> +
> +#define AD4080_CHANNEL_DEFINE(bits, storage, idx) {			\
>  	.type = IIO_VOLTAGE,						\
>  	.indexed = 1,							\
> -	.channel = 0,							\
> +	.channel = (idx),						\
>  	.info_mask_separate = BIT(IIO_CHAN_INFO_SCALE),			\
>  	.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) |	\
>  			BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),		\
>  	.info_mask_shared_by_all_available =				\
>  			BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),		\
>  	.ext_info = ad4080_ext_info,					\
> -	.scan_index = 0,						\
> +	.scan_index = (idx),						\
> +	.scan_type = {							\
> +		.sign = 's',						\
> +		.realbits = (bits),					\
> +		.storagebits = (storage),				\
> +	},								\
> +}
> +
> +/*
> + * AD4880 has per-channel attributes (filter_type, oversampling_ratio,
> + * sampling_frequency) since each channel has its own independent ADC
> + * with separate SPI configuration interface.
> + */
> +#define AD4880_CHANNEL_DEFINE(bits, storage, idx) {		\
> +	.type = IIO_VOLTAGE,						\
> +	.indexed = 1,							\
> +	.channel = (idx),						\
> +	.info_mask_separate = BIT(IIO_CHAN_INFO_SCALE) |		\
> +			BIT(IIO_CHAN_INFO_SAMP_FREQ) |			\
> +			BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),		\
> +	.info_mask_separate_available =					\
> +			BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),		\
> +	.ext_info = ad4880_ext_info,				\
> +	.scan_index = (idx),						\
>  	.scan_type = {							\
>  		.sign = 's',						\
>  		.realbits = (bits),					\
> @@ -438,17 +518,22 @@ static struct iio_chan_spec_ext_info ad4080_ext_info[] = {
>  	},								\
>  }
>  
> -static const struct iio_chan_spec ad4080_channel = AD4080_CHANNEL_DEFINE(20, 32);
> +static const struct iio_chan_spec ad4080_channel = AD4080_CHANNEL_DEFINE(20, 32, 0);
>  
> -static const struct iio_chan_spec ad4081_channel = AD4080_CHANNEL_DEFINE(20, 32);
> +static const struct iio_chan_spec ad4081_channel = AD4080_CHANNEL_DEFINE(20, 32, 0);
>  
> -static const struct iio_chan_spec ad4083_channel = AD4080_CHANNEL_DEFINE(16, 16);
> +static const struct iio_chan_spec ad4083_channel = AD4080_CHANNEL_DEFINE(16, 16, 0);
>  
> -static const struct iio_chan_spec ad4084_channel = AD4080_CHANNEL_DEFINE(16, 16);
> +static const struct iio_chan_spec ad4084_channel = AD4080_CHANNEL_DEFINE(16, 16, 0);
>  
> -static const struct iio_chan_spec ad4086_channel = AD4080_CHANNEL_DEFINE(14, 16);
> +static const struct iio_chan_spec ad4086_channel = AD4080_CHANNEL_DEFINE(14, 16, 0);
>  
> -static const struct iio_chan_spec ad4087_channel = AD4080_CHANNEL_DEFINE(14, 16);
> +static const struct iio_chan_spec ad4087_channel = AD4080_CHANNEL_DEFINE(14, 16, 0);
> +
> +static const struct iio_chan_spec ad4880_channels[] = {
> +	AD4880_CHANNEL_DEFINE(20, 32, 0),
> +	AD4880_CHANNEL_DEFINE(20, 32, 1),
> +};
>  
>  static const struct ad4080_chip_info ad4080_chip_info = {
>  	.name = "ad4080",
> @@ -510,25 +595,34 @@ static const struct ad4080_chip_info ad4087_chip_info = {
>  	.lvds_cnv_clk_cnt_max = 1,
>  };
>  
> -static int ad4080_setup(struct iio_dev *indio_dev)
> +static const struct ad4080_chip_info ad4880_chip_info = {
> +	.name = "ad4880",
> +	.product_id = AD4880_CHIP_ID,
> +	.scale_table = ad4080_scale_table,
> +	.num_scales = ARRAY_SIZE(ad4080_scale_table),
> +	.num_channels = 2,
> +	.channels = ad4880_channels,
> +	.lvds_cnv_clk_cnt_max = AD4080_LVDS_CNV_CLK_CNT_MAX,
> +};
> +
> +static int ad4080_setup_channel(struct ad4080_state *st, unsigned int ch)
>  {
> -	struct ad4080_state *st = iio_priv(indio_dev);
> -	struct device *dev = regmap_get_device(st->regmap);
> +	struct device *dev = regmap_get_device(st->regmap[ch]);
>  	__le16 id_le;
>  	u16 id;
>  	int ret;
>  
> -	ret = regmap_write(st->regmap, AD4080_REG_INTERFACE_CONFIG_A,
> +	ret = regmap_write(st->regmap[ch], AD4080_REG_INTERFACE_CONFIG_A,
>  			   AD4080_INTERFACE_CONFIG_A_SW_RESET);
>  	if (ret)
>  		return ret;
>  
> -	ret = regmap_write(st->regmap, AD4080_REG_INTERFACE_CONFIG_A,
> +	ret = regmap_write(st->regmap[ch], AD4080_REG_INTERFACE_CONFIG_A,
>  			   AD4080_INTERFACE_CONFIG_A_SDO_ENABLE);
>  	if (ret)
>  		return ret;
>  
> -	ret = regmap_bulk_read(st->regmap, AD4080_REG_PRODUCT_ID_L, &id_le,
> +	ret = regmap_bulk_read(st->regmap[ch], AD4080_REG_PRODUCT_ID_L, &id_le,
>  			       sizeof(id_le));
>  	if (ret)
>  		return ret;
> @@ -537,18 +631,18 @@ static int ad4080_setup(struct iio_dev *indio_dev)
>  	if (id != st->info->product_id)
>  		dev_info(dev, "Unrecognized CHIP_ID 0x%X\n", id);
>  
> -	ret = regmap_set_bits(st->regmap, AD4080_REG_GPIO_CONFIG_A,
> +	ret = regmap_set_bits(st->regmap[ch], AD4080_REG_GPIO_CONFIG_A,
>  			      AD4080_GPIO_CONFIG_A_GPO_1_EN);
>  	if (ret)
>  		return ret;
>  
> -	ret = regmap_write(st->regmap, AD4080_REG_GPIO_CONFIG_B,
> +	ret = regmap_write(st->regmap[ch], AD4080_REG_GPIO_CONFIG_B,
>  			   FIELD_PREP(AD4080_GPIO_CONFIG_B_GPIO_1_SEL_MSK,
>  				      AD4080_GPIO_CONFIG_B_GPIO_FILTER_RES_RDY));
>  	if (ret)
>  		return ret;
>  
> -	ret = iio_backend_num_lanes_set(st->back, st->num_lanes);
> +	ret = iio_backend_num_lanes_set(st->back[ch], st->num_lanes);
>  	if (ret)
>  		return ret;
>  
> @@ -556,7 +650,7 @@ static int ad4080_setup(struct iio_dev *indio_dev)
>  		return 0;
>  
>  	/* Set maximum LVDS Data Transfer Latency */
> -	ret = regmap_update_bits(st->regmap,
> +	ret = regmap_update_bits(st->regmap[ch],
>  				 AD4080_REG_ADC_DATA_INTF_CONFIG_B,
>  				 AD4080_ADC_DATA_INTF_CONFIG_B_LVDS_CNV_CLK_CNT_MSK,
>  				 FIELD_PREP(AD4080_ADC_DATA_INTF_CONFIG_B_LVDS_CNV_CLK_CNT_MSK,
> @@ -565,24 +659,39 @@ static int ad4080_setup(struct iio_dev *indio_dev)
>  		return ret;
>  
>  	if (st->num_lanes > 1) {
> -		ret = regmap_set_bits(st->regmap, AD4080_REG_ADC_DATA_INTF_CONFIG_A,
> +		ret = regmap_set_bits(st->regmap[ch], AD4080_REG_ADC_DATA_INTF_CONFIG_A,
>  				      AD4080_ADC_DATA_INTF_CONFIG_A_SPI_LVDS_LANES);
>  		if (ret)
>  			return ret;
>  	}
>  
> -	ret = regmap_set_bits(st->regmap,
> +	ret = regmap_set_bits(st->regmap[ch],
>  			      AD4080_REG_ADC_DATA_INTF_CONFIG_B,
>  			      AD4080_ADC_DATA_INTF_CONFIG_B_LVDS_CNV_EN);
>  	if (ret)
>  		return ret;
>  
> -	return ad4080_lvds_sync_write(st);
> +	return ad4080_lvds_sync_write(st, ch);
> +}
> +
> +static int ad4080_setup(struct iio_dev *indio_dev)
> +{
> +	struct ad4080_state *st = iio_priv(indio_dev);
> +	unsigned int ch;
> +	int ret;
> +
> +	for (ch = 0; ch < st->info->num_channels; ch++) {
> +		ret = ad4080_setup_channel(st, ch);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
>  }
>  
>  static int ad4080_properties_parse(struct ad4080_state *st)
>  {
> -	struct device *dev = regmap_get_device(st->regmap);
> +	struct device *dev = regmap_get_device(st->regmap[0]);
>  
>  	st->lvds_cnv_en = device_property_read_bool(dev, "adi,lvds-cnv-enable");
>  
> @@ -602,6 +711,7 @@ static int ad4080_probe(struct spi_device *spi)
>  	struct device *dev = &spi->dev;
>  	struct ad4080_state *st;
>  	struct clk *clk;
> +	unsigned int ch;
>  	int ret;
>  
>  	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
> @@ -610,6 +720,10 @@ static int ad4080_probe(struct spi_device *spi)
>  
>  	st = iio_priv(indio_dev);
>  
> +	st->info = spi_get_device_match_data(spi);
> +	if (!st->info)
> +		return -ENODEV;
> +
>  	ret = devm_regulator_bulk_get_enable(dev,
>  					     ARRAY_SIZE(ad4080_power_supplies),
>  					     ad4080_power_supplies);
> @@ -617,13 +731,34 @@ static int ad4080_probe(struct spi_device *spi)
>  		return dev_err_probe(dev, ret,
>  				     "failed to get and enable supplies\n");
>  
> -	st->regmap = devm_regmap_init_spi(spi, &ad4080_regmap_config);
> -	if (IS_ERR(st->regmap))
> -		return PTR_ERR(st->regmap);
> +	/* Setup primary SPI device (channel 0) */
> +	st->spi[0] = spi;
> +	st->regmap[0] = devm_regmap_init_spi(spi, &ad4080_regmap_config);
> +	if (IS_ERR(st->regmap[0]))
> +		return PTR_ERR(st->regmap[0]);
>  
> -	st->info = spi_get_device_match_data(spi);
> -	if (!st->info)
> -		return -ENODEV;
> +	/* Setup ancillary SPI devices for additional channels */
> +	if (st->info->num_channels > 1) {
> +		u32 reg[AD4080_MAX_CHANNELS];
> +
> +		ret = device_property_read_u32_array(dev, "reg", reg,
> +						     st->info->num_channels);
> +		if (ret)
> +			return dev_err_probe(dev, ret,
> +					     "missing reg entries for multi-channel device\n");
> +
> +		for (int i = 1; i < st->info->num_channels; i++) {
> +			st->spi[i] = devm_spi_new_ancillary_device(spi, reg[i]);
> +			if (IS_ERR(st->spi[i]))
> +				return dev_err_probe(dev, PTR_ERR(st->spi[i]),
> +						     "failed to register ancillary device\n");
> +
> +			st->regmap[i] = devm_regmap_init_spi(st->spi[i],
> +							     &ad4080_regmap_config);
> +			if (IS_ERR(st->regmap[i]))
> +				return PTR_ERR(st->regmap[i]);
> +		}
> +	}
>  
>  	ret = devm_mutex_init(dev, &st->lock);
>  	if (ret)
> @@ -632,7 +767,8 @@ static int ad4080_probe(struct spi_device *spi)
>  	indio_dev->name = st->info->name;
>  	indio_dev->channels = st->info->channels;
>  	indio_dev->num_channels = st->info->num_channels;
> -	indio_dev->info = &ad4080_iio_info;
> +	indio_dev->info = st->info->num_channels > 1 ?
> +			  &ad4880_iio_info : &ad4080_iio_info;
>  
>  	ret = ad4080_properties_parse(st);
>  	if (ret)
> @@ -644,15 +780,23 @@ static int ad4080_probe(struct spi_device *spi)
>  
>  	st->clk_rate = clk_get_rate(clk);
>  
> -	st->back = devm_iio_backend_get(dev, NULL);
> -	if (IS_ERR(st->back))
> -		return PTR_ERR(st->back);
> +	/* Get backends for all channels */
> +	for (ch = 0; ch < st->info->num_channels; ch++) {
> +		st->back[ch] = devm_iio_backend_get_by_index(dev, ch);
> +		if (IS_ERR(st->back[ch]))
> +			return PTR_ERR(st->back[ch]);
>  
> -	ret = devm_iio_backend_request_buffer(dev, st->back, indio_dev);
> -	if (ret)
> -		return ret;
> +		ret = devm_iio_backend_enable(dev, st->back[ch]);
> +		if (ret)
> +			return ret;
> +	}
>  
> -	ret = devm_iio_backend_enable(dev, st->back);
> +	/*
> +	 * Request buffer from the first backend only. For multi-channel
> +	 * devices (e.g., AD4880), all backends share a single IIO buffer
> +	 * as data from all ADC channels is interleaved into one stream.
> +	 */
> +	ret = devm_iio_backend_request_buffer(dev, st->back[0], indio_dev);
>  	if (ret)
>  		return ret;
>  
> @@ -670,6 +814,7 @@ static const struct spi_device_id ad4080_id[] = {
>  	{ "ad4084", (kernel_ulong_t)&ad4084_chip_info },
>  	{ "ad4086", (kernel_ulong_t)&ad4086_chip_info },
>  	{ "ad4087", (kernel_ulong_t)&ad4087_chip_info },
> +	{ "ad4880", (kernel_ulong_t)&ad4880_chip_info },
>  	{ }
>  };
>  MODULE_DEVICE_TABLE(spi, ad4080_id);
> @@ -681,6 +826,7 @@ static const struct of_device_id ad4080_of_match[] = {
>  	{ .compatible = "adi,ad4084", &ad4084_chip_info },
>  	{ .compatible = "adi,ad4086", &ad4086_chip_info },
>  	{ .compatible = "adi,ad4087", &ad4087_chip_info },
> +	{ .compatible = "adi,ad4880", &ad4880_chip_info },
>  	{ }
>  };
>  MODULE_DEVICE_TABLE(of, ad4080_of_match);

  reply	other threads:[~2026-02-13 16:42 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-02-13 14:47 [PATCH v3 0/5] iio: adc: ad4080: add support for AD4880 dual-channel ADC Antoniu Miclaus
2026-02-13 14:47 ` [PATCH v3 1/5] spi: allow ancillary devices to share parent's chip selects Antoniu Miclaus
2026-02-13 16:39   ` Nuno Sá
2026-02-15 18:36   ` Jonathan Cameron
2026-02-13 14:47 ` [PATCH v3 2/5] spi: add devm_spi_new_ancillary_device() Antoniu Miclaus
2026-02-13 16:40   ` Nuno Sá
2026-02-13 14:47 ` [PATCH v3 3/5] iio: backend: add devm_iio_backend_get_by_index() Antoniu Miclaus
2026-02-13 16:33   ` Nuno Sá
2026-02-13 14:47 ` [PATCH v3 4/5] dt-bindings: iio: adc: ad4080: add AD4880 support Antoniu Miclaus
2026-02-13 16:34   ` Rob Herring (Arm)
2026-02-14  8:54   ` Krzysztof Kozlowski
2026-02-13 14:47 ` [PATCH v3 5/5] iio: adc: ad4080: add support for AD4880 dual-channel ADC Antoniu Miclaus
2026-02-13 16:43   ` Nuno Sá [this message]
2026-02-15 18:42   ` Jonathan Cameron
2026-02-15 18:34 ` [PATCH v3 0/5] " Jonathan Cameron

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=562d21574f46214cbb02433519e4e52b1520a916.camel@gmail.com \
    --to=noname.nuno@gmail.com \
    --cc=Michael.Hennerich@analog.com \
    --cc=andy@kernel.org \
    --cc=antoniu.miclaus@analog.com \
    --cc=broonie@kernel.org \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=dlechner@baylibre.com \
    --cc=jic23@kernel.org \
    --cc=krzk+dt@kernel.org \
    --cc=lars@metafoo.de \
    --cc=linux-iio@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-spi@vger.kernel.org \
    --cc=nuno.sa@analog.com \
    --cc=olivier.moysan@foss.st.com \
    --cc=robh@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox