Re: [RFC PATCH 3/4] iio: adc: Add support for AD4170

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, 18 Dec 2024 11:37:59 -0300
Marcelo Schmitt <marcelo.schmitt@xxxxxxxxxx> wrote:

> From: Ana-Maria Cusco <ana-maria.cusco@xxxxxxxxxx>
> 
> From: Ana-Maria Cusco <ana-maria.cusco@xxxxxxxxxx>
Two froms!
> 
> Add support for the AD4170 ADC with the following features:
> - Single-shot read (read_raw), scale, sampling freq
> - Multi channel buffer support
> - Buffered capture in triggered mode
> - Gain and offset calibration
> - chop_iexc and chop_adc device configuration
> - Powerdown switch configuration
> 
> Co-developed-by: Dragos Bogdan <dragos.bogdan@xxxxxxxxxx>
> Signed-off-by: Dragos Bogdan <dragos.bogdan@xxxxxxxxxx>
> Signed-off-by: Ana-Maria Cusco <ana-maria.cusco@xxxxxxxxxx>
> Co-developed-by: Marcelo Schmitt <marcelo.schmitt@xxxxxxxxxx>
> Signed-off-by: Marcelo Schmitt <marcelo.schmitt@xxxxxxxxxx>
> ---
>  drivers/iio/adc/Kconfig  |   16 +
>  drivers/iio/adc/Makefile |    1 +
>  drivers/iio/adc/ad4170.c | 2049 ++++++++++++++++++++++++++++++++++++++
>  drivers/iio/adc/ad4170.h |  316 ++++++

Don't have a separate header if only 1 c file. It just adds unnecessary boilerplate
and can lead to separations that make little sense.

It's a big driver and I think the changes requested to bindings will make
it bigger and  more complex still.  Hence not the most detailed of reviews
follows.

Jonathan

> diff --git a/drivers/iio/adc/ad4170.c b/drivers/iio/adc/ad4170.c
> new file mode 100644
> index 000000000000..20b74575f2cb
> --- /dev/null
> +++ b/drivers/iio/adc/ad4170.c
> @@ -0,0 +1,2049 @@

...

> +
> +static const char *const ad4170_clk_sel[] = {
> +	"ext-clk", "xtal"
> +};
> +
> +static const char *const ad4170_i_out_pin_dt_props[] = {
> +	"adi,excitation-pin-0",
> +	"adi,excitation-pin-1",
> +	"adi,excitation-pin-2",
> +	"adi,excitation-pin-3",
> +};
> +
> +static const char *const ad4170_i_out_val_dt_props[] = {

Push this down into the place it is used. Same for similar
examples of once use static const data.

> +	"adi,excitation-current-0-microamp",
> +	"adi,excitation-current-1-microamp",
> +	"adi,excitation-current-2-microamp",
> +	"adi,excitation-current-3-microamp",
> +};
> +
> +#define AD4170_SINC5_FS_PADDING		8
> +#define AD4170_SINC3_FS_OFFSET		2
> +
> +#define AD4170_SINC3_MIN_FS		4
> +#define AD4170_SINC3_MAX_FS		65532
> +#define AD4170_SINC5_MIN_FS		1
> +#define AD4170_SINC5_MAX_FS		256
> +
> +/* Make separate fs tables? One for SINC5 other for SINC5+AVG and SINC3? */

That sounds simpler than this.

> +static const unsigned int ad4170_filt_fs_tbl[] = {
> +	1, /* SINC5 minimum filter_fs */
> +	2,
> +	4, /* SINC5+AVG and SINC3 minimum filter_fs */
> +	8,
> +	12,
> +	16,
> +	20,
> +	40,
> +	48,
> +	80,
> +	100,
> +	256, /* SINC5 maximum filter_fs */
> +	500,
> +	1000,
> +	5000,
> +	8332,
> +	10000,
> +	25000,
> +	50000,
> +	65532 /* SINC5+AVG and SINC3 maximum filter_fs */
> +};

> +struct ad4170_state {
> +	struct regmap *regmap;
> +	struct spi_device *spi;
> +	struct regulator_bulk_data supplies[7];
> +	struct mutex lock; /* Protect filter, PGA, GPIO, chan read, chan config */
> +	struct iio_chan_spec chans[AD4170_MAX_CHANNELS];
> +	struct ad4170_chan_info chans_info[AD4170_MAX_CHANNELS];
> +	struct ad4170_setup setups[AD4170_MAX_SETUPS];
> +	u32 mclk_hz;
> +	enum ad4170_pin_function pins_fn[AD4170_NUM_ANALOG_PINS];
> +	enum ad4170_gpio_function gpio_fn[AD4170_NUM_GPIO_PINS];
> +	unsigned int clock_ctrl;
> +	struct clk *ext_clk;
> +	struct clk_hw int_clk_hw;
> +	int sps_tbl[ARRAY_SIZE(ad4170_filt_names)][ARRAY_SIZE(ad4170_filt_fs_tbl)][2];
> +	struct completion completion;
> +	struct iio_trigger *trig;
> +	u32 data[AD4170_MAX_CHANNELS];
> +
> +	struct spi_transfer xfer;
> +	struct spi_message msg;
> +	/*
> +	 * DMA (thus cache coherency maintenance) requires the transfer buffers
> +	 * to live in their own cache lines.
Comment doesn't match code.  write_tx_buf is not in the
cacheline you intend.

> +	 */
> +	u8 reg_write_tx_buf[6];
> +	__be32 reg_read_rx_buf __aligned(IIO_DMA_MINALIGN);
> +	__be16 reg_read_tx_buf;
> +};
> +

> +static const struct regmap_config ad4170_regmap_config = {
> +	.reg_bits = 14,
> +	.val_bits = 32,
> +	.reg_format_endian = REGMAP_ENDIAN_BIG,
> +	.val_format_endian = REGMAP_ENDIAN_BIG,
> +	.reg_read = ad4170_reg_read,
> +	.reg_write = ad4170_reg_write,
> +};
> +
> +static int ad4170_set_mode(struct ad4170_state *st, unsigned int mode)
> +{
> +	return regmap_update_bits(st->regmap, AD4170_ADC_CTRL_REG,
> +				  AD4170_REG_CTRL_MODE_MSK,
> +				  FIELD_PREP(AD4170_REG_CTRL_MODE_MSK, mode));
> +}
> +
> +/* 8 possible setups (0-7)*/
> +static int ad4170_write_setup(struct ad4170_state *st, unsigned int setup_num,
> +			      struct ad4170_setup *setup)
> +{
> +	int ret;
> +
> +	/*
> +	 * It is recommended to place the ADC in standby mode or idle mode to
> +	 * write to OFFSET and GAIN registers.
> +	 */
> +	ret = ad4170_set_mode(st, AD4170_ADC_CTRL_MODE_IDLE);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_write(st->regmap, AD4170_MISC_REG(setup_num), setup->misc);
> +	if (ret < 0)
regmap always returns 0 on success so you can just do if (ret)
> +		return ret;
> +
> +	ret = regmap_write(st->regmap, AD4170_AFE_REG(setup_num), setup->afe);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = regmap_write(st->regmap, AD4170_FILTER_REG(setup_num),
> +			   setup->filter);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = regmap_write(st->regmap, AD4170_FILTER_FS_REG(setup_num),
> +			   setup->filter_fs);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = regmap_write(st->regmap, AD4170_OFFSET_REG(setup_num),
> +			   setup->offset);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = regmap_write(st->regmap, AD4170_GAIN_REG(setup_num), setup->gain);
> +	if (ret < 0)
> +		return ret;
> +
> +	return 0;
Advantage of above is then return regmap_write() etc is obviously the same
as the earlier calls.

> +}

> +static int ad4170_set_filter_type(struct iio_dev *indio_dev,
> +				  const struct iio_chan_spec *chan,
> +				  unsigned int val)
> +{
> +	struct ad4170_state *st = iio_priv(indio_dev);
> +	struct ad4170_chan_info *chan_info = &st->chans_info[chan->address];
> +	struct ad4170_setup *setup = &st->setups[chan_info->setup_num];
> +	unsigned int old_filter_fs, old_filter, filter_type_conf;
> +	int ret = 0;
> +
> +	switch (val) {
> +	case AD4170_SINC5_AVG:
> +		filter_type_conf = AD4170_SINC5_AVG_CONF;
> +		break;
> +	case AD4170_SINC5:
> +		filter_type_conf = AD4170_SINC5_CONF;
> +		break;
> +	case AD4170_SINC3:
> +		filter_type_conf = AD4170_SINC3_CONF;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	/*
> +	 * The filters provide the same ODR for a given filter_fs value but
> +	 * there are different minimum and maximum filter_fs limits for each
> +	 * filter. The filter_fs value will be adjusted if the current filter_fs
> +	 * is out of the limits of the just requested filter. Since the
> +	 * filter_fs value affects the ODR (sampling_frequency), changing the
> +	 * filter may lead to a change in the sampling frequency.
> +	 */
> +	iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {

As below on this magic going away. Though in this case not worth a helper function as no early returns.

> +		old_filter = setup->filter;
> +		old_filter_fs = setup->filter_fs;
> +		if (val == AD4170_SINC5_AVG || val == AD4170_SINC3) {
> +			if (setup->filter_fs < AD4170_SINC3_MIN_FS)
> +				setup->filter_fs = AD4170_SINC3_MIN_FS;
> +			if (setup->filter_fs > AD4170_SINC3_MAX_FS)
> +				setup->filter_fs = AD4170_SINC3_MAX_FS;
> +
> +		} else if (val == AD4170_SINC5) {
> +			if (setup->filter_fs < AD4170_SINC5_MIN_FS)
> +				setup->filter_fs = AD4170_SINC5_MIN_FS;
> +			if (setup->filter_fs > AD4170_SINC5_MAX_FS)
> +				setup->filter_fs = AD4170_SINC5_MAX_FS;
> +		}
> +
> +		setup->filter &= ~AD4170_SETUPS_FILTER_TYPE_MSK;
> +		setup->filter |= FIELD_PREP(AD4170_SETUPS_FILTER_TYPE_MSK,
> +					    filter_type_conf);
> +
> +		guard(mutex)(&st->lock);
> +		ret = ad4170_write_setup(st, chan_info->setup_num, setup);
> +		if (ret) {
> +			setup->filter = old_filter;
> +			setup->filter_fs = old_filter_fs;
> +		}
> +		return ret;
> +	}
> +	unreachable();
> +}
>
> +
> +static int ad4170_read_sample(struct iio_dev *indio_dev, unsigned int channel,
> +			      int *val)
> +{
> +	struct ad4170_state *st = iio_priv(indio_dev);
> +	struct ad4170_chan_info *chan_info = &st->chans_info[channel];
> +	struct ad4170_setup *setup = &st->setups[chan_info->setup_num];
> +	int precision_bits = ad4170_channel_template.scan_type.realbits;
> +	int ret;
> +
> +	guard(mutex)(&st->lock);
> +	ret = ad4170_set_channel_enable(st, channel, true);
> +	if (ret)
> +		return ret;
> +
> +	reinit_completion(&st->completion);
> +
> +	ret = ad4170_set_mode(st, AD4170_ADC_CTRL_MODE_SINGLE);
> +	if (ret)
> +		return ret;
> +
> +	ret = wait_for_completion_timeout(&st->completion, HZ);
> +	if (!ret)
> +		goto out;

Odd to let this go, but for other cases not re enable the channel.
Add a comment on why you are doing this.

> +
> +	ret = regmap_read(st->regmap, AD4170_DATA_24b_REG, val);
> +	if (ret)
> +		return ret;
> +
> +	if (FIELD_GET(AD4170_AFE_BIPOLAR_MSK, setup->afe))
> +		*val = sign_extend32(*val, precision_bits - 1);
> +out:
> +	ret = ad4170_set_channel_enable(st, channel, false);
> +	if (ret)
> +		return ret;
> +
> +	return IIO_VAL_INT;
> +}

...

> +/*
> + * Receives the device state, the channel spec, a reference selection, and
> + * returns the magnitude of the allowed input range in µV.
> + * Verifies whether the channel configuration is valid by checking the provided
> + * input type, polarity, and voltage references result in a sane input range.
> + * Returns negative error code on failure.
> + */
> +static int ad4170_get_input_range(struct ad4170_state *st,
> +				  struct iio_chan_spec const *chan,
> +				  unsigned int ref_sel)
> +{
> +	struct ad4170_chan_info *chan_info = &st->chans_info[chan->address];
> +	struct ad4170_setup *setup = &st->setups[chan_info->setup_num];
> +	bool bipolar = FIELD_GET(AD4170_AFE_BIPOLAR_MSK, setup->afe);
> +	int refp, refn, ain_voltage, ret;
> +
> +	switch (ref_sel) {
> +	case AD4170_AFE_REFIN_REFIN1:
> +		refp = regulator_get_voltage(st->supplies[AD4170_REFIN1P_SUP].consumer);
> +		refn = regulator_get_voltage(st->supplies[AD4170_REFIN1N_SUP].consumer);
> +		break;
> +	case AD4170_AFE_REFIN_REFIN2:
> +		refp = regulator_get_voltage(st->supplies[AD4170_REFIN2P_SUP].consumer);
> +		refn = regulator_get_voltage(st->supplies[AD4170_REFIN2N_SUP].consumer);
> +		break;
> +	case AD4170_AFE_REFIN_AVDD:
> +		refp = regulator_get_voltage(st->supplies[AD4170_AVDD_SUP].consumer);
> +		ret = regulator_get_voltage(st->supplies[AD4170_AVSS_SUP].consumer);
> +		/*
> +		 * TODO AVSS is actually optional.
> +		 * Should we handle -EPROBE_DEFER here?

Not here.  That should have been handled when originally getting the regulator.

> +		 */
> +		if (ret < 0)
> +			ret = 0; /* Assume AVSS at GND if not provided */
> +
> +		refn = ret;
> +		break;
> +	case AD4170_AFE_REFIN_REFOUT:
> +		refn = regulator_get_voltage(st->supplies[AD4170_AVSS_SUP].consumer);
> +		if (refn < 0)
> +			refn = 0;
> +
> +		/* REFOUT is 2.5 V relative to AVSS */
> +		/* avss-supply is never above 0V. */
> +		refp = AD4170_INT_REF_2_5V - refn;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +	if (refp < 0)
> +		return refp;
> +
> +	if (refn < 0)
> +		return refn;
> +
> +	/*
> +	 * Find out the analog input range from the channel type, polarity, and
> +	 * voltage reference selection.
> +	 * AD4170 channels are either differential or pseudo-differential.
> +	 */
> +	/* Differential Input Voltage Range: −VREF/gain to +VREF/gain (datasheet page 6) */
> +	/* Single-Ended Input Voltage Range: 0 to VREF/gain (datasheet page 6) */

Checkpatch is going to moan.  Just make a larger multiline comment without appropriate
formatting to have same affect as here.

> +	if (chan->differential) {
> +		if (!bipolar)
> +			return dev_err_probe(&st->spi->dev, -EINVAL,
> +					     "Invalid channel %lu setup.\n",
> +					     chan->address);
> +
> +		/* Differential bipolar channel */
> +		/* avss-supply is never above 0V. */
> +		/* Assuming refin1n-supply not above 0V. */
> +		/* Assuming refin2n-supply not above 0V. */

More to combine into a block comment with some extra formatting.

> +		return refp + refn;
> +	}
> +	/*
> +	 * Some configurations can lead to invalid setups.
> +	 * For example, if AVSS = -2.5V, REF_SELECT set to REFOUT (REFOUT/AVSS),
> +	 * and single-ended channel configuration set, then the input range
> +	 * should go from 0V to +VREF (single-ended - datasheet pg 10), but
> +	 * REFOUT/AVSS range would be -2.5V to 0V.
> +	 * Check the positive reference is higher than 0V for pseudo-diff
> +	 * channels.
> +	 */
> +	if (bipolar) {
> +		/* Pseudo-differential bipolar channel */
> +		/* Input allowed to swing from GND to +VREF */
> +		if (refp <= 0)
> +			return dev_err_probe(&st->spi->dev, -EINVAL,
> +					     "Invalid setup for channel %lu.\n",
> +					     chan->address);
> +
> +		return refp;
> +	}
> +
> +	/* Pseudo-differential unipolar channel */
> +	/* Input allowed to swing from IN- to +VREF */
> +	if (refp <= 0)
> +		return dev_err_probe(&st->spi->dev, -EINVAL,
> +				     "Invalid setup for channel %lu.\n",
> +				     chan->address);
> +
> +	ret = ad4170_get_AINM_voltage(st, chan->channel2, &ain_voltage);
> +	if (ret < 0)
> +		return ret;
> +
> +	if (refp - ain_voltage <= 0)
> +		return dev_err_probe(&st->spi->dev, -EINVAL,
> +				     "Invalid setup for channel %lu.\n",
> +				     chan->address);
> +
> +	return refp - ain_voltage;
> +}
> +
> +static int ad4170_read_raw(struct iio_dev *indio_dev,
> +			   struct iio_chan_spec const *chan,
> +			   int *val, int *val2, long info)
> +{
> +	struct ad4170_state *st = iio_priv(indio_dev);
> +	struct ad4170_chan_info *chan_info = &st->chans_info[chan->address];
> +	struct ad4170_setup *setup = &st->setups[chan_info->setup_num];
> +	enum ad4170_filter_type f_type;
> +	unsigned int pga, fs_idx;
> +
> +	switch (info) {
> +	case IIO_CHAN_INFO_RAW:
> +		iio_device_claim_direct_scoped(return -EBUSY, indio_dev)

Sorry to say that I think this is going away.  Please open code the claim
and release.  If I finish reviewing the backlog I'll start work on ripping
this out. The unreachable() here is one of the reasons it is a pain
and not worth it



> +			return ad4170_read_sample(indio_dev, chan->address, val);
> +		unreachable();
> +	case IIO_CHAN_INFO_SCALE:
> +		pga = FIELD_GET(AD4170_AFE_PGA_GAIN_MSK, setup->afe);
> +		*val = chan_info->scale_tbl[pga][0];
> +		*val2 = chan_info->scale_tbl[pga][1];
> +		return IIO_VAL_INT_PLUS_NANO;
> +	case IIO_CHAN_INFO_OFFSET:
> +		pga = FIELD_GET(AD4170_AFE_PGA_GAIN_MSK, setup->afe);
> +		*val = chan_info->offset_tbl[pga];
> +		return IIO_VAL_INT;
> +	case IIO_CHAN_INFO_SAMP_FREQ:
> +		f_type = ad4170_filter_to_filter_type(setup->filter);
> +		fs_idx = find_closest(setup->filter_fs, ad4170_filt_fs_tbl,
> +				      ARRAY_SIZE(ad4170_filt_fs_tbl));
> +		*val = st->sps_tbl[f_type][fs_idx][0];
> +		*val2 = st->sps_tbl[f_type][fs_idx][1];
> +		return IIO_VAL_INT_PLUS_MICRO;
> +	case IIO_CHAN_INFO_CALIBBIAS:
> +		*val = setup->offset;
> +		return IIO_VAL_INT;
> +	case IIO_CHAN_INFO_CALIBSCALE:
> +		*val = setup->gain;
> +		return IIO_VAL_INT;
> +	default:
> +		return -EINVAL;
> +	}
> +}



> +
> +static int ad4170_write_raw(struct iio_dev *indio_dev,
> +			    struct iio_chan_spec const *chan,
> +			    int val, int val2, long info)
> +{
> +	struct ad4170_state *st = iio_priv(indio_dev);
> +
> +	iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {

It's a pain but this is almost certainly going away. Easiest solution
is use the opencoded claim and release but then factor out the bit in this scope
as a __ad4170_write_raw() so that you can still do direct returns etc.

> +		switch (info) {
> +		case IIO_CHAN_INFO_SCALE:
> +			return ad4170_set_pga(indio_dev, st, chan->address, val,
> +					      val2);
> +		case IIO_CHAN_INFO_SAMP_FREQ:
> +			return ad4170_set_channel_freq(st, chan->address, val,
> +						       val2);
> +		case IIO_CHAN_INFO_CALIBBIAS:
> +			return ad4170_set_calib_offset(indio_dev, chan->address,
> +						       val);
> +		case IIO_CHAN_INFO_CALIBSCALE:
> +			return ad4170_set_calib_gain(indio_dev, chan->address,
> +						     val);
> +		default:
> +			return -EINVAL;
> +		}
> +	}
> +	unreachable();
> +}
> +
> +static int ad4170_update_scan_mode(struct iio_dev *indio_dev,
> +				   const unsigned long *active_scan_mask)
> +{
> +	struct ad4170_state *st = iio_priv(indio_dev);
> +	unsigned int channel;
> +	int ret;
> +
> +	guard(mutex)(&st->lock);
> +
> +	for_each_set_bit(channel, active_scan_mask, indio_dev->num_channels) {

Can't do this any more... Try building on latest kernel.  You will need
to use an accessor function to get num_channels.

> +		ret = ad4170_set_channel_enable(st, channel, true);
> +		if (ret)
> +			return ret;
> +	}
> +	return 0;
> +}


c int ad4170_parse_channels(struct iio_dev *indio_dev)
> +{
> +	struct ad4170_state *st = iio_priv(indio_dev);
> +	struct device *dev = &st->spi->dev;
> +	int chan_num, i, ret;
> +
> +	chan_num = 0;
> +	device_for_each_child_node_scoped(dev, child) {
> +		ret = ad4170_parse_channel_node(indio_dev, child, chan_num);
> +		if (ret)
> +			return ret;
> +
> +		chan_num++;
> +	}
> +	for (i = 0; i < AD4170_MAX_CHANNELS; i++)
> +		if (st->chans[i].scan_index == 0)
> +			break;
> +
> +	/*
> +	 * When more than one channel is enabled, channel 0 must always be used.
Maybe say why?

> +	 */
> +	if (chan_num > 1 && i == AD4170_MAX_CHANNELS)
> +		return dev_err_probe(dev, -EINVAL,
> +				     "Channel 0 must be configured\n");
> +
> +	indio_dev->channels = st->chans;
> +	indio_dev->num_channels = chan_num;
> +	return 0;
> +}

> +
> +static int ad4170_clk_output_is_enabled(struct clk_hw *hw)
> +{
> +	struct ad4170_state *st = clk_hw_to_ad4170(hw);
> +	u32 clk_sel;
> +
> +	clk_sel = FIELD_GET(AD4170_CLOCK_CTRL_CLOCKSEL_MSK, st->clock_ctrl);
> +	return clk_sel == AD4170_INTERNAL_OSC_OUTPUT;

That is a bool not an int.

> +}

> +static int ad4170_parse_pw_switch(struct ad4170_state *st, struct device *dev)
> +{
> +	bool pdsw0, pdsw1;
> +
> +	pdsw0 = device_property_read_bool(dev, "adi,gpio0-power-down-switch");
> +	pdsw1 = device_property_read_bool(dev, "adi,gpio1-power-down-switch");
> +
> +	/*
> +	 * Error if a GPIO is assigned to be both excitation current output and
> +	 * power switch.
> +	 */
> +	if (pdsw0) {
> +		if (st->gpio_fn[0] != AD4170_GPIO_UNASIGNED)
> +			return dev_err_probe(&st->spi->dev, -EINVAL,

Can't you use the dev that was passed in?

> +					     "GPIO 0 already used with fn %u\n",
> +					     st->gpio_fn[0]);
> +
> +		st->gpio_fn[0] = AD4170_GPIO_PW_DOW_SWITCH;
> +	}
> +	if (pdsw1) {
> +		if (st->gpio_fn[1] != AD4170_GPIO_UNASIGNED)
> +			return dev_err_probe(&st->spi->dev, -EINVAL,
> +					     "GPIO 1 already used with fn %u\n",
> +					     st->gpio_fn[1]);
> +
> +		st->gpio_fn[1] = AD4170_GPIO_PW_DOW_SWITCH;
> +	}
> +	return regmap_update_bits(st->regmap, AD4170_POWER_DOWN_SW_REG,
> +				 AD4170_POWER_DOWN_SW_PDSW0_MSK |
> +				 AD4170_POWER_DOWN_SW_PDSW1_MSK,
> +				 pdsw0 | pdsw1);
> +}
> +
> +static int ad4170_parse_vbias(struct ad4170_state *st, struct device *dev)
> +{
> +	u32 vbias_pins[AD4170_MAX_ANALOG_PINS];
> +	unsigned int i, val;
> +	u32 num_vbias_pins;
> +	int ret;
> +
> +	ret = device_property_count_u32(dev, "adi,vbias-pins");
> +	if (ret > 0) {
> +		if (ret > AD4170_MAX_ANALOG_PINS)
> +			return dev_err_probe(dev, -EINVAL,
> +					     "Too many vbias pins %u\n", ret);

Look at what dev_err_probe() does... You never want to print ret explicitly
as it does the job better than this.

> +
> +		num_vbias_pins = ret;
> +		ret = device_property_read_u32_array(dev, "adi,vbias-pins",
> +						     vbias_pins,
> +						     num_vbias_pins);
> +		if (ret)
> +			return dev_err_probe(dev, ret,
> +					     "Failed to read vbias pins\n");
> +	}
> +	for (i = 0; i < num_vbias_pins; i++) {
> +		if (st->pins_fn[vbias_pins[i]] != AD4170_PIN_UNASIGNED)
> +			return dev_err_probe(&st->spi->dev, -EINVAL,

dev?

> +					     "AIN%d already used with fn %u\n",
> +					     vbias_pins[i], st->pins_fn[i]);
> +
> +		val |= BIT(vbias_pins[i]);
> +		st->pins_fn[vbias_pins[i]] = AD4170_PIN_VBIAS;
> +	}
> +	return regmap_write(st->regmap, AD4170_V_BIAS_REG, val);
> +}
> +
> +static int ad4170_parse_firmware(struct iio_dev *indio_dev)
> +{
> +	struct ad4170_state *st = iio_priv(indio_dev);
> +	struct device *dev = &st->spi->dev;
> +	int ret, i;
> +	u8 aux;
> +
> +	ret = ad4170_clock_select(indio_dev);
> +	if (ret < 0)
> +		return dev_err_probe(dev, ret, "Failed to setup device clock\n");
> +
> +	ret = regmap_write(st->regmap, AD4170_CLOCK_CTRL_REG, st->clock_ctrl);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = ad4170_parse_pin_muxing(indio_dev);
> +	if (ret < 0)
> +		return ret;
> +
> +	for (i = 0; i < AD4170_NUM_ANALOG_PINS; i++)
> +		st->pins_fn[i] = AD4170_PIN_UNASIGNED;
> +
> +	for (i = 0; i < AD4170_NUM_GPIO_PINS; i++)
> +		st->gpio_fn[i] = AD4170_GPIO_UNASIGNED;
> +
> +	ret = ad4170_parse_exc_current(indio_dev);
> +	if (ret)
> +		return ret;
> +// write to misc reg must be delaied because misc register contains settings
> +// that are channel specific.

looks like left over debug comment. Make sure to address these before posting.

> +
> +	ret = ad4170_parse_pw_switch(st, dev);
> +	if (ret < 0)
> +		return dev_err_probe(dev, ret,
> +				     "Failed to config power down switches\n");
> +
> +	ret = ad4170_parse_vbias(st, dev);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = ad4170_parse_channels(indio_dev);
> +	if (ret)
> +		return ret;
> +
> +	aux = AD4170_MISC_CHOP_IEXC_OFF;
> +	ret = device_property_read_u8(dev, "adi,chop-iexc", &aux);
> +	if (!ret) {
> +		ret = ad4170_find_table_index(ad4170_iexc_chop_tbl, aux);
> +		if (ret < 0)
> +			return dev_err_probe(dev, ret,
> +					     "Invalid adi,chop-iexc config: %u\n",
> +					      aux);
> +	}
> +
> +	/* Set excitation current chop config to first channel setup config */
> +	st->setups[indio_dev->channels[0].address].misc |=
> +		FIELD_PREP(AD4170_MISC_CHOP_IEXC_MSK, aux);
> +	return 0;
> +}
> +
> +static int ad4170_initial_config(struct iio_dev *indio_dev)
> +{
> +	struct ad4170_state *st = iio_priv(indio_dev);
> +	struct ad4170_chan_info *chan_info;
> +	struct iio_chan_spec const *chan;
> +	struct ad4170_setup *setup;
> +	unsigned int val;
> +	unsigned int i;
> +	int ret;
> +
> +	ad4170_fill_sps_tbl(st);
> +
> +	/* Put ADC in IDLE mode */
Code is pretty self explanatory.  So drop the comment as something that might bitrot.

> +	ret = ad4170_set_mode(st, AD4170_ADC_CTRL_MODE_IDLE);
> +	if (ret)
> +		return ret;
> +
> +	/* Setup channels. */

Similar with this one.

> +	for (i = 0; i < indio_dev->num_channels; i++) {

Can reduce the scope of some of the local variables by pulling them in here.

> +		chan = &indio_dev->channels[i];
> +		chan_info = &st->chans_info[chan->address];
> +		setup = &st->setups[chan_info->setup_num];

To match with the other drivers that support hardware where channels have
to share some config, you will need to do the setup stuff alongside a config
entry allocator that checks for matches. It's fiddly but there are examples
in tree.  Some of the other ADI folk should be able to point you at a good
example to follow

> +
> +		ret = regmap_update_bits(st->regmap,
> +					 AD4170_CHAN_SETUP_REG(chan->address),
> +					 AD4170_CHANNEL_SETUP_SETUP_MSK,
> +					 FIELD_PREP(AD4170_CHANNEL_SETUP_SETUP_MSK,
> +						    chan_info->setup_num));
> +		if (ret)
> +			return ret;
> +
> +		setup->gain = AD4170_GAIN_REG_DEFAULT;
> +		ret = ad4170_write_setup(st, chan_info->setup_num, setup);
> +		if (ret)
> +			return ret;
> +
> +		val = FIELD_PREP(AD4170_CHANNEL_MAPN_AINP_MSK, chan->channel) |
> +		      FIELD_PREP(AD4170_CHANNEL_MAPN_AINM_MSK, chan->channel2);
> +
> +		ret = regmap_write(st->regmap, AD4170_CHAN_MAP_REG(i), val);
> +		if (ret < 0)
> +			return ret;
> +
> +		ret = ad4170_set_channel_freq(st, chan->address,
> +					      AD4170_MAX_SAMP_RATE, 0);
> +		if (ret)
> +			return ret;
> +
> +		ret = ad4170_fill_scale_tbl(indio_dev, i);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = regmap_write(st->regmap, AD4170_CHANNEL_EN_REG, 0);
> +	if (ret < 0)
> +		return ret;
> +
> +	/*
> +	 * Configure channels to share the same data output register, i.e. data
> +	 * can be read from the same register address regardless of channel
> +	 * number.
> +	 */
> +	ret = regmap_update_bits(st->regmap, AD4170_ADC_CTRL_REG,
> +				 AD4170_ADC_CTRL_MULTI_DATA_REG_SEL_MSK,
> +				 AD4170_ADC_CTRL_MULTI_DATA_REG_SEL_MSK);
> +	if (ret)
> +		return ret;
> +
> +	return 0;

	return regmap_update_bits...

> +}

> +static void ad4170_prepare_message(struct ad4170_state *st)
> +{
> +	/*
> +	 * Continuous data register read is enabled on buffer postenable so
> +	 * no instruction phase is needed meaning we don't need to send the
> +	 * register address to read data. Transfer only needs the read buffer.
> +	 */
> +	st->xfer.rx_buf = &st->reg_read_rx_buf;
> +	st->xfer.bits_per_word = ad4170_channel_template.scan_type.storagebits;
> +	st->xfer.len = BITS_TO_BYTES(ad4170_channel_template.scan_type.storagebits);
> +
> +	spi_message_init_with_transfers(&st->msg, &st->xfer, 1);
> +}
> +
> +static int ad4170_buffer_postenable(struct iio_dev *indio_dev)
> +{
> +	struct ad4170_state *st = iio_priv(indio_dev);
> +	int ret;
> +
> +	ret = ad4170_set_mode(st, AD4170_ADC_CTRL_MODE_CONT);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = regmap_update_bits(st->regmap, AD4170_ADC_CTRL_REG,
> +				 AD4170_REG_CTRL_CONT_READ_MSK,
> +				 FIELD_PREP(AD4170_REG_CTRL_CONT_READ_MSK,
> +					    AD4170_ADC_CTRL_CONT_READ_ENABLE));
> +
> +	if (ret < 0)
> +		return ret;
> +
> +	return spi_optimize_message(st->spi, &st->msg);

This is a little odd. You have an optimized message, but also use regmap
and never seem to use st->msg.

Half done conversion?

> +}
> +
> +static int ad4170_buffer_predisable(struct iio_dev *indio_dev)
> +{
> +	struct ad4170_state *st = iio_priv(indio_dev);
> +	int ret, i;
> +
> +	spi_unoptimize_message(&st->msg);
> +
> +	for (i = 0; i < indio_dev->num_channels; i++) {
> +		ret = ad4170_set_channel_enable(st, i, false);

I guess harmless to disable channels that were never enabled. Maybe
add a comment on that.

> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = regmap_update_bits(st->regmap, AD4170_ADC_CTRL_REG,
> +				 AD4170_REG_CTRL_CONT_READ_MSK,
> +				 FIELD_PREP(AD4170_REG_CTRL_CONT_READ_MSK,
> +					    AD4170_ADC_CTRL_CONT_READ_DISABLE));
> +	if (ret < 0)
> +		return ret;
> +
> +	return ad4170_set_mode(st, AD4170_ADC_CTRL_MODE_IDLE);
> +}
> +
> +static const struct iio_buffer_setup_ops ad4170_buffer_ops = {
> +	.postenable = ad4170_buffer_postenable,
> +	.predisable = ad4170_buffer_predisable,
> +};
> +
> +static irqreturn_t ad4170_trigger_handler(int irq, void *p)
> +{
> +	struct iio_poll_func *pf = p;
> +	struct iio_dev *indio_dev = pf->indio_dev;
> +	struct ad4170_state *st = iio_priv(indio_dev);
> +	int ret, i = 0;
> +	int scan_index;
> +
> +	for_each_set_bit(scan_index, indio_dev->active_scan_mask,
> +			 indio_dev->masklength) {

Try building on current kernel...  then fix it up ;)  There is a new
iterator for this.


> +		/* Read register data */
> +		ret = regmap_read(st->regmap, AD4170_DATA_24b_REG, &st->data[i]);
> +		if (ret)
> +			goto out;
> +		i++;
> +	}
> +
> +	iio_push_to_buffers_with_timestamp(indio_dev, &st->data,
> +					   iio_get_time_ns(indio_dev));

Used the pollfunc that gets a timestamp but grabbed a new one here which makes no sense.
Figure out when it makes more sense to get that timestamp and only use that.

> +out:
> +	iio_trigger_notify_done(indio_dev->trig);
> +	return IRQ_HANDLED;
> +}
> +
> +static int ad4170_triggered_buffer_setup(struct iio_dev *indio_dev)
> +{
> +	struct ad4170_state *st = iio_priv(indio_dev);
> +	int ret;
> +
> +	indio_dev->modes |= INDIO_BUFFER_TRIGGERED;

That's set appropriately by devm_iio_trigger_buffer_setup() so no need
I think to set it here.

> +
> +	st->trig = devm_iio_trigger_alloc(indio_dev->dev.parent, "%s-trig%d",
> +					  indio_dev->name,
> +					  iio_device_id(indio_dev));
> +	if (!st->trig)
> +		return -ENOMEM;
> +
> +	st->trig->ops = &ad4170_trigger_ops;
> +	st->trig->dev.parent = indio_dev->dev.parent;
> +
> +	iio_trigger_set_drvdata(st->trig, indio_dev);
> +	ret = devm_iio_trigger_register(indio_dev->dev.parent, st->trig);
> +	if (ret)
> +		return ret;
> +
> +	indio_dev->trig = iio_trigger_get(st->trig);
> +
> +	ret = request_irq(st->spi->irq,
> +			  &ad4170_interrupt,
> +			  IRQF_TRIGGER_FALLING | IRQF_ONESHOT,

Interrupt direction is a thing for firmware to control, not the driver so don't set it here.

> +			  indio_dev->name, indio_dev);
> +	if (ret)
> +		return ret;
> +
> +	return devm_iio_triggered_buffer_setup(indio_dev->dev.parent, indio_dev,
> +					       &iio_pollfunc_store_time,
> +					       &ad4170_trigger_handler,
> +					       &ad4170_buffer_ops);
> +}
> +
> +static int ad4170_probe(struct spi_device *spi)
> +{
> +	struct device *dev = &spi->dev;
> +	struct iio_dev *indio_dev;
> +	struct ad4170_state *st;
> +	int ret;
> +
> +	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
> +	if (!indio_dev)
> +		return -ENOMEM;
> +
> +	st = iio_priv(indio_dev);
> +	devm_mutex_init(dev, &st->lock);
> +
> +	indio_dev->name = AD4170_NAME;
> +	indio_dev->modes = INDIO_DIRECT_MODE;
> +	indio_dev->info = &ad4170_info;
> +
> +	st->spi = spi;
> +	st->regmap = devm_regmap_init(dev, NULL, st, &ad4170_regmap_config);
> +
> +	st->supplies[AD4170_AVDD_SUP].supply = "avdd";
> +	st->supplies[AD4170_AVSS_SUP].supply = "avss";
> +	st->supplies[AD4170_IOVDD_SUP].supply = "iovdd";
> +	st->supplies[AD4170_REFIN1P_SUP].supply = "refin1p";
> +	st->supplies[AD4170_REFIN1N_SUP].supply = "refin1n";
> +	st->supplies[AD4170_REFIN2P_SUP].supply = "refin2p";
> +	st->supplies[AD4170_REFIN2N_SUP].supply = "refin2n";
> +
> +	/*
> +	 * If a regulator is not available, it will be set to a dummy regulator.
> +	 * Each channel reference is checked with regulator_get_voltage() before
> +	 * setting attributes so if any channel uses a dummy supply the driver
> +	 * probe will fail.

If you are using an optional regulator to provide an attribute and it's not there
then we should not be registering the attribute (to indicate to userspace
it is not supported).  You are doing complex handling of channel setup in here
anyway so shouldn't be too hard to filter for this

> +	 */
> +	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(st->supplies),
> +				      st->supplies);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "Failed to get supplies\n");
> +
> +	ret = regulator_bulk_enable(ARRAY_SIZE(st->supplies), st->supplies);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "Failed to enable supplies\n");
> +
> +	ret = devm_add_action_or_reset(dev, ad4170_disable_supplies, st);
> +	if (ret)
> +		return dev_err_probe(dev, ret,
> +				     "Failed to add supplies disable action\n");
> +
> +	ret = ad4170_soft_reset(st);
> +	if (ret)
> +		return ret;
> +
> +	ret = ad4170_parse_firmware(indio_dev);
> +	if (ret)
> +		return dev_err_probe(dev, ret,
> +				     "Failed to parse firmware\n");

Check wrapping throughout.  This easily fits on line line under 80 chars.

> +
> +	ret = ad4170_initial_config(indio_dev);
> +	if (ret)
> +		return dev_err_probe(dev, ret,
> +				     "Failed to setup device\n");
> +
> +	init_completion(&st->completion);
> +
> +	ret = ad4170_triggered_buffer_setup(indio_dev);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "Failed to setup read buffer\n");
> +
> +	ad4170_prepare_message(st);
> +
> +	return devm_iio_device_register(dev, indio_dev);
> +}
> +
> +static const struct of_device_id ad4170_of_match[] = {
> +	{
> +		.compatible = "adi,ad4170",
> +	},
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, ad4170_of_match);
> +
> +static struct spi_driver ad4170_driver = {
> +	.driver = {
> +		.name = AD4170_NAME,

As below. String here preferred over the define.

> +		.of_match_table = ad4170_of_match,
> +	},

Need the id_table of spi_match_ids as well so autoprobing works. (odd piece
of history that we can't unwind easily).

> +	.probe = ad4170_probe,
> +};
> +module_spi_driver(ad4170_driver);
> +
> +MODULE_AUTHOR("Ana-Maria Cusco <ana-maria.cusco@xxxxxxxxxx>");
> +MODULE_AUTHOR("Marcelo Schmitt <marcelo.schmitt@xxxxxxxxxx>");
> +MODULE_DESCRIPTION("Analog Devices AD4170 SPI driver");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/iio/adc/ad4170.h b/drivers/iio/adc/ad4170.h
> new file mode 100644
> index 000000000000..5b24788314b1
> --- /dev/null
> +++ b/drivers/iio/adc/ad4170.h
As mentioned at the top, just put this stuff at top of the c file.

> @@ -0,0 +1,316 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * AD4170 ADC driver
> + *
> + * Copyright 2024 Analog Devices Inc.
> + */
> +
> +#include <dt-bindings/iio/adc/adi,ad4170.h>
> +
> +#define AD4170_NAME				"ad4170"

Use the string inline rather than via a define like this.
Easier to review and often there is no specific reason why the string
should be the same in all the places it is used.

> +
> +#define AD4170_READ_MASK BIT(14)
> +/* AD4170 registers */
> +#define AD4170_INTERFACE_CONFIG_A_REG		0x00

Clunky name. I'd shorten it.

> +#define AD4170_STATUS_REG			0x14
> +#define AD4170_DATA_24b_REG			0x1c
> +#define AD4170_PIN_MUXING_REG			0x68
> +#define AD4170_CLOCK_CTRL_REG			0x6A
> +#define AD4170_POWER_DOWN_SW_REG		0x6e
> +#define AD4170_ADC_CTRL_REG			0x70
> +#define AD4170_CHANNEL_EN_REG			0x78
> +#define AD4170_CHAN_SETUP_REG(x)		(0x80 + 4 * (x))
> +#define AD4170_CHAN_MAP_REG(x)			(0x82 + 4 * (x))
> +#define AD4170_MISC_REG(x)			(0xc0 + 14 * (x))
> +#define AD4170_AFE_REG(x)			(0xc2 + 14 * (x))
> +#define AD4170_FILTER_REG(x)			(0xc4 + 14 * (x))
> +#define AD4170_FILTER_FS_REG(x)			(0xc6 + 14 * (x))
> +#define AD4170_OFFSET_REG(x)			(0xc8 + 14 * (x))
> +#define AD4170_GAIN_REG(x)			(0xcb + 14 * (x))
> +#define AD4170_V_BIAS_REG			0x134
> +#define AD4170_CURRENT_SRC_REG(x)		(0x138 + 2 * (x))
> +
> +/* AD4170_REG_INTERFACE_CONFIG_A */

Name the fields to make it obvious what they are in.  Just the config_A bit should do
or INTCONFA or some other shortening.



> +#define AD4170_SW_RESET_MSK		(BIT(7) | BIT(0))
> +#define AD4170_IFACE_CONFIG_ADDR_ASCENSION_MSK	BIT(5)
That made me go look at the datasheet.  Weird naming.  I'd call it ADDR_INC_NDEC
or something like that.

> +#define AD4170_RESET_SLEEP_US	        1000
> +#define AD4170_INT_REF_2_5V		2500000
> +
> +/* AD4170_REG_PIN_MUXING */
> +#define AD4170_PIN_MUXING_DIG_AUX2_CTRL_MSK		GENMASK(7, 6)
> +#define AD4170_PIN_MUXING_DIG_AUX1_CTRL_MSK		GENMASK(5, 4)
> +#define AD4170_PIN_MUXING_SYNC_CTRL_MSK			GENMASK(3, 2)
> +
> +/* AD4170_REG_CLOCK_CTRL */
> +#define AD4170_INT_FREQ_16MHZ				16000000
> +#define AD4170_EXT_FREQ_MHZ_MIN				1000000
> +#define AD4170_EXT_FREQ_MHZ_MAX				17000000
Generally don't mix field definitions with values they map to.  Put these
magic values later, or put them inline where they are used.  They are real
numbers afterall.  MEGA define in units.h is your friend as well for making
them more readable.

> +#define AD4170_CLOCK_CTRL_CLOCKSEL_MSK			GENMASK(1, 0)
> +
> +#define AD4170_INTERNAL_OSC				0x0
> +#define AD4170_INTERNAL_OSC_OUTPUT			0x1
> +#define AD4170_EXTERNAL_OSC				0x2
> +#define AD4170_EXTERNAL_XTAL				0x3

Name these so it's obvious where they go.  So after the field name.

I'll not look closely at the rest of the defines but suggestion is to rethink them
to make it easier to:
1) Figure out which register a field is in.
2) Figure out what values can be set in that field.

> +
> +/* AD4170_REG_POWER_DOWN_SW */
> +#define AD4170_POWER_DOWN_SW_PDSW1_MSK				BIT(1)
> +#define AD4170_POWER_DOWN_SW_PDSW0_MSK				BIT(0)
> +
> +/* AD4170_REG_ADC_CTRL */
> +#define AD4170_ADC_CTRL_MULTI_DATA_REG_SEL_MSK			BIT(7)
> +#define AD4170_REG_CTRL_CONT_READ_MSK				GENMASK(5, 4)
> +#define AD4170_REG_CTRL_MODE_MSK				GENMASK(3, 0)
> +
> +/* AD4170_REG_CHANNEL_EN */
> +#define AD4170_CHANNEL_EN(ch)					BIT(ch)
> +
> +/* AD4170_REG_ADC_CHANNEL_SETUP */
> +#define AD4170_CHANNEL_SETUP_SETUP_MSK				GENMASK(2, 0)
> +
> +/* AD4170_REG_ADC_CHANNEL_MAP */
> +#define AD4170_CHANNEL_MAPN_AINP_MSK				GENMASK(12, 8)
> +#define AD4170_CHANNEL_MAPN_AINM_MSK				GENMASK(4, 0)
> +
> +/* AD4170_REG_ADC_SETUPS_MISC */
> +#define AD4170_MISC_CHOP_IEXC_MSK				GENMASK(15, 14)
> +#define AD4170_MISC_CHOP_ADC_MSK				GENMASK(9, 8)
> +#define AD4170_MISC_BURNOUT_MSK					GENMASK(1, 0)
> +
> +/* AD4170_REG_ADC_SETUPS_AFE */
> +#define AD4170_AFE_REF_BUF_M_MSK				GENMASK(11, 10)
> +#define AD4170_AFE_REF_BUF_P_MSK				GENMASK(9, 8)
> +#define AD4170_AFE_REF_SELECT_MSK				GENMASK(6, 5)
> +#define AD4170_AFE_BIPOLAR_MSK					BIT(4)
> +#define AD4170_AFE_PGA_GAIN_MSK					GENMASK(3, 0)
> +
> +/* AD4170_REG_ADC_SETUPS_FILTER */
> +#define AD4170_SETUPS_POST_FILTER_SEL_MSK			GENMASK(7, 4)
> +#define AD4170_SETUPS_FILTER_TYPE_MSK				GENMASK(3, 0)
> +
> +/* AD4170 REG_OFFSET*/
> +#define AD4170_OFFSET_MSK					GENMASK(23, 0)
> +
> +/* AD4170 REG_GAIN*/
> +#define AD4170_GAIN_MSK						GENMASK(23, 0)
> +#define AD4170_GAIN_REG_DEFAULT					0x555555
> +
> +/* AD4170_REG_CURRENT_SOURCE */
> +#define AD4170_CURRENT_SRC_I_OUT_PIN_MSK			GENMASK(12, 8)
> +#define AD4170_CURRENT_SRC_I_OUT_VAL_MSK			GENMASK(2, 0)
> +
> +/* AD4170_REG_FIR_CONTROL */
> +#define AD4170_FIR_CONTROL_IIR_MODE_MSK				BIT(15)
> +
> +#define AD4170_MAX_CHANNELS				16
> +#define AD4170_MAX_ANALOG_PINS				8
> +#define AD4170_MAX_SETUPS				8
> +#define AD4170_INVALID_SETUP_SLOT			9
> +#define AD4170_NUM_CURRENT_SRC				4
> +#define AD4170_MAX_SAMP_RATE				125000
> +
> +#define AD4170_NUM_ANALOG_PINS				9
> +#define AD4170_NUM_GPIO_PINS				4
> +
> +#define AD4170_DIG_AUX1_DISABLED	0
> +#define AD4170_DIG_AUX1_RDY		1
> +#define AD4170_DIG_AUX1_SYNC		2
> +
> +#define AD4170_DIG_AUX2_DISABLED	0
> +#define AD4170_DIG_AUX2_LDAC		1
> +#define AD4170_DIG_AUX2_SYNC		2
> +
> +#define AD4170_SYNC_DISABLED		0
> +#define AD4170_SYNC_STANDARD		1
> +#define AD4170_SYNC_ALTERNATE		2
> +
> +#define AD4170_I_OUT_0UA		0
> +#define AD4170_I_OUT_10UA		10
> +#define AD4170_I_OUT_50UA		50
> +#define AD4170_I_OUT_100UA		100
> +#define AD4170_I_OUT_250UA		250
> +#define AD4170_I_OUT_500UA		500
> +#define AD4170_I_OUT_1000UA		1000
> +#define AD4170_I_OUT_1500UA		1500

Defines for not so magic numbers where the value is the name aren't
normally all that useful.

> +
> +#define AD4170_BURNOUT_OFF		0
> +#define AD4170_BURNOUT_100NA		100
> +#define AD4170_BURNOUT_2000NA		2000
> +#define AD4170_BURNOUT_10000NA		10000
> +
> +#define AD4170_PGA_OPTIONS		10
> +
> +enum ad4170_pin_function {
> +	AD4170_PIN_UNASIGNED,
> +	AD4170_PIN_ANALOG_IN,
> +	AD4170_PIN_CURRENT_OUT,
> +	AD4170_PIN_VBIAS
> +};
> +
> +enum ad4170_gpio_function {
> +	AD4170_GPIO_UNASIGNED,
> +	AD4170_GPIO_PW_DOW_SWITCH,
> +	AD4170_GPIO_AC_EXCITATION,
> +	AD4170_GPIO_OUTPUT,
> +	AD4170_GPIO_CHANNEL,
> +};
> +
> +#define AD4170_ADC_CTRL_CONT_READ_DISABLE		0
> +#define AD4170_ADC_CTRL_CONT_READ_ENABLE		1
> +//#define AD4170_ADC_CTRL_CONT_READ_TRANSMIT		2

?

> +
> +#define AD4170_ADC_CTRL_MODE_CONT			0
> +#define AD4170_ADC_CTRL_MODE_SINGLE			4
> +#define AD4170_ADC_CTRL_MODE_IDLE			7
> +
> +/**
> + * @enum ad4170_ref_buf
> + * @brief REFIN Buffer Enable.
> + */
> +enum ad4170_ref_buf {
> +	/** Pre-charge Buffer. */

Use longer defines and drop the comments as they should then
be unnecessary.

> +	AD4170_REF_BUF_PRE,
> +	/** Full Buffer.*/
> +	AD4170_REF_BUF_FULL,
> +	/** Bypass */
> +	AD4170_REF_BUF_BYPASS
> +};
> +
> +/**
> + * @enum ad4170_filter_type
> + * @brief Filter Mode for Sinc-Based Filters.
> + */
> +enum ad4170_filter_type {
> +	AD4170_SINC5_AVG,
> +	AD4170_SINC5,
> +	AD4170_SINC3,
> +};
> +
> +/* ADC Register Lengths */
> +static const unsigned int ad4170_reg_size[] = {
> +	[AD4170_INTERFACE_CONFIG_A_REG] = 1,
> +	[AD4170_STATUS_REG]	= 2,
> +	[AD4170_DATA_24b_REG]	= 3,
> +	[AD4170_PIN_MUXING_REG]	= 2,
> +	[AD4170_CLOCK_CTRL_REG]	= 2,
> +	[AD4170_POWER_DOWN_SW_REG]	= 2,
> +	[AD4170_ADC_CTRL_REG]	= 2,
> +	[AD4170_CHANNEL_EN_REG]	= 2,
> +	/*
> +	 * CHANNEL_SETUP and CHANNEL_MAP register are all 2 byte size each and
> +	 * their addresses are interleaved such that we have CHANNEL_SETUP0
> +	 * address followed by CHANNEL_MAP0 address, followed by CHANNEL_SETUP1,
> +	 * and so on until CHANNEL_MAP15.
> +	 * Thus, initialize the register size for them only once.
> +	 */
> +	[AD4170_CHAN_SETUP_REG(0) ... AD4170_CHAN_MAP_REG(AD4170_MAX_CHANNELS - 1)] = 2,
> +	/*
> +	 * MISC, AFE, FILTER, FILTER_FS, OFFSET, and GAIN register addresses are
> +	 * also interleaved but MISC, AFE, FILTER, FILTER_FS, OFFSET are 16-bit
> +	 * while OFFSET, GAIN are 24-bit registers so we can't init them all to
> +	 * the same size.
> +	 */
> +	/* Init MISC register size */

Maybe use a macro for each config set?
Would avoid confusion of having them out of register order here.

> +	[AD4170_MISC_REG(0)] = 2,
> +	[AD4170_MISC_REG(1)] = 2,
> +	[AD4170_MISC_REG(2)] = 2,
> +	[AD4170_MISC_REG(3)] = 2,
> +	[AD4170_MISC_REG(4)] = 2,
> +	[AD4170_MISC_REG(5)] = 2,
> +	[AD4170_MISC_REG(6)] = 2,
> +	[AD4170_MISC_REG(7)] = 2,
> +	/* Init AFE register size */
> +	[AD4170_AFE_REG(0)] = 2,
> +	[AD4170_AFE_REG(1)] = 2,
> +	[AD4170_AFE_REG(2)] = 2,
> +	[AD4170_AFE_REG(3)] = 2,
> +	[AD4170_AFE_REG(4)] = 2,
> +	[AD4170_AFE_REG(5)] = 2,
> +	[AD4170_AFE_REG(6)] = 2,
> +	[AD4170_AFE_REG(7)] = 2,
> +	/* Init FILTER register size */
> +	[AD4170_FILTER_REG(0)]	= 2,
> +	[AD4170_FILTER_REG(1)]	= 2,
> +	[AD4170_FILTER_REG(2)]	= 2,
> +	[AD4170_FILTER_REG(3)]	= 2,
> +	[AD4170_FILTER_REG(4)]	= 2,
> +	[AD4170_FILTER_REG(5)]	= 2,
> +	[AD4170_FILTER_REG(6)]	= 2,
> +	[AD4170_FILTER_REG(7)]	= 2,
> +	/* Init FILTER_FS register size */
> +	[AD4170_FILTER_FS_REG(0)]	= 2,
> +	[AD4170_FILTER_FS_REG(1)]	= 2,
> +	[AD4170_FILTER_FS_REG(2)]	= 2,
> +	[AD4170_FILTER_FS_REG(3)]	= 2,
> +	[AD4170_FILTER_FS_REG(4)]	= 2,
> +	[AD4170_FILTER_FS_REG(5)]	= 2,
> +	[AD4170_FILTER_FS_REG(6)]	= 2,
> +	[AD4170_FILTER_FS_REG(7)]	= 2,
> +	/* Init OFFSET register size */
> +	[AD4170_OFFSET_REG(0)]	= 3,
> +	[AD4170_OFFSET_REG(1)]	= 3,
> +	[AD4170_OFFSET_REG(2)]	= 3,
> +	[AD4170_OFFSET_REG(3)]	= 3,
> +	[AD4170_OFFSET_REG(4)]	= 3,
> +	[AD4170_OFFSET_REG(5)]	= 3,
> +	[AD4170_OFFSET_REG(6)]	= 3,
> +	[AD4170_OFFSET_REG(7)]	= 3,
> +	/* Init GAIN register size */
> +	[AD4170_GAIN_REG(0)]	= 3,
> +	[AD4170_GAIN_REG(1)]	= 3,
> +	[AD4170_GAIN_REG(2)]	= 3,
> +	[AD4170_GAIN_REG(3)]	= 3,
> +	[AD4170_GAIN_REG(4)]	= 3,
> +	[AD4170_GAIN_REG(5)]	= 3,
> +	[AD4170_GAIN_REG(6)]	= 3,
> +	[AD4170_GAIN_REG(7)]	= 3,
> +	[AD4170_V_BIAS_REG]	= 2,
> +	[AD4170_CURRENT_SRC_REG(0) ... AD4170_CURRENT_SRC_REG(AD4170_NUM_CURRENT_SRC - 1)] = 2,
> +};

> +
> +static const unsigned int ad4170_burnout_current_na_tbl[] = {
> +	AD4170_BURNOUT_OFF,

Maybe just call it 0NA which is off :)

> +	AD4170_BURNOUT_100NA,
> +	AD4170_BURNOUT_2000NA,
> +	AD4170_BURNOUT_10000NA,
> +};






[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux