diff mbox series

[v2,09/10] iio: adc: ad7606: dynamically allocate channel info

Message ID 20250318-iio-adc-ad7606-improvements-v2-9-4b605427774c@baylibre.com (mailing list archive)
State Accepted
Headers show
Series iio: adc: ad7606: improvements and ad7606c parallel interface support | expand

Commit Message

David Lechner March 18, 2025, 10:52 p.m. UTC
Refactor the ad7606 drivers to dynamically allocate the channel info.

The channel info was getting a bit unwieldy. In some cases, the
indio_dev->channels field was getting assigned up to 3 different times,
each in a different function, making it difficult to see where the info
was coming from. This problem stems from the number of permutations of
the channel array needed to support various modes of operation and data
buses. We already have 4 per chip (hardware mode, software mode, AXI ADC
backend and AXI ADC backend with software mode) and we intend to add two
more per chip when adding SPI offload support.

To make it easier to read and maintain, move all of the channel setup
to a single function that dynamically allocates and fills in the channel
info.

Additionally, this lets us remove some hacks where we had to compute an
offset due to the fact that sometimes there was a soft timestamp channel
at the start of the array. Now the timestamp channel is always at the
end of the array as is typical in other drivers.

Reviewed-by: Nuno Sá <nuno.sa@analog.com>
Signed-off-by: David Lechner <dlechner@baylibre.com>
---
 drivers/iio/adc/ad7606.c     | 232 ++++++++++++++++++-------------------------
 drivers/iio/adc/ad7606.h     |  76 +-------------
 drivers/iio/adc/ad7606_par.c |  33 ------
 drivers/iio/adc/ad7606_spi.c |  86 +---------------
 4 files changed, 102 insertions(+), 325 deletions(-)

Comments

Dan Carpenter March 22, 2025, 5:25 p.m. UTC | #1
Hi David,

kernel test robot noticed the following build warnings:

url:    https://github.com/intel-lab-lkp/linux/commits/David-Lechner/iio-adc-ad7606-check-for-NULL-before-calling-sw_mode_config/20250319-065737
base:   9f36acefb2621d980734a5bb7d74e0e24e0af166
patch link:    https://lore.kernel.org/r/20250318-iio-adc-ad7606-improvements-v2-9-4b605427774c%40baylibre.com
patch subject: [PATCH v2 09/10] iio: adc: ad7606: dynamically allocate channel info
config: arm64-randconfig-r071-20250322 (https://download.01.org/0day-ci/archive/20250322/202503222246.RafigmhQ-lkp@intel.com/config)
compiler: clang version 21.0.0git (https://github.com/llvm/llvm-project c2692afc0a92cd5da140dfcdfff7818a5b8ce997)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
| Closes: https://lore.kernel.org/r/202503222246.RafigmhQ-lkp@intel.com/

smatch warnings:
drivers/iio/adc/ad7606.c:1270 ad7606_probe_channels() warn: potentially one past the end of array 'channels[i]'

vim +1270 drivers/iio/adc/ad7606.c

87cf5705725eeb David Lechner      2025-03-18  1196  static int ad7606_probe_channels(struct iio_dev *indio_dev)
e571c1902116a3 Alexandru Ardelean 2024-09-19  1197  {
e571c1902116a3 Alexandru Ardelean 2024-09-19  1198  	struct ad7606_state *st = iio_priv(indio_dev);
87cf5705725eeb David Lechner      2025-03-18  1199  	struct device *dev = indio_dev->dev.parent;
87cf5705725eeb David Lechner      2025-03-18  1200  	struct iio_chan_spec *channels;
87cf5705725eeb David Lechner      2025-03-18  1201  	bool slow_bus;
87cf5705725eeb David Lechner      2025-03-18  1202  	int ret, i;
87cf5705725eeb David Lechner      2025-03-18  1203  
87cf5705725eeb David Lechner      2025-03-18  1204  	slow_bus = !st->bops->iio_backend_config;
87cf5705725eeb David Lechner      2025-03-18  1205  	indio_dev->num_channels = st->chip_info->num_adc_channels;
87cf5705725eeb David Lechner      2025-03-18  1206  
87cf5705725eeb David Lechner      2025-03-18  1207  	/* Slow buses also get 1 more channel for soft timestamp */
87cf5705725eeb David Lechner      2025-03-18  1208  	if (slow_bus)
87cf5705725eeb David Lechner      2025-03-18  1209  		indio_dev->num_channels++;
87cf5705725eeb David Lechner      2025-03-18  1210  
87cf5705725eeb David Lechner      2025-03-18  1211  	channels = devm_kcalloc(dev, indio_dev->num_channels, sizeof(*channels),
87cf5705725eeb David Lechner      2025-03-18  1212  				GFP_KERNEL);
87cf5705725eeb David Lechner      2025-03-18  1213  	if (!channels)
f3838e934dfff2 Alexandru Ardelean 2024-09-19  1214  		return -ENOMEM;
f3838e934dfff2 Alexandru Ardelean 2024-09-19  1215  
87cf5705725eeb David Lechner      2025-03-18  1216  	for (i = 0; i < indio_dev->num_channels; i++) {
87cf5705725eeb David Lechner      2025-03-18  1217  		struct iio_chan_spec *chan = &channels[i];
87cf5705725eeb David Lechner      2025-03-18  1218  
87cf5705725eeb David Lechner      2025-03-18  1219  		chan->type = IIO_VOLTAGE;
87cf5705725eeb David Lechner      2025-03-18  1220  		chan->indexed = 1;
87cf5705725eeb David Lechner      2025-03-18  1221  		chan->channel = i;
87cf5705725eeb David Lechner      2025-03-18  1222  		chan->scan_index = i;
87cf5705725eeb David Lechner      2025-03-18  1223  		chan->scan_type.sign = 's';
87cf5705725eeb David Lechner      2025-03-18  1224  		chan->scan_type.realbits = st->chip_info->bits;
87cf5705725eeb David Lechner      2025-03-18  1225  		chan->scan_type.storagebits = st->chip_info->bits > 16 ? 32 : 16;
87cf5705725eeb David Lechner      2025-03-18  1226  		chan->scan_type.endianness = IIO_CPU;
f3838e934dfff2 Alexandru Ardelean 2024-09-19  1227  
87cf5705725eeb David Lechner      2025-03-18  1228  		if (indio_dev->modes & INDIO_DIRECT_MODE)
87cf5705725eeb David Lechner      2025-03-18  1229  			chan->info_mask_separate |= BIT(IIO_CHAN_INFO_RAW);
87cf5705725eeb David Lechner      2025-03-18  1230  
87cf5705725eeb David Lechner      2025-03-18  1231  		if (st->sw_mode_en) {
87cf5705725eeb David Lechner      2025-03-18  1232  			chan->info_mask_separate |= BIT(IIO_CHAN_INFO_SCALE);
87cf5705725eeb David Lechner      2025-03-18  1233  			chan->info_mask_separate_available |=
87cf5705725eeb David Lechner      2025-03-18  1234  				BIT(IIO_CHAN_INFO_SCALE);
87cf5705725eeb David Lechner      2025-03-18  1235  
87cf5705725eeb David Lechner      2025-03-18  1236  			/*
87cf5705725eeb David Lechner      2025-03-18  1237  			 * All chips with software mode support oversampling,
87cf5705725eeb David Lechner      2025-03-18  1238  			 * so we skip the oversampling_available check. And the
87cf5705725eeb David Lechner      2025-03-18  1239  			 * shared_by_type instead of shared_by_all on slow
87cf5705725eeb David Lechner      2025-03-18  1240  			 * buses is for backward compatibility.
87cf5705725eeb David Lechner      2025-03-18  1241  			 */
87cf5705725eeb David Lechner      2025-03-18  1242  			if (slow_bus)
87cf5705725eeb David Lechner      2025-03-18  1243  				chan->info_mask_shared_by_type |=
87cf5705725eeb David Lechner      2025-03-18  1244  					BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO);
87cf5705725eeb David Lechner      2025-03-18  1245  			else
87cf5705725eeb David Lechner      2025-03-18  1246  				chan->info_mask_shared_by_all |=
87cf5705725eeb David Lechner      2025-03-18  1247  					BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO);
87cf5705725eeb David Lechner      2025-03-18  1248  
87cf5705725eeb David Lechner      2025-03-18  1249  			chan->info_mask_shared_by_all_available |=
87cf5705725eeb David Lechner      2025-03-18  1250  				BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO);
87cf5705725eeb David Lechner      2025-03-18  1251  		} else {
87cf5705725eeb David Lechner      2025-03-18  1252  			chan->info_mask_shared_by_type |=
87cf5705725eeb David Lechner      2025-03-18  1253  				BIT(IIO_CHAN_INFO_SCALE);
87cf5705725eeb David Lechner      2025-03-18  1254  
87cf5705725eeb David Lechner      2025-03-18  1255  			if (st->chip_info->oversampling_avail)
87cf5705725eeb David Lechner      2025-03-18  1256  				chan->info_mask_shared_by_all |=
87cf5705725eeb David Lechner      2025-03-18  1257  					BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO);
87cf5705725eeb David Lechner      2025-03-18  1258  		}
87cf5705725eeb David Lechner      2025-03-18  1259  
87cf5705725eeb David Lechner      2025-03-18  1260  		if (!slow_bus)
87cf5705725eeb David Lechner      2025-03-18  1261  			chan->info_mask_shared_by_all |=
87cf5705725eeb David Lechner      2025-03-18  1262  				BIT(IIO_CHAN_INFO_SAMP_FREQ);
87cf5705725eeb David Lechner      2025-03-18  1263  
87cf5705725eeb David Lechner      2025-03-18  1264  		ret = st->chip_info->scale_setup_cb(indio_dev, chan);
e571c1902116a3 Alexandru Ardelean 2024-09-19  1265  		if (ret)
e571c1902116a3 Alexandru Ardelean 2024-09-19  1266  			return ret;
e571c1902116a3 Alexandru Ardelean 2024-09-19  1267  	}
e571c1902116a3 Alexandru Ardelean 2024-09-19  1268  
87cf5705725eeb David Lechner      2025-03-18  1269  	if (slow_bus)
87cf5705725eeb David Lechner      2025-03-18 @1270  		channels[i] = (struct iio_chan_spec)IIO_CHAN_SOFT_TIMESTAMP(i);
                                                                ^^^^^^^^^^^
i is == indio_dev->num_channels so this is out of bounds by one element.

87cf5705725eeb David Lechner      2025-03-18  1271  
87cf5705725eeb David Lechner      2025-03-18  1272  	indio_dev->channels = channels;
87cf5705725eeb David Lechner      2025-03-18  1273  
e571c1902116a3 Alexandru Ardelean 2024-09-19  1274  	return 0;
e571c1902116a3 Alexandru Ardelean 2024-09-19  1275  }
David Lechner March 24, 2025, 1:50 p.m. UTC | #2
On 3/22/25 12:25 PM, Dan Carpenter wrote:
> Hi David,
> 
> kernel test robot noticed the following build warnings:
> 
> url:    https://github.com/intel-lab-lkp/linux/commits/David-Lechner/iio-adc-ad7606-check-for-NULL-before-calling-sw_mode_config/20250319-065737
> base:   9f36acefb2621d980734a5bb7d74e0e24e0af166
> patch link:    https://lore.kernel.org/r/20250318-iio-adc-ad7606-improvements-v2-9-4b605427774c%40baylibre.com
> patch subject: [PATCH v2 09/10] iio: adc: ad7606: dynamically allocate channel info
> config: arm64-randconfig-r071-20250322 (https://download.01.org/0day-ci/archive/20250322/202503222246.RafigmhQ-lkp@intel.com/config)
> compiler: clang version 21.0.0git (https://github.com/llvm/llvm-project c2692afc0a92cd5da140dfcdfff7818a5b8ce997)
> 
> If you fix the issue in a separate patch/commit (i.e. not just a new version of
> the same patch/commit), kindly add following tags
> | Reported-by: kernel test robot <lkp@intel.com>
> | Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
> | Closes: https://lore.kernel.org/r/202503222246.RafigmhQ-lkp@intel.com/
> 
> smatch warnings:
> drivers/iio/adc/ad7606.c:1270 ad7606_probe_channels() warn: potentially one past the end of array 'channels[i]'
> 
> vim +1270 drivers/iio/adc/ad7606.c
> 
> 87cf5705725eeb David Lechner      2025-03-18  1196  static int ad7606_probe_channels(struct iio_dev *indio_dev)
> e571c1902116a3 Alexandru Ardelean 2024-09-19  1197  {
> e571c1902116a3 Alexandru Ardelean 2024-09-19  1198  	struct ad7606_state *st = iio_priv(indio_dev);
> 87cf5705725eeb David Lechner      2025-03-18  1199  	struct device *dev = indio_dev->dev.parent;
> 87cf5705725eeb David Lechner      2025-03-18  1200  	struct iio_chan_spec *channels;
> 87cf5705725eeb David Lechner      2025-03-18  1201  	bool slow_bus;
> 87cf5705725eeb David Lechner      2025-03-18  1202  	int ret, i;
> 87cf5705725eeb David Lechner      2025-03-18  1203  
> 87cf5705725eeb David Lechner      2025-03-18  1204  	slow_bus = !st->bops->iio_backend_config;
> 87cf5705725eeb David Lechner      2025-03-18  1205  	indio_dev->num_channels = st->chip_info->num_adc_channels;
> 87cf5705725eeb David Lechner      2025-03-18  1206  
> 87cf5705725eeb David Lechner      2025-03-18  1207  	/* Slow buses also get 1 more channel for soft timestamp */
> 87cf5705725eeb David Lechner      2025-03-18  1208  	if (slow_bus)
> 87cf5705725eeb David Lechner      2025-03-18  1209  		indio_dev->num_channels++;
> 87cf5705725eeb David Lechner      2025-03-18  1210  
> 87cf5705725eeb David Lechner      2025-03-18  1211  	channels = devm_kcalloc(dev, indio_dev->num_channels, sizeof(*channels),
> 87cf5705725eeb David Lechner      2025-03-18  1212  				GFP_KERNEL);
> 87cf5705725eeb David Lechner      2025-03-18  1213  	if (!channels)
> f3838e934dfff2 Alexandru Ardelean 2024-09-19  1214  		return -ENOMEM;
> f3838e934dfff2 Alexandru Ardelean 2024-09-19  1215  
> 87cf5705725eeb David Lechner      2025-03-18  1216  	for (i = 0; i < indio_dev->num_channels; i++) {

The fix is to change this line to:

							for (i = 0; i < st->chip_info->num_adc_channels; i++) {

> 87cf5705725eeb David Lechner      2025-03-18  1217  		struct iio_chan_spec *chan = &channels[i];
> 87cf5705725eeb David Lechner      2025-03-18  1218  
> 87cf5705725eeb David Lechner      2025-03-18  1219  		chan->type = IIO_VOLTAGE;
> 87cf5705725eeb David Lechner      2025-03-18  1220  		chan->indexed = 1;
> 87cf5705725eeb David Lechner      2025-03-18  1221  		chan->channel = i;
> 87cf5705725eeb David Lechner      2025-03-18  1222  		chan->scan_index = i;
> 87cf5705725eeb David Lechner      2025-03-18  1223  		chan->scan_type.sign = 's';
> 87cf5705725eeb David Lechner      2025-03-18  1224  		chan->scan_type.realbits = st->chip_info->bits;
> 87cf5705725eeb David Lechner      2025-03-18  1225  		chan->scan_type.storagebits = st->chip_info->bits > 16 ? 32 : 16;
> 87cf5705725eeb David Lechner      2025-03-18  1226  		chan->scan_type.endianness = IIO_CPU;
> f3838e934dfff2 Alexandru Ardelean 2024-09-19  1227  
> 87cf5705725eeb David Lechner      2025-03-18  1228  		if (indio_dev->modes & INDIO_DIRECT_MODE)
> 87cf5705725eeb David Lechner      2025-03-18  1229  			chan->info_mask_separate |= BIT(IIO_CHAN_INFO_RAW);
> 87cf5705725eeb David Lechner      2025-03-18  1230  
> 87cf5705725eeb David Lechner      2025-03-18  1231  		if (st->sw_mode_en) {
> 87cf5705725eeb David Lechner      2025-03-18  1232  			chan->info_mask_separate |= BIT(IIO_CHAN_INFO_SCALE);
> 87cf5705725eeb David Lechner      2025-03-18  1233  			chan->info_mask_separate_available |=
> 87cf5705725eeb David Lechner      2025-03-18  1234  				BIT(IIO_CHAN_INFO_SCALE);
> 87cf5705725eeb David Lechner      2025-03-18  1235  
> 87cf5705725eeb David Lechner      2025-03-18  1236  			/*
> 87cf5705725eeb David Lechner      2025-03-18  1237  			 * All chips with software mode support oversampling,
> 87cf5705725eeb David Lechner      2025-03-18  1238  			 * so we skip the oversampling_available check. And the
> 87cf5705725eeb David Lechner      2025-03-18  1239  			 * shared_by_type instead of shared_by_all on slow
> 87cf5705725eeb David Lechner      2025-03-18  1240  			 * buses is for backward compatibility.
> 87cf5705725eeb David Lechner      2025-03-18  1241  			 */
> 87cf5705725eeb David Lechner      2025-03-18  1242  			if (slow_bus)
> 87cf5705725eeb David Lechner      2025-03-18  1243  				chan->info_mask_shared_by_type |=
> 87cf5705725eeb David Lechner      2025-03-18  1244  					BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO);
> 87cf5705725eeb David Lechner      2025-03-18  1245  			else
> 87cf5705725eeb David Lechner      2025-03-18  1246  				chan->info_mask_shared_by_all |=
> 87cf5705725eeb David Lechner      2025-03-18  1247  					BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO);
> 87cf5705725eeb David Lechner      2025-03-18  1248  
> 87cf5705725eeb David Lechner      2025-03-18  1249  			chan->info_mask_shared_by_all_available |=
> 87cf5705725eeb David Lechner      2025-03-18  1250  				BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO);
> 87cf5705725eeb David Lechner      2025-03-18  1251  		} else {
> 87cf5705725eeb David Lechner      2025-03-18  1252  			chan->info_mask_shared_by_type |=
> 87cf5705725eeb David Lechner      2025-03-18  1253  				BIT(IIO_CHAN_INFO_SCALE);
> 87cf5705725eeb David Lechner      2025-03-18  1254  
> 87cf5705725eeb David Lechner      2025-03-18  1255  			if (st->chip_info->oversampling_avail)
> 87cf5705725eeb David Lechner      2025-03-18  1256  				chan->info_mask_shared_by_all |=
> 87cf5705725eeb David Lechner      2025-03-18  1257  					BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO);
> 87cf5705725eeb David Lechner      2025-03-18  1258  		}
> 87cf5705725eeb David Lechner      2025-03-18  1259  
> 87cf5705725eeb David Lechner      2025-03-18  1260  		if (!slow_bus)
> 87cf5705725eeb David Lechner      2025-03-18  1261  			chan->info_mask_shared_by_all |=
> 87cf5705725eeb David Lechner      2025-03-18  1262  				BIT(IIO_CHAN_INFO_SAMP_FREQ);
> 87cf5705725eeb David Lechner      2025-03-18  1263  
> 87cf5705725eeb David Lechner      2025-03-18  1264  		ret = st->chip_info->scale_setup_cb(indio_dev, chan);
> e571c1902116a3 Alexandru Ardelean 2024-09-19  1265  		if (ret)
> e571c1902116a3 Alexandru Ardelean 2024-09-19  1266  			return ret;
> e571c1902116a3 Alexandru Ardelean 2024-09-19  1267  	}
> e571c1902116a3 Alexandru Ardelean 2024-09-19  1268  
> 87cf5705725eeb David Lechner      2025-03-18  1269  	if (slow_bus)
> 87cf5705725eeb David Lechner      2025-03-18 @1270  		channels[i] = (struct iio_chan_spec)IIO_CHAN_SOFT_TIMESTAMP(i);
>                                                                 ^^^^^^^^^^^
> i is == indio_dev->num_channels so this is out of bounds by one element.
> 
> 87cf5705725eeb David Lechner      2025-03-18  1271  
> 87cf5705725eeb David Lechner      2025-03-18  1272  	indio_dev->channels = channels;
> 87cf5705725eeb David Lechner      2025-03-18  1273  
> e571c1902116a3 Alexandru Ardelean 2024-09-19  1274  	return 0;
> e571c1902116a3 Alexandru Ardelean 2024-09-19  1275  }
>
Jonathan Cameron March 30, 2025, 6:07 p.m. UTC | #3
On Mon, 24 Mar 2025 08:50:15 -0500
David Lechner <dlechner@baylibre.com> wrote:

> On 3/22/25 12:25 PM, Dan Carpenter wrote:
> > Hi David,
> > 
> > kernel test robot noticed the following build warnings:
> > 
> > url:    https://github.com/intel-lab-lkp/linux/commits/David-Lechner/iio-adc-ad7606-check-for-NULL-before-calling-sw_mode_config/20250319-065737
> > base:   9f36acefb2621d980734a5bb7d74e0e24e0af166
> > patch link:    https://lore.kernel.org/r/20250318-iio-adc-ad7606-improvements-v2-9-4b605427774c%40baylibre.com
> > patch subject: [PATCH v2 09/10] iio: adc: ad7606: dynamically allocate channel info
> > config: arm64-randconfig-r071-20250322 (https://download.01.org/0day-ci/archive/20250322/202503222246.RafigmhQ-lkp@intel.com/config)
> > compiler: clang version 21.0.0git (https://github.com/llvm/llvm-project c2692afc0a92cd5da140dfcdfff7818a5b8ce997)
> > 
> > If you fix the issue in a separate patch/commit (i.e. not just a new version of
> > the same patch/commit), kindly add following tags
> > | Reported-by: kernel test robot <lkp@intel.com>
> > | Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
> > | Closes: https://lore.kernel.org/r/202503222246.RafigmhQ-lkp@intel.com/
> > 
> > smatch warnings:
> > drivers/iio/adc/ad7606.c:1270 ad7606_probe_channels() warn: potentially one past the end of array 'channels[i]'
> > 
> > vim +1270 drivers/iio/adc/ad7606.c
> > 
> > 87cf5705725eeb David Lechner      2025-03-18  1196  static int ad7606_probe_channels(struct iio_dev *indio_dev)
> > e571c1902116a3 Alexandru Ardelean 2024-09-19  1197  {
> > e571c1902116a3 Alexandru Ardelean 2024-09-19  1198  	struct ad7606_state *st = iio_priv(indio_dev);
> > 87cf5705725eeb David Lechner      2025-03-18  1199  	struct device *dev = indio_dev->dev.parent;
> > 87cf5705725eeb David Lechner      2025-03-18  1200  	struct iio_chan_spec *channels;
> > 87cf5705725eeb David Lechner      2025-03-18  1201  	bool slow_bus;
> > 87cf5705725eeb David Lechner      2025-03-18  1202  	int ret, i;
> > 87cf5705725eeb David Lechner      2025-03-18  1203  
> > 87cf5705725eeb David Lechner      2025-03-18  1204  	slow_bus = !st->bops->iio_backend_config;
> > 87cf5705725eeb David Lechner      2025-03-18  1205  	indio_dev->num_channels = st->chip_info->num_adc_channels;
> > 87cf5705725eeb David Lechner      2025-03-18  1206  
> > 87cf5705725eeb David Lechner      2025-03-18  1207  	/* Slow buses also get 1 more channel for soft timestamp */
> > 87cf5705725eeb David Lechner      2025-03-18  1208  	if (slow_bus)
> > 87cf5705725eeb David Lechner      2025-03-18  1209  		indio_dev->num_channels++;
> > 87cf5705725eeb David Lechner      2025-03-18  1210  
> > 87cf5705725eeb David Lechner      2025-03-18  1211  	channels = devm_kcalloc(dev, indio_dev->num_channels, sizeof(*channels),
> > 87cf5705725eeb David Lechner      2025-03-18  1212  				GFP_KERNEL);
> > 87cf5705725eeb David Lechner      2025-03-18  1213  	if (!channels)
> > f3838e934dfff2 Alexandru Ardelean 2024-09-19  1214  		return -ENOMEM;
> > f3838e934dfff2 Alexandru Ardelean 2024-09-19  1215  
> > 87cf5705725eeb David Lechner      2025-03-18  1216  	for (i = 0; i < indio_dev->num_channels; i++) {  
> 
> The fix is to change this line to:
> 
> 							for (i = 0; i < st->chip_info->num_adc_channels; i++) {
> 
Tweaked and applied.

> > 87cf5705725eeb David Lechner      2025-03-18  1217  		struct iio_chan_spec *chan = &channels[i];
> > 87cf5705725eeb David Lechner      2025-03-18  1218  
> > 87cf5705725eeb David Lechner      2025-03-18  1219  		chan->type = IIO_VOLTAGE;
> > 87cf5705725eeb David Lechner      2025-03-18  1220  		chan->indexed = 1;
> > 87cf5705725eeb David Lechner      2025-03-18  1221  		chan->channel = i;
> > 87cf5705725eeb David Lechner      2025-03-18  1222  		chan->scan_index = i;
> > 87cf5705725eeb David Lechner      2025-03-18  1223  		chan->scan_type.sign = 's';
> > 87cf5705725eeb David Lechner      2025-03-18  1224  		chan->scan_type.realbits = st->chip_info->bits;
> > 87cf5705725eeb David Lechner      2025-03-18  1225  		chan->scan_type.storagebits = st->chip_info->bits > 16 ? 32 : 16;
> > 87cf5705725eeb David Lechner      2025-03-18  1226  		chan->scan_type.endianness = IIO_CPU;
> > f3838e934dfff2 Alexandru Ardelean 2024-09-19  1227  
> > 87cf5705725eeb David Lechner      2025-03-18  1228  		if (indio_dev->modes & INDIO_DIRECT_MODE)
> > 87cf5705725eeb David Lechner      2025-03-18  1229  			chan->info_mask_separate |= BIT(IIO_CHAN_INFO_RAW);
> > 87cf5705725eeb David Lechner      2025-03-18  1230  
> > 87cf5705725eeb David Lechner      2025-03-18  1231  		if (st->sw_mode_en) {
> > 87cf5705725eeb David Lechner      2025-03-18  1232  			chan->info_mask_separate |= BIT(IIO_CHAN_INFO_SCALE);
> > 87cf5705725eeb David Lechner      2025-03-18  1233  			chan->info_mask_separate_available |=
> > 87cf5705725eeb David Lechner      2025-03-18  1234  				BIT(IIO_CHAN_INFO_SCALE);
> > 87cf5705725eeb David Lechner      2025-03-18  1235  
> > 87cf5705725eeb David Lechner      2025-03-18  1236  			/*
> > 87cf5705725eeb David Lechner      2025-03-18  1237  			 * All chips with software mode support oversampling,
> > 87cf5705725eeb David Lechner      2025-03-18  1238  			 * so we skip the oversampling_available check. And the
> > 87cf5705725eeb David Lechner      2025-03-18  1239  			 * shared_by_type instead of shared_by_all on slow
> > 87cf5705725eeb David Lechner      2025-03-18  1240  			 * buses is for backward compatibility.
> > 87cf5705725eeb David Lechner      2025-03-18  1241  			 */
> > 87cf5705725eeb David Lechner      2025-03-18  1242  			if (slow_bus)
> > 87cf5705725eeb David Lechner      2025-03-18  1243  				chan->info_mask_shared_by_type |=
> > 87cf5705725eeb David Lechner      2025-03-18  1244  					BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO);
> > 87cf5705725eeb David Lechner      2025-03-18  1245  			else
> > 87cf5705725eeb David Lechner      2025-03-18  1246  				chan->info_mask_shared_by_all |=
> > 87cf5705725eeb David Lechner      2025-03-18  1247  					BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO);
> > 87cf5705725eeb David Lechner      2025-03-18  1248  
> > 87cf5705725eeb David Lechner      2025-03-18  1249  			chan->info_mask_shared_by_all_available |=
> > 87cf5705725eeb David Lechner      2025-03-18  1250  				BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO);
> > 87cf5705725eeb David Lechner      2025-03-18  1251  		} else {
> > 87cf5705725eeb David Lechner      2025-03-18  1252  			chan->info_mask_shared_by_type |=
> > 87cf5705725eeb David Lechner      2025-03-18  1253  				BIT(IIO_CHAN_INFO_SCALE);
> > 87cf5705725eeb David Lechner      2025-03-18  1254  
> > 87cf5705725eeb David Lechner      2025-03-18  1255  			if (st->chip_info->oversampling_avail)
> > 87cf5705725eeb David Lechner      2025-03-18  1256  				chan->info_mask_shared_by_all |=
> > 87cf5705725eeb David Lechner      2025-03-18  1257  					BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO);
> > 87cf5705725eeb David Lechner      2025-03-18  1258  		}
> > 87cf5705725eeb David Lechner      2025-03-18  1259  
> > 87cf5705725eeb David Lechner      2025-03-18  1260  		if (!slow_bus)
> > 87cf5705725eeb David Lechner      2025-03-18  1261  			chan->info_mask_shared_by_all |=
> > 87cf5705725eeb David Lechner      2025-03-18  1262  				BIT(IIO_CHAN_INFO_SAMP_FREQ);
> > 87cf5705725eeb David Lechner      2025-03-18  1263  
> > 87cf5705725eeb David Lechner      2025-03-18  1264  		ret = st->chip_info->scale_setup_cb(indio_dev, chan);
> > e571c1902116a3 Alexandru Ardelean 2024-09-19  1265  		if (ret)
> > e571c1902116a3 Alexandru Ardelean 2024-09-19  1266  			return ret;
> > e571c1902116a3 Alexandru Ardelean 2024-09-19  1267  	}
> > e571c1902116a3 Alexandru Ardelean 2024-09-19  1268  
> > 87cf5705725eeb David Lechner      2025-03-18  1269  	if (slow_bus)
> > 87cf5705725eeb David Lechner      2025-03-18 @1270  		channels[i] = (struct iio_chan_spec)IIO_CHAN_SOFT_TIMESTAMP(i);
> >                                                                 ^^^^^^^^^^^
> > i is == indio_dev->num_channels so this is out of bounds by one element.
> > 
> > 87cf5705725eeb David Lechner      2025-03-18  1271  
> > 87cf5705725eeb David Lechner      2025-03-18  1272  	indio_dev->channels = channels;
> > 87cf5705725eeb David Lechner      2025-03-18  1273  
> > e571c1902116a3 Alexandru Ardelean 2024-09-19  1274  	return 0;
> > e571c1902116a3 Alexandru Ardelean 2024-09-19  1275  }
> >   
>
diff mbox series

Patch

diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c
index 09c35161df365e531b8d254c7333359facf045c7..f3a78b01278527a3a380b80423d39774cee269c4 100644
--- a/drivers/iio/adc/ad7606.c
+++ b/drivers/iio/adc/ad7606.c
@@ -95,92 +95,6 @@  static const unsigned int ad7616_oversampling_avail[8] = {
 	1, 2, 4, 8, 16, 32, 64, 128,
 };
 
-static const struct iio_chan_spec ad7605_channels[] = {
-	IIO_CHAN_SOFT_TIMESTAMP(4),
-	AD7605_CHANNEL(0),
-	AD7605_CHANNEL(1),
-	AD7605_CHANNEL(2),
-	AD7605_CHANNEL(3),
-};
-
-static const struct iio_chan_spec ad7606_channels_16bit[] = {
-	IIO_CHAN_SOFT_TIMESTAMP(8),
-	AD7606_CHANNEL(0, 16),
-	AD7606_CHANNEL(1, 16),
-	AD7606_CHANNEL(2, 16),
-	AD7606_CHANNEL(3, 16),
-	AD7606_CHANNEL(4, 16),
-	AD7606_CHANNEL(5, 16),
-	AD7606_CHANNEL(6, 16),
-	AD7606_CHANNEL(7, 16),
-};
-
-static const struct iio_chan_spec ad7606_channels_18bit[] = {
-	IIO_CHAN_SOFT_TIMESTAMP(8),
-	AD7606_CHANNEL(0, 18),
-	AD7606_CHANNEL(1, 18),
-	AD7606_CHANNEL(2, 18),
-	AD7606_CHANNEL(3, 18),
-	AD7606_CHANNEL(4, 18),
-	AD7606_CHANNEL(5, 18),
-	AD7606_CHANNEL(6, 18),
-	AD7606_CHANNEL(7, 18),
-};
-
-static const struct iio_chan_spec ad7607_channels[] = {
-	IIO_CHAN_SOFT_TIMESTAMP(8),
-	AD7606_CHANNEL(0, 14),
-	AD7606_CHANNEL(1, 14),
-	AD7606_CHANNEL(2, 14),
-	AD7606_CHANNEL(3, 14),
-	AD7606_CHANNEL(4, 14),
-	AD7606_CHANNEL(5, 14),
-	AD7606_CHANNEL(6, 14),
-	AD7606_CHANNEL(7, 14),
-};
-
-static const struct iio_chan_spec ad7608_channels[] = {
-	IIO_CHAN_SOFT_TIMESTAMP(8),
-	AD7606_CHANNEL(0, 18),
-	AD7606_CHANNEL(1, 18),
-	AD7606_CHANNEL(2, 18),
-	AD7606_CHANNEL(3, 18),
-	AD7606_CHANNEL(4, 18),
-	AD7606_CHANNEL(5, 18),
-	AD7606_CHANNEL(6, 18),
-	AD7606_CHANNEL(7, 18),
-};
-
-/*
- * The current assumption that this driver makes for AD7616, is that it's
- * working in Hardware Mode with Serial, Burst and Sequencer modes activated.
- * To activate them, following pins must be pulled high:
- *	-SER/PAR
- *	-SEQEN
- * And following pins must be pulled low:
- *	-WR/BURST
- *	-DB4/SER1W
- */
-static const struct iio_chan_spec ad7616_channels[] = {
-	IIO_CHAN_SOFT_TIMESTAMP(16),
-	AD7606_CHANNEL(0, 16),
-	AD7606_CHANNEL(1, 16),
-	AD7606_CHANNEL(2, 16),
-	AD7606_CHANNEL(3, 16),
-	AD7606_CHANNEL(4, 16),
-	AD7606_CHANNEL(5, 16),
-	AD7606_CHANNEL(6, 16),
-	AD7606_CHANNEL(7, 16),
-	AD7606_CHANNEL(8, 16),
-	AD7606_CHANNEL(9, 16),
-	AD7606_CHANNEL(10, 16),
-	AD7606_CHANNEL(11, 16),
-	AD7606_CHANNEL(12, 16),
-	AD7606_CHANNEL(13, 16),
-	AD7606_CHANNEL(14, 16),
-	AD7606_CHANNEL(15, 16),
-};
-
 static int ad7606c_18bit_chan_scale_setup(struct iio_dev *indio_dev,
 					  struct iio_chan_spec *chan);
 static int ad7606c_16bit_chan_scale_setup(struct iio_dev *indio_dev,
@@ -198,20 +112,18 @@  static int ad7606b_sw_mode_setup(struct iio_dev *indio_dev);
 
 const struct ad7606_chip_info ad7605_4_info = {
 	.max_samplerate = 300 * KILO,
-	.channels = ad7605_channels,
 	.name = "ad7605-4",
+	.bits = 16,
 	.num_adc_channels = 4,
-	.num_channels = 5,
 	.scale_setup_cb = ad7606_16bit_chan_scale_setup,
 };
 EXPORT_SYMBOL_NS_GPL(ad7605_4_info, "IIO_AD7606");
 
 const struct ad7606_chip_info ad7606_8_info = {
 	.max_samplerate = 200 * KILO,
-	.channels = ad7606_channels_16bit,
 	.name = "ad7606-8",
+	.bits = 16,
 	.num_adc_channels = 8,
-	.num_channels = 9,
 	.oversampling_avail = ad7606_oversampling_avail,
 	.oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
 	.scale_setup_cb = ad7606_16bit_chan_scale_setup,
@@ -220,10 +132,9 @@  EXPORT_SYMBOL_NS_GPL(ad7606_8_info, "IIO_AD7606");
 
 const struct ad7606_chip_info ad7606_6_info = {
 	.max_samplerate = 200 * KILO,
-	.channels = ad7606_channels_16bit,
 	.name = "ad7606-6",
+	.bits = 16,
 	.num_adc_channels = 6,
-	.num_channels = 7,
 	.oversampling_avail = ad7606_oversampling_avail,
 	.oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
 	.scale_setup_cb = ad7606_16bit_chan_scale_setup,
@@ -232,10 +143,9 @@  EXPORT_SYMBOL_NS_GPL(ad7606_6_info, "IIO_AD7606");
 
 const struct ad7606_chip_info ad7606_4_info = {
 	.max_samplerate = 200 * KILO,
-	.channels = ad7606_channels_16bit,
 	.name = "ad7606-4",
+	.bits = 16,
 	.num_adc_channels = 4,
-	.num_channels = 5,
 	.oversampling_avail = ad7606_oversampling_avail,
 	.oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
 	.scale_setup_cb = ad7606_16bit_chan_scale_setup,
@@ -243,11 +153,10 @@  const struct ad7606_chip_info ad7606_4_info = {
 EXPORT_SYMBOL_NS_GPL(ad7606_4_info, "IIO_AD7606");
 
 const struct ad7606_chip_info ad7606b_info = {
-	.channels = ad7606_channels_16bit,
 	.max_samplerate = 800 * KILO,
 	.name = "ad7606b",
+	.bits = 16,
 	.num_adc_channels = 8,
-	.num_channels = 9,
 	.oversampling_avail = ad7606_oversampling_avail,
 	.oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
 	.scale_setup_cb = ad7606_16bit_chan_scale_setup,
@@ -257,10 +166,9 @@  EXPORT_SYMBOL_NS_GPL(ad7606b_info, "IIO_AD7606");
 
 const struct ad7606_chip_info ad7606c_16_info = {
 	.max_samplerate = 1 * MEGA,
-	.channels = ad7606_channels_16bit,
 	.name = "ad7606c16",
+	.bits = 16,
 	.num_adc_channels = 8,
-	.num_channels = 9,
 	.oversampling_avail = ad7606_oversampling_avail,
 	.oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
 	.scale_setup_cb = ad7606c_16bit_chan_scale_setup,
@@ -270,10 +178,9 @@  EXPORT_SYMBOL_NS_GPL(ad7606c_16_info, "IIO_AD7606");
 
 const struct ad7606_chip_info ad7607_info = {
 	.max_samplerate = 200 * KILO,
-	.channels = ad7607_channels,
 	.name = "ad7607",
+	.bits = 14,
 	.num_adc_channels = 8,
-	.num_channels = 9,
 	.oversampling_avail = ad7606_oversampling_avail,
 	.oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
 	.scale_setup_cb = ad7607_chan_scale_setup,
@@ -282,10 +189,9 @@  EXPORT_SYMBOL_NS_GPL(ad7607_info, "IIO_AD7606");
 
 const struct ad7606_chip_info ad7608_info = {
 	.max_samplerate = 200 * KILO,
-	.channels = ad7608_channels,
 	.name = "ad7608",
+	.bits = 18,
 	.num_adc_channels = 8,
-	.num_channels = 9,
 	.oversampling_avail = ad7606_oversampling_avail,
 	.oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
 	.scale_setup_cb = ad7608_chan_scale_setup,
@@ -294,10 +200,9 @@  EXPORT_SYMBOL_NS_GPL(ad7608_info, "IIO_AD7606");
 
 const struct ad7606_chip_info ad7609_info = {
 	.max_samplerate = 200 * KILO,
-	.channels = ad7608_channels,
 	.name = "ad7609",
+	.bits = 18,
 	.num_adc_channels = 8,
-	.num_channels = 9,
 	.oversampling_avail = ad7606_oversampling_avail,
 	.oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
 	.scale_setup_cb = ad7609_chan_scale_setup,
@@ -306,10 +211,9 @@  EXPORT_SYMBOL_NS_GPL(ad7609_info, "IIO_AD7606");
 
 const struct ad7606_chip_info ad7606c_18_info = {
 	.max_samplerate = 1 * MEGA,
-	.channels = ad7606_channels_18bit,
 	.name = "ad7606c18",
+	.bits = 18,
 	.num_adc_channels = 8,
-	.num_channels = 9,
 	.oversampling_avail = ad7606_oversampling_avail,
 	.oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
 	.scale_setup_cb = ad7606c_18bit_chan_scale_setup,
@@ -319,11 +223,10 @@  EXPORT_SYMBOL_NS_GPL(ad7606c_18_info, "IIO_AD7606");
 
 const struct ad7606_chip_info ad7616_info = {
 	.max_samplerate = 1 * MEGA,
-	.channels = ad7616_channels,
 	.init_delay_ms = 15,
 	.name = "ad7616",
+	.bits = 16,
 	.num_adc_channels = 16,
-	.num_channels = 17,
 	.oversampling_avail = ad7616_oversampling_avail,
 	.oversampling_num = ARRAY_SIZE(ad7616_oversampling_avail),
 	.os_req_reset = true,
@@ -373,7 +276,6 @@  static int ad7606_get_chan_config(struct iio_dev *indio_dev, int ch,
 {
 	struct ad7606_state *st = iio_priv(indio_dev);
 	unsigned int num_channels = st->chip_info->num_adc_channels;
-	unsigned int offset = indio_dev->num_channels - st->chip_info->num_adc_channels;
 	struct device *dev = st->dev;
 	int ret;
 
@@ -389,7 +291,7 @@  static int ad7606_get_chan_config(struct iio_dev *indio_dev, int ch,
 			continue;
 
 		/* channel number (here) is from 1 to num_channels */
-		if (reg < offset || reg > num_channels) {
+		if (reg < 1 || reg > num_channels) {
 			dev_warn(dev,
 				 "Invalid channel number (ignoring): %d\n", reg);
 			continue;
@@ -706,8 +608,8 @@  static int ad7606_scan_direct(struct iio_dev *indio_dev, unsigned int ch,
 			      int *val)
 {
 	struct ad7606_state *st = iio_priv(indio_dev);
-	unsigned int realbits = st->chip_info->channels[1].scan_type.realbits;
 	const struct iio_chan_spec *chan;
+	unsigned int realbits;
 	int ret;
 
 	if (st->gpio_convst) {
@@ -739,7 +641,9 @@  static int ad7606_scan_direct(struct iio_dev *indio_dev, unsigned int ch,
 	if (ret)
 		goto error_ret;
 
-	chan = &indio_dev->channels[ch + 1];
+	chan = &indio_dev->channels[ch];
+	realbits = chan->scan_type.realbits;
+
 	if (chan->scan_type.sign == 'u') {
 		if (realbits > 16)
 			*val = st->data.buf32[ch];
@@ -1289,29 +1193,84 @@  static int ad7606b_sw_mode_setup(struct iio_dev *indio_dev)
 	return st->bops->sw_mode_config(indio_dev);
 }
 
-static int ad7606_chan_scales_setup(struct iio_dev *indio_dev)
+static int ad7606_probe_channels(struct iio_dev *indio_dev)
 {
 	struct ad7606_state *st = iio_priv(indio_dev);
-	unsigned int offset = indio_dev->num_channels - st->chip_info->num_adc_channels;
-	struct iio_chan_spec *chans;
-	size_t size;
-	int ch, ret;
-
-	/* Clone IIO channels, since some may be differential */
-	size = indio_dev->num_channels * sizeof(*indio_dev->channels);
-	chans = devm_kzalloc(st->dev, size, GFP_KERNEL);
-	if (!chans)
+	struct device *dev = indio_dev->dev.parent;
+	struct iio_chan_spec *channels;
+	bool slow_bus;
+	int ret, i;
+
+	slow_bus = !st->bops->iio_backend_config;
+	indio_dev->num_channels = st->chip_info->num_adc_channels;
+
+	/* Slow buses also get 1 more channel for soft timestamp */
+	if (slow_bus)
+		indio_dev->num_channels++;
+
+	channels = devm_kcalloc(dev, indio_dev->num_channels, sizeof(*channels),
+				GFP_KERNEL);
+	if (!channels)
 		return -ENOMEM;
 
-	memcpy(chans, indio_dev->channels, size);
-	indio_dev->channels = chans;
+	for (i = 0; i < indio_dev->num_channels; i++) {
+		struct iio_chan_spec *chan = &channels[i];
 
-	for (ch = 0; ch < st->chip_info->num_adc_channels; ch++) {
-		ret = st->chip_info->scale_setup_cb(indio_dev, &chans[ch + offset]);
+		chan->type = IIO_VOLTAGE;
+		chan->indexed = 1;
+		chan->channel = i;
+		chan->scan_index = i;
+		chan->scan_type.sign = 's';
+		chan->scan_type.realbits = st->chip_info->bits;
+		chan->scan_type.storagebits = st->chip_info->bits > 16 ? 32 : 16;
+		chan->scan_type.endianness = IIO_CPU;
+
+		if (indio_dev->modes & INDIO_DIRECT_MODE)
+			chan->info_mask_separate |= BIT(IIO_CHAN_INFO_RAW);
+
+		if (st->sw_mode_en) {
+			chan->info_mask_separate |= BIT(IIO_CHAN_INFO_SCALE);
+			chan->info_mask_separate_available |=
+				BIT(IIO_CHAN_INFO_SCALE);
+
+			/*
+			 * All chips with software mode support oversampling,
+			 * so we skip the oversampling_available check. And the
+			 * shared_by_type instead of shared_by_all on slow
+			 * buses is for backward compatibility.
+			 */
+			if (slow_bus)
+				chan->info_mask_shared_by_type |=
+					BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO);
+			else
+				chan->info_mask_shared_by_all |=
+					BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO);
+
+			chan->info_mask_shared_by_all_available |=
+				BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO);
+		} else {
+			chan->info_mask_shared_by_type |=
+				BIT(IIO_CHAN_INFO_SCALE);
+
+			if (st->chip_info->oversampling_avail)
+				chan->info_mask_shared_by_all |=
+					BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO);
+		}
+
+		if (!slow_bus)
+			chan->info_mask_shared_by_all |=
+				BIT(IIO_CHAN_INFO_SAMP_FREQ);
+
+		ret = st->chip_info->scale_setup_cb(indio_dev, chan);
 		if (ret)
 			return ret;
 	}
 
+	if (slow_bus)
+		channels[i] = (struct iio_chan_spec)IIO_CHAN_SOFT_TIMESTAMP(i);
+
+	indio_dev->channels = channels;
+
 	return 0;
 }
 
@@ -1343,6 +1302,11 @@  int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
 	st->bops = bops;
 	st->base_address = base_address;
 	st->oversampling = 1;
+	st->sw_mode_en = device_property_read_bool(dev, "adi,sw-mode");
+
+	if (st->sw_mode_en && !chip_info->sw_setup_cb)
+		return dev_err_probe(dev, -EINVAL,
+			"Software mode is not supported for this chip\n");
 
 	ret = devm_regulator_get_enable(dev, "avcc");
 	if (ret)
@@ -1371,10 +1335,14 @@  int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
 		else
 			indio_dev->info = &ad7606_info_no_os_or_range;
 	}
-	indio_dev->modes = INDIO_DIRECT_MODE;
+
+	/* AXI ADC backend doesn't support single read. */
+	indio_dev->modes = st->bops->iio_backend_config ? 0 : INDIO_DIRECT_MODE;
 	indio_dev->name = chip_info->name;
-	indio_dev->channels = st->chip_info->channels;
-	indio_dev->num_channels = st->chip_info->num_channels;
+
+	ret = ad7606_probe_channels(indio_dev);
+	if (ret)
+		return ret;
 
 	ret = ad7606_reset(st);
 	if (ret)
@@ -1465,17 +1433,11 @@  int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
 	st->write_scale = ad7606_write_scale_hw;
 	st->write_os = ad7606_write_os_hw;
 
-	st->sw_mode_en = st->chip_info->sw_setup_cb &&
-			 device_property_present(st->dev, "adi,sw-mode");
 	if (st->sw_mode_en) {
 		indio_dev->info = &ad7606_info_sw_mode;
 		st->chip_info->sw_setup_cb(indio_dev);
 	}
 
-	ret = ad7606_chan_scales_setup(indio_dev);
-	if (ret)
-		return ret;
-
 	return devm_iio_device_register(dev, indio_dev);
 }
 EXPORT_SYMBOL_NS_GPL(ad7606_probe, "IIO_AD7606");
diff --git a/drivers/iio/adc/ad7606.h b/drivers/iio/adc/ad7606.h
index c57a193761c92add6f82cf0cc51ccfdb9d8d2ab4..f0b262fb4554f0bf244338c98ca585143321d616 100644
--- a/drivers/iio/adc/ad7606.h
+++ b/drivers/iio/adc/ad7606.h
@@ -40,76 +40,6 @@ 
 #define AD7606_RANGE_CH_ADDR(ch)	(0x03 + ((ch) >> 1))
 #define AD7606_OS_MODE			0x08
 
-#define AD760X_CHANNEL(num, mask_sep, mask_type, mask_all,	\
-		mask_sep_avail, mask_all_avail, bits) {		\
-		.type = IIO_VOLTAGE,				\
-		.indexed = 1,					\
-		.channel = num,					\
-		.info_mask_separate = mask_sep,			\
-		.info_mask_separate_available =			\
-			mask_sep_avail,				\
-		.info_mask_shared_by_type = mask_type,		\
-		.info_mask_shared_by_all = mask_all,		\
-		.info_mask_shared_by_all_available =		\
-			mask_all_avail,				\
-		.scan_index = num,				\
-		.scan_type = {					\
-			.sign = 's',				\
-			.realbits = (bits),			\
-			.storagebits = (bits) > 16 ? 32 : 16,	\
-			.endianness = IIO_CPU,			\
-		},						\
-}
-
-#define AD7606_SW_CHANNEL(num, bits)			\
-	AD760X_CHANNEL(num,				\
-		/* mask separate */			\
-		BIT(IIO_CHAN_INFO_RAW) |		\
-		BIT(IIO_CHAN_INFO_SCALE),		\
-		/* mask type */				\
-		BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),	\
-		/* mask all */				\
-		0,					\
-		/* mask separate available */		\
-		BIT(IIO_CHAN_INFO_SCALE),		\
-		/* mask all available */		\
-		BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),	\
-		bits)
-
-#define AD7605_CHANNEL(num)				\
-	AD760X_CHANNEL(num, BIT(IIO_CHAN_INFO_RAW),	\
-		BIT(IIO_CHAN_INFO_SCALE), 0, 0, 0, 16)
-
-#define AD7606_CHANNEL(num, bits)			\
-	AD760X_CHANNEL(num, BIT(IIO_CHAN_INFO_RAW),	\
-		BIT(IIO_CHAN_INFO_SCALE),		\
-		BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),	\
-		0, 0, bits)
-
-#define AD7616_CHANNEL(num)	AD7606_SW_CHANNEL(num, 16)
-
-#define AD7606_BI_CHANNEL(num)				\
-	AD760X_CHANNEL(num, 0,				\
-		BIT(IIO_CHAN_INFO_SCALE),		\
-		BIT(IIO_CHAN_INFO_SAMP_FREQ) |		\
-		BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),  \
-		0, 0, 16)
-
-#define AD7606_BI_SW_CHANNEL(num)			\
-	AD760X_CHANNEL(num,				\
-		/* mask separate */			\
-		BIT(IIO_CHAN_INFO_SCALE),		\
-		/* mask type */				\
-		0,					\
-		/* mask all */				\
-		BIT(IIO_CHAN_INFO_SAMP_FREQ) |		\
-		BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),	\
-		/* mask separate available */		\
-		BIT(IIO_CHAN_INFO_SCALE),		\
-		/* mask all available */		\
-		BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),	\
-		16)
-
 struct ad7606_state;
 
 typedef int (*ad7606_scale_setup_cb_t)(struct iio_dev *indio_dev,
@@ -118,11 +48,10 @@  typedef int (*ad7606_sw_setup_cb_t)(struct iio_dev *indio_dev);
 
 /**
  * struct ad7606_chip_info - chip specific information
- * @channels:		channel specification
  * @max_samplerate:	maximum supported sample rate
  * @name:		device name
+ * @bits:		data width in bits
  * @num_adc_channels:	the number of physical voltage inputs
- * @num_channels:	number of IIO channels
  * @scale_setup_cb:	callback to setup the scales for each channel
  * @sw_setup_cb:	callback to setup the software mode if available.
  * @oversampling_avail:	pointer to the array which stores the available
@@ -133,11 +62,10 @@  typedef int (*ad7606_sw_setup_cb_t)(struct iio_dev *indio_dev);
  *			after a restart
  */
 struct ad7606_chip_info {
-	const struct iio_chan_spec	*channels;
 	unsigned int			max_samplerate;
 	const char			*name;
+	unsigned int			bits;
 	unsigned int			num_adc_channels;
-	unsigned int			num_channels;
 	ad7606_scale_setup_cb_t		scale_setup_cb;
 	ad7606_sw_setup_cb_t		sw_setup_cb;
 	const unsigned int		*oversampling_avail;
diff --git a/drivers/iio/adc/ad7606_par.c b/drivers/iio/adc/ad7606_par.c
index 335fb481bfde15b79331eabdcbc970d70880338c..e33b07ab5eace4b78e7cf39ee7e8d9379c9f73e7 100644
--- a/drivers/iio/adc/ad7606_par.c
+++ b/drivers/iio/adc/ad7606_par.c
@@ -21,28 +21,6 @@ 
 #include "ad7606.h"
 #include "ad7606_bus_iface.h"
 
-static const struct iio_chan_spec ad7606b_bi_channels[] = {
-	AD7606_BI_CHANNEL(0),
-	AD7606_BI_CHANNEL(1),
-	AD7606_BI_CHANNEL(2),
-	AD7606_BI_CHANNEL(3),
-	AD7606_BI_CHANNEL(4),
-	AD7606_BI_CHANNEL(5),
-	AD7606_BI_CHANNEL(6),
-	AD7606_BI_CHANNEL(7),
-};
-
-static const struct iio_chan_spec ad7606b_bi_sw_channels[] = {
-	AD7606_BI_SW_CHANNEL(0),
-	AD7606_BI_SW_CHANNEL(1),
-	AD7606_BI_SW_CHANNEL(2),
-	AD7606_BI_SW_CHANNEL(3),
-	AD7606_BI_SW_CHANNEL(4),
-	AD7606_BI_SW_CHANNEL(5),
-	AD7606_BI_SW_CHANNEL(6),
-	AD7606_BI_SW_CHANNEL(7),
-};
-
 static int ad7606_par_bus_update_scan_mode(struct iio_dev *indio_dev,
 					   const unsigned long *scan_mask)
 {
@@ -94,9 +72,6 @@  static int ad7606_par_bus_setup_iio_backend(struct device *dev,
 			return ret;
 	}
 
-	indio_dev->channels = ad7606b_bi_channels;
-	indio_dev->num_channels = 8;
-
 	return 0;
 }
 
@@ -120,19 +95,11 @@  static int ad7606_par_bus_reg_write(struct ad7606_state *st, unsigned int addr,
 	return pdata->bus_reg_write(st->back, addr, val);
 }
 
-static int ad7606_par_bus_sw_mode_config(struct iio_dev *indio_dev)
-{
-	indio_dev->channels = ad7606b_bi_sw_channels;
-
-	return 0;
-}
-
 static const struct ad7606_bus_ops ad7606_bi_bops = {
 	.iio_backend_config = ad7606_par_bus_setup_iio_backend,
 	.update_scan_mode = ad7606_par_bus_update_scan_mode,
 	.reg_read = ad7606_par_bus_reg_read,
 	.reg_write = ad7606_par_bus_reg_write,
-	.sw_mode_config = ad7606_par_bus_sw_mode_config,
 };
 
 static int ad7606_par16_read_block(struct device *dev,
diff --git a/drivers/iio/adc/ad7606_spi.c b/drivers/iio/adc/ad7606_spi.c
index 1abaf8626206cb30e532cf9f82e0d050706aa1e0..b2b975fb7fea4d1af6caef59e75ca495501bc140 100644
--- a/drivers/iio/adc/ad7606_spi.c
+++ b/drivers/iio/adc/ad7606_spi.c
@@ -15,50 +15,6 @@ 
 
 #define MAX_SPI_FREQ_HZ		23500000	/* VDRIVE above 4.75 V */
 
-static const struct iio_chan_spec ad7616_sw_channels[] = {
-	IIO_CHAN_SOFT_TIMESTAMP(16),
-	AD7616_CHANNEL(0),
-	AD7616_CHANNEL(1),
-	AD7616_CHANNEL(2),
-	AD7616_CHANNEL(3),
-	AD7616_CHANNEL(4),
-	AD7616_CHANNEL(5),
-	AD7616_CHANNEL(6),
-	AD7616_CHANNEL(7),
-	AD7616_CHANNEL(8),
-	AD7616_CHANNEL(9),
-	AD7616_CHANNEL(10),
-	AD7616_CHANNEL(11),
-	AD7616_CHANNEL(12),
-	AD7616_CHANNEL(13),
-	AD7616_CHANNEL(14),
-	AD7616_CHANNEL(15),
-};
-
-static const struct iio_chan_spec ad7606b_sw_channels[] = {
-	IIO_CHAN_SOFT_TIMESTAMP(8),
-	AD7606_SW_CHANNEL(0, 16),
-	AD7606_SW_CHANNEL(1, 16),
-	AD7606_SW_CHANNEL(2, 16),
-	AD7606_SW_CHANNEL(3, 16),
-	AD7606_SW_CHANNEL(4, 16),
-	AD7606_SW_CHANNEL(5, 16),
-	AD7606_SW_CHANNEL(6, 16),
-	AD7606_SW_CHANNEL(7, 16),
-};
-
-static const struct iio_chan_spec ad7606c_18_sw_channels[] = {
-	IIO_CHAN_SOFT_TIMESTAMP(8),
-	AD7606_SW_CHANNEL(0, 18),
-	AD7606_SW_CHANNEL(1, 18),
-	AD7606_SW_CHANNEL(2, 18),
-	AD7606_SW_CHANNEL(3, 18),
-	AD7606_SW_CHANNEL(4, 18),
-	AD7606_SW_CHANNEL(5, 18),
-	AD7606_SW_CHANNEL(6, 18),
-	AD7606_SW_CHANNEL(7, 18),
-};
-
 static u16 ad7616_spi_rd_wr_cmd(int addr, char is_write_op)
 {
 	/*
@@ -160,48 +116,13 @@  static int ad7606_spi_reg_write(struct ad7606_state *st,
 	return spi_write(spi, &st->d16[0], sizeof(st->d16[0]));
 }
 
-static int ad7616_sw_mode_config(struct iio_dev *indio_dev)
-{
-	/*
-	 * Scale can be configured individually for each channel
-	 * in software mode.
-	 */
-	indio_dev->channels = ad7616_sw_channels;
-
-	return 0;
-}
-
 static int ad7606b_sw_mode_config(struct iio_dev *indio_dev)
 {
 	struct ad7606_state *st = iio_priv(indio_dev);
-	int ret;
 
 	/* Configure device spi to output on a single channel */
-	ret = st->bops->reg_write(st, AD7606_CONFIGURATION_REGISTER,
-				  AD7606_SINGLE_DOUT);
-	if (ret)
-		return ret;
-
-	/*
-	 * Scale can be configured individually for each channel
-	 * in software mode.
-	 */
-	indio_dev->channels = ad7606b_sw_channels;
-
-	return 0;
-}
-
-static int ad7606c_18_sw_mode_config(struct iio_dev *indio_dev)
-{
-	int ret;
-
-	ret = ad7606b_sw_mode_config(indio_dev);
-	if (ret)
-		return ret;
-
-	indio_dev->channels = ad7606c_18_sw_channels;
-
-	return 0;
+	return st->bops->reg_write(st, AD7606_CONFIGURATION_REGISTER,
+				   AD7606_SINGLE_DOUT);
 }
 
 static const struct ad7606_bus_ops ad7606_spi_bops = {
@@ -221,7 +142,6 @@  static const struct ad7606_bus_ops ad7616_spi_bops = {
 	.reg_read = ad7606_spi_reg_read,
 	.reg_write = ad7606_spi_reg_write,
 	.rd_wr_cmd = ad7616_spi_rd_wr_cmd,
-	.sw_mode_config = ad7616_sw_mode_config,
 };
 
 static const struct ad7606_bus_ops ad7606b_spi_bops = {
@@ -237,7 +157,7 @@  static const struct ad7606_bus_ops ad7606c_18_spi_bops = {
 	.reg_read = ad7606_spi_reg_read,
 	.reg_write = ad7606_spi_reg_write,
 	.rd_wr_cmd = ad7606b_spi_rd_wr_cmd,
-	.sw_mode_config = ad7606c_18_sw_mode_config,
+	.sw_mode_config = ad7606b_sw_mode_config,
 };
 
 static const struct ad7606_bus_info ad7605_4_bus_info = {