diff mbox series

[v2,1/2] iio:adc:ad7476: Handle the different regulators used by various parts.

Message ID 20210405162325.627977-2-jic23@kernel.org (mailing list archive)
State New, archived
Headers show
Series iio:adc:ad7476: Regulator support and binding doc | expand

Commit Message

Jonathan Cameron April 5, 2021, 4:23 p.m. UTC
From: Jonathan Cameron <Jonathan.Cameron@huawei.com>

Not all of the parts supported by this driver use single supply.
Hence we add chip_info fields to say what additional supplies exist
and in the case of vref, ensure that is used for the reference voltage
rather than vcc.

One corner case is the ad7091r which has an internal reference that
can be over-driven by an external reference connected on the vref pin.
To handle that force_ext_vref is introduced and set if an optional
vref regulator is present.

Tested using really simple QEMU model and some fixed regulators.

The devm_add_action_or_reset() callback is changed to take the
regulator as it's parameter so we can use one callback for all the
different regulators without having to store pointers to them in
the iio_priv() structure.

Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Cc: Michael Hennerich <michael.hennerich@analog.com>
---
 drivers/iio/adc/ad7476.c | 108 +++++++++++++++++++++++++++++++++------
 1 file changed, 93 insertions(+), 15 deletions(-)

Comments

Lars-Peter Clausen April 5, 2021, 5:52 p.m. UTC | #1
On 4/5/21 6:23 PM, Jonathan Cameron wrote:
> From: Jonathan Cameron <Jonathan.Cameron@huawei.com>
>
> Not all of the parts supported by this driver use single supply.
> Hence we add chip_info fields to say what additional supplies exist
> and in the case of vref, ensure that is used for the reference voltage
> rather than vcc.
>
> One corner case is the ad7091r which has an internal reference that
> can be over-driven by an external reference connected on the vref pin.
> To handle that force_ext_vref is introduced and set if an optional
> vref regulator is present.
>
> Tested using really simple QEMU model and some fixed regulators.
>
> The devm_add_action_or_reset() callback is changed to take the
> regulator as it's parameter so we can use one callback for all the
> different regulators without having to store pointers to them in
> the iio_priv() structure.
>
> Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> Cc: Michael Hennerich <michael.hennerich@analog.com>
> ---
>   drivers/iio/adc/ad7476.c | 108 +++++++++++++++++++++++++++++++++------
>   1 file changed, 93 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c
> index 9e9ff07cf972..6867e96e3eda 100644
> --- a/drivers/iio/adc/ad7476.c
> +++ b/drivers/iio/adc/ad7476.c
> @@ -32,12 +32,15 @@ struct ad7476_chip_info {
>   	/* channels used when convst gpio is defined */
>   	struct iio_chan_spec		convst_channel[2];
>   	void (*reset)(struct ad7476_state *);
> +	bool				has_vref;
> +	bool				has_vdrive;
>   };
>   
>   struct ad7476_state {
>   	struct spi_device		*spi;
>   	const struct ad7476_chip_info	*chip_info;
> -	struct regulator		*reg;
> +	struct regulator		*ref_reg;
> +	bool				force_ext_vref;
>   	struct gpio_desc		*convst_gpio;
>   	struct spi_transfer		xfer;
>   	struct spi_message		msg;
> @@ -52,13 +55,17 @@ struct ad7476_state {
>   };
>   
>   enum ad7476_supported_device_ids {
> +	ID_AD7091,
>   	ID_AD7091R,
> +	ID_AD7273,
> +	ID_AD7274,
>   	ID_AD7276,
>   	ID_AD7277,
>   	ID_AD7278,
>   	ID_AD7466,
>   	ID_AD7467,
>   	ID_AD7468,
> +	ID_AD7475,
>   	ID_AD7495,
>   	ID_AD7940,
>   	ID_ADC081S,
> @@ -145,8 +152,8 @@ static int ad7476_read_raw(struct iio_dev *indio_dev,
>   			GENMASK(st->chip_info->channel[0].scan_type.realbits - 1, 0);
>   		return IIO_VAL_INT;
>   	case IIO_CHAN_INFO_SCALE:
> -		if (!st->chip_info->int_vref_uv) {
> -			scale_uv = regulator_get_voltage(st->reg);
> +		if (!st->chip_info->int_vref_uv || st->force_ext_vref) {
Set set->reg_reg to NULL when not present and check for that instead of 
adding force_ext_vref?
> +			scale_uv = regulator_get_voltage(st->ref_reg);
>   			if (scale_uv < 0)
>   				return scale_uv;
>   		} else {
> @@ -187,13 +194,32 @@ static int ad7476_read_raw(struct iio_dev *indio_dev,
>   		BIT(IIO_CHAN_INFO_RAW))
>   
>
>   static int ad7476_probe(struct spi_device *spi)
>   {
> [...]
> +	/* Either vcc or vref (below) as appropriate */
> +	st->ref_reg = reg;
> +
> +	if (st->chip_info->has_vref) {
> +
> +		/* If a device has an internal reference vref is optional */
> +		if (st->chip_info->int_vref_uv) {
> +			reg = devm_regulator_get_optional(&spi->dev, "vref");

I think we need to distinguish between -ENODEV and other errors, if not 
only to handle EPROBE_DEFER.

[...]
kernel test robot April 5, 2021, 9:37 p.m. UTC | #2
Hi Jonathan,

I love your patch! Yet something to improve:

[auto build test ERROR on iio/togreg]
[also build test ERROR on v5.12-rc6 next-20210401]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Jonathan-Cameron/iio-adc-ad7476-Regulator-support-and-binding-doc/20210406-002735
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git togreg
config: riscv-randconfig-r004-20210405 (attached as .config)
compiler: clang version 13.0.0 (https://github.com/llvm/llvm-project 2760a808b9916a2839513b7fd7314a464f52481e)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # install riscv cross compiling tool for clang build
        # apt-get install binutils-riscv64-linux-gnu
        # https://github.com/0day-ci/linux/commit/0c18d053103b05b990e986b54c77a32db4f3f9f4
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Jonathan-Cameron/iio-adc-ad7476-Regulator-support-and-binding-doc/20210406-002735
        git checkout 0c18d053103b05b990e986b54c77a32db4f3f9f4
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=riscv 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

>> drivers/iio/adc/ad7476.c:418:24: error: no member named 'reg' in 'struct ad7476_state'
           regulator_disable(st->reg);
                             ~~  ^
   1 error generated.


vim +418 drivers/iio/adc/ad7476.c

4bb2b8f94ace32 drivers/iio/adc/ad7476.c              Beniamin Bia       2020-03-11  304  
fc52692c49969e drivers/iio/adc/ad7476.c              Greg Kroah-Hartman 2012-12-21  305  static int ad7476_probe(struct spi_device *spi)
349282d82e929e drivers/staging/iio/adc/ad7476_core.c Michael Hennerich  2010-10-11  306  {
349282d82e929e drivers/staging/iio/adc/ad7476_core.c Michael Hennerich  2010-10-11  307  	struct ad7476_state *st;
67688105af8376 drivers/staging/iio/adc/ad7476_core.c Jonathan Cameron   2011-06-27  308  	struct iio_dev *indio_dev;
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  309  	struct regulator *reg;
cb093e444fede7 drivers/staging/iio/adc/ad7476_core.c Lars-Peter Clausen 2012-09-10  310  	int ret;
349282d82e929e drivers/staging/iio/adc/ad7476_core.c Michael Hennerich  2010-10-11  311  
4ea454d2c1a38d drivers/iio/adc/ad7476.c              Sachin Kamat       2013-07-23  312  	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
4ea454d2c1a38d drivers/iio/adc/ad7476.c              Sachin Kamat       2013-07-23  313  	if (!indio_dev)
4ea454d2c1a38d drivers/iio/adc/ad7476.c              Sachin Kamat       2013-07-23  314  		return -ENOMEM;
4ea454d2c1a38d drivers/iio/adc/ad7476.c              Sachin Kamat       2013-07-23  315  
67688105af8376 drivers/staging/iio/adc/ad7476_core.c Jonathan Cameron   2011-06-27  316  	st = iio_priv(indio_dev);
cb093e444fede7 drivers/staging/iio/adc/ad7476_core.c Lars-Peter Clausen 2012-09-10  317  	st->chip_info =
cb093e444fede7 drivers/staging/iio/adc/ad7476_core.c Lars-Peter Clausen 2012-09-10  318  		&ad7476_chip_info_tbl[spi_get_device_id(spi)->driver_data];
cb093e444fede7 drivers/staging/iio/adc/ad7476_core.c Lars-Peter Clausen 2012-09-10  319  
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  320  	reg = devm_regulator_get(&spi->dev, "vcc");
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  321  	if (IS_ERR(reg))
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  322  		return PTR_ERR(reg);
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  323  
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  324  	ret = regulator_enable(reg);
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  325  	if (ret)
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  326  		return ret;
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  327  
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  328  	ret = devm_add_action_or_reset(&spi->dev, ad7476_reg_disable, reg);
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  329  	if (ret)
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  330  		return ret;
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  331  
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  332  	/* Either vcc or vref (below) as appropriate */
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  333  	st->ref_reg = reg;
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  334  
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  335  	if (st->chip_info->has_vref) {
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  336  
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  337  		/* If a device has an internal reference vref is optional */
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  338  		if (st->chip_info->int_vref_uv) {
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  339  			reg = devm_regulator_get_optional(&spi->dev, "vref");
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  340  		} else {
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  341  			reg = devm_regulator_get(&spi->dev, "vref");
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  342  			if (IS_ERR(reg))
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  343  				return PTR_ERR(reg);
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  344  		}
cb093e444fede7 drivers/staging/iio/adc/ad7476_core.c Lars-Peter Clausen 2012-09-10  345  
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  346  		if (!IS_ERR(reg)) {
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  347  			ret = regulator_enable(reg);
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  348  			if (ret)
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  349  				return ret;
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  350  
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  351  			ret = devm_add_action_or_reset(&spi->dev,
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  352  						       ad7476_reg_disable,
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  353  						       reg);
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  354  			if (ret)
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  355  				return ret;
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  356  			st->ref_reg = reg;
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  357  			st->force_ext_vref = true;
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  358  		}
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  359  	}
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  360  
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  361  	if (st->chip_info->has_vdrive) {
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  362  		reg = devm_regulator_get(&spi->dev, "vdrive");
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  363  		if (IS_ERR(reg))
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  364  			return PTR_ERR(reg);
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  365  
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  366  		ret = regulator_enable(reg);
349282d82e929e drivers/staging/iio/adc/ad7476_core.c Michael Hennerich  2010-10-11  367  		if (ret)
4ea454d2c1a38d drivers/iio/adc/ad7476.c              Sachin Kamat       2013-07-23  368  			return ret;
349282d82e929e drivers/staging/iio/adc/ad7476_core.c Michael Hennerich  2010-10-11  369  
4bb2b8f94ace32 drivers/iio/adc/ad7476.c              Beniamin Bia       2020-03-11  370  		ret = devm_add_action_or_reset(&spi->dev, ad7476_reg_disable,
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  371  					       reg);
4bb2b8f94ace32 drivers/iio/adc/ad7476.c              Beniamin Bia       2020-03-11  372  		if (ret)
4bb2b8f94ace32 drivers/iio/adc/ad7476.c              Beniamin Bia       2020-03-11  373  			return ret;
0c18d053103b05 drivers/iio/adc/ad7476.c              Jonathan Cameron   2021-04-05  374  	}
4bb2b8f94ace32 drivers/iio/adc/ad7476.c              Beniamin Bia       2020-03-11  375  
af37e4703d00ce drivers/iio/adc/ad7476.c              Dragos Bogdan      2020-03-11  376  	st->convst_gpio = devm_gpiod_get_optional(&spi->dev,
af37e4703d00ce drivers/iio/adc/ad7476.c              Dragos Bogdan      2020-03-11  377  						  "adi,conversion-start",
af37e4703d00ce drivers/iio/adc/ad7476.c              Dragos Bogdan      2020-03-11  378  						  GPIOD_OUT_LOW);
af37e4703d00ce drivers/iio/adc/ad7476.c              Dragos Bogdan      2020-03-11  379  	if (IS_ERR(st->convst_gpio))
af37e4703d00ce drivers/iio/adc/ad7476.c              Dragos Bogdan      2020-03-11  380  		return PTR_ERR(st->convst_gpio);
af37e4703d00ce drivers/iio/adc/ad7476.c              Dragos Bogdan      2020-03-11  381  
38f71aa905c20c drivers/staging/iio/adc/ad7476_core.c Jonathan Cameron   2011-07-13  382  	spi_set_drvdata(spi, indio_dev);
349282d82e929e drivers/staging/iio/adc/ad7476_core.c Michael Hennerich  2010-10-11  383  
349282d82e929e drivers/staging/iio/adc/ad7476_core.c Michael Hennerich  2010-10-11  384  	st->spi = spi;
349282d82e929e drivers/staging/iio/adc/ad7476_core.c Michael Hennerich  2010-10-11  385  
67688105af8376 drivers/staging/iio/adc/ad7476_core.c Jonathan Cameron   2011-06-27  386  	indio_dev->name = spi_get_device_id(spi)->name;
67688105af8376 drivers/staging/iio/adc/ad7476_core.c Jonathan Cameron   2011-06-27  387  	indio_dev->modes = INDIO_DIRECT_MODE;
67688105af8376 drivers/staging/iio/adc/ad7476_core.c Jonathan Cameron   2011-06-27  388  	indio_dev->channels = st->chip_info->channel;
67688105af8376 drivers/staging/iio/adc/ad7476_core.c Jonathan Cameron   2011-06-27  389  	indio_dev->num_channels = 2;
67688105af8376 drivers/staging/iio/adc/ad7476_core.c Jonathan Cameron   2011-06-27  390  	indio_dev->info = &ad7476_info;
3a6af93dd66eba drivers/iio/adc/ad7476.c              Dragos Bogdan      2020-03-11  391  
a66904b209b6d8 drivers/iio/adc/ad7476.c              Colin Ian King     2020-04-24  392  	if (st->convst_gpio)
3a6af93dd66eba drivers/iio/adc/ad7476.c              Dragos Bogdan      2020-03-11  393  		indio_dev->channels = st->chip_info->convst_channel;
349282d82e929e drivers/staging/iio/adc/ad7476_core.c Michael Hennerich  2010-10-11  394  	/* Setup default message */
349282d82e929e drivers/staging/iio/adc/ad7476_core.c Michael Hennerich  2010-10-11  395  
349282d82e929e drivers/staging/iio/adc/ad7476_core.c Michael Hennerich  2010-10-11  396  	st->xfer.rx_buf = &st->data;
c5e0819e2d82c7 drivers/staging/iio/adc/ad7476_core.c Jonathan Cameron   2011-05-18  397  	st->xfer.len = st->chip_info->channel[0].scan_type.storagebits / 8;
349282d82e929e drivers/staging/iio/adc/ad7476_core.c Michael Hennerich  2010-10-11  398  
349282d82e929e drivers/staging/iio/adc/ad7476_core.c Michael Hennerich  2010-10-11  399  	spi_message_init(&st->msg);
349282d82e929e drivers/staging/iio/adc/ad7476_core.c Michael Hennerich  2010-10-11  400  	spi_message_add_tail(&st->xfer, &st->msg);
349282d82e929e drivers/staging/iio/adc/ad7476_core.c Michael Hennerich  2010-10-11  401  
7a28fe3c93d6cd drivers/staging/iio/adc/ad7476.c      Lars-Peter Clausen 2012-09-10  402  	ret = iio_triggered_buffer_setup(indio_dev, NULL,
7a28fe3c93d6cd drivers/staging/iio/adc/ad7476.c      Lars-Peter Clausen 2012-09-10  403  			&ad7476_trigger_handler, NULL);
349282d82e929e drivers/staging/iio/adc/ad7476_core.c Michael Hennerich  2010-10-11  404  	if (ret)
67688105af8376 drivers/staging/iio/adc/ad7476_core.c Jonathan Cameron   2011-06-27  405  		goto error_disable_reg;
349282d82e929e drivers/staging/iio/adc/ad7476_core.c Michael Hennerich  2010-10-11  406  
87c5b10fd97937 drivers/iio/adc/ad7476.c              Lars-Peter Clausen 2012-09-17  407  	if (st->chip_info->reset)
87c5b10fd97937 drivers/iio/adc/ad7476.c              Lars-Peter Clausen 2012-09-17  408  		st->chip_info->reset(st);
87c5b10fd97937 drivers/iio/adc/ad7476.c              Lars-Peter Clausen 2012-09-17  409  
26d25ae3f0d8ff drivers/staging/iio/adc/ad7476_core.c Jonathan Cameron   2011-09-02  410  	ret = iio_device_register(indio_dev);
26d25ae3f0d8ff drivers/staging/iio/adc/ad7476_core.c Jonathan Cameron   2011-09-02  411  	if (ret)
26d25ae3f0d8ff drivers/staging/iio/adc/ad7476_core.c Jonathan Cameron   2011-09-02  412  		goto error_ring_unregister;
349282d82e929e drivers/staging/iio/adc/ad7476_core.c Michael Hennerich  2010-10-11  413  	return 0;
349282d82e929e drivers/staging/iio/adc/ad7476_core.c Michael Hennerich  2010-10-11  414  
26d25ae3f0d8ff drivers/staging/iio/adc/ad7476_core.c Jonathan Cameron   2011-09-02  415  error_ring_unregister:
7a28fe3c93d6cd drivers/staging/iio/adc/ad7476.c      Lars-Peter Clausen 2012-09-10  416  	iio_triggered_buffer_cleanup(indio_dev);
349282d82e929e drivers/staging/iio/adc/ad7476_core.c Michael Hennerich  2010-10-11  417  error_disable_reg:
349282d82e929e drivers/staging/iio/adc/ad7476_core.c Michael Hennerich  2010-10-11 @418  	regulator_disable(st->reg);
26d25ae3f0d8ff drivers/staging/iio/adc/ad7476_core.c Jonathan Cameron   2011-09-02  419  
349282d82e929e drivers/staging/iio/adc/ad7476_core.c Michael Hennerich  2010-10-11  420  	return ret;
349282d82e929e drivers/staging/iio/adc/ad7476_core.c Michael Hennerich  2010-10-11  421  }
349282d82e929e drivers/staging/iio/adc/ad7476_core.c Michael Hennerich  2010-10-11  422  

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
diff mbox series

Patch

diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c
index 9e9ff07cf972..6867e96e3eda 100644
--- a/drivers/iio/adc/ad7476.c
+++ b/drivers/iio/adc/ad7476.c
@@ -32,12 +32,15 @@  struct ad7476_chip_info {
 	/* channels used when convst gpio is defined */
 	struct iio_chan_spec		convst_channel[2];
 	void (*reset)(struct ad7476_state *);
+	bool				has_vref;
+	bool				has_vdrive;
 };
 
 struct ad7476_state {
 	struct spi_device		*spi;
 	const struct ad7476_chip_info	*chip_info;
-	struct regulator		*reg;
+	struct regulator		*ref_reg;
+	bool				force_ext_vref;
 	struct gpio_desc		*convst_gpio;
 	struct spi_transfer		xfer;
 	struct spi_message		msg;
@@ -52,13 +55,17 @@  struct ad7476_state {
 };
 
 enum ad7476_supported_device_ids {
+	ID_AD7091,
 	ID_AD7091R,
+	ID_AD7273,
+	ID_AD7274,
 	ID_AD7276,
 	ID_AD7277,
 	ID_AD7278,
 	ID_AD7466,
 	ID_AD7467,
 	ID_AD7468,
+	ID_AD7475,
 	ID_AD7495,
 	ID_AD7940,
 	ID_ADC081S,
@@ -145,8 +152,8 @@  static int ad7476_read_raw(struct iio_dev *indio_dev,
 			GENMASK(st->chip_info->channel[0].scan_type.realbits - 1, 0);
 		return IIO_VAL_INT;
 	case IIO_CHAN_INFO_SCALE:
-		if (!st->chip_info->int_vref_uv) {
-			scale_uv = regulator_get_voltage(st->reg);
+		if (!st->chip_info->int_vref_uv || st->force_ext_vref) {
+			scale_uv = regulator_get_voltage(st->ref_reg);
 			if (scale_uv < 0)
 				return scale_uv;
 		} else {
@@ -187,13 +194,32 @@  static int ad7476_read_raw(struct iio_dev *indio_dev,
 		BIT(IIO_CHAN_INFO_RAW))
 
 static const struct ad7476_chip_info ad7476_chip_info_tbl[] = {
+	[ID_AD7091] = {
+		.channel[0] = AD7091R_CHAN(12),
+		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+		.convst_channel[0] = AD7091R_CONVST_CHAN(12),
+		.convst_channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+		.reset = ad7091_reset,
+	},
 	[ID_AD7091R] = {
 		.channel[0] = AD7091R_CHAN(12),
 		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
 		.convst_channel[0] = AD7091R_CONVST_CHAN(12),
 		.convst_channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+		.int_vref_uv = 2500000,
+		.has_vref = true,
 		.reset = ad7091_reset,
 	},
+	[ID_AD7273] = {
+		.channel[0] = AD7940_CHAN(10),
+		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+		.has_vref = true,
+	},
+	[ID_AD7274] = {
+		.channel[0] = AD7940_CHAN(12),
+		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+		.has_vref = true,
+	},
 	[ID_AD7276] = {
 		.channel[0] = AD7940_CHAN(12),
 		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
@@ -218,10 +244,17 @@  static const struct ad7476_chip_info ad7476_chip_info_tbl[] = {
 		.channel[0] = AD7476_CHAN(8),
 		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
 	},
+	[ID_AD7475] = {
+		.channel[0] = AD7476_CHAN(12),
+		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+		.has_vref = true,
+		.has_vdrive = true,
+	},
 	[ID_AD7495] = {
 		.channel[0] = AD7476_CHAN(12),
 		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
 		.int_vref_uv = 2500000,
+		.has_vdrive = true,
 	},
 	[ID_AD7940] = {
 		.channel[0] = AD7940_CHAN(14),
@@ -254,6 +287,7 @@  static const struct ad7476_chip_info ad7476_chip_info_tbl[] = {
 	[ID_LTC2314_14] = {
 		.channel[0] = AD7940_CHAN(14),
 		.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+		.has_vref = true,
 	},
 };
 
@@ -263,15 +297,16 @@  static const struct iio_info ad7476_info = {
 
 static void ad7476_reg_disable(void *data)
 {
-	struct ad7476_state *st = data;
+	struct regulator *reg = data;
 
-	regulator_disable(st->reg);
+	regulator_disable(reg);
 }
 
 static int ad7476_probe(struct spi_device *spi)
 {
 	struct ad7476_state *st;
 	struct iio_dev *indio_dev;
+	struct regulator *reg;
 	int ret;
 
 	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
@@ -282,19 +317,62 @@  static int ad7476_probe(struct spi_device *spi)
 	st->chip_info =
 		&ad7476_chip_info_tbl[spi_get_device_id(spi)->driver_data];
 
-	st->reg = devm_regulator_get(&spi->dev, "vcc");
-	if (IS_ERR(st->reg))
-		return PTR_ERR(st->reg);
+	reg = devm_regulator_get(&spi->dev, "vcc");
+	if (IS_ERR(reg))
+		return PTR_ERR(reg);
 
-	ret = regulator_enable(st->reg);
+	ret = regulator_enable(reg);
 	if (ret)
 		return ret;
 
-	ret = devm_add_action_or_reset(&spi->dev, ad7476_reg_disable,
-				       st);
+	ret = devm_add_action_or_reset(&spi->dev, ad7476_reg_disable, reg);
 	if (ret)
 		return ret;
 
+	/* Either vcc or vref (below) as appropriate */
+	st->ref_reg = reg;
+
+	if (st->chip_info->has_vref) {
+
+		/* If a device has an internal reference vref is optional */
+		if (st->chip_info->int_vref_uv) {
+			reg = devm_regulator_get_optional(&spi->dev, "vref");
+		} else {
+			reg = devm_regulator_get(&spi->dev, "vref");
+			if (IS_ERR(reg))
+				return PTR_ERR(reg);
+		}
+
+		if (!IS_ERR(reg)) {
+			ret = regulator_enable(reg);
+			if (ret)
+				return ret;
+
+			ret = devm_add_action_or_reset(&spi->dev,
+						       ad7476_reg_disable,
+						       reg);
+			if (ret)
+				return ret;
+			st->ref_reg = reg;
+			st->force_ext_vref = true;
+		}
+	}
+
+	if (st->chip_info->has_vdrive) {
+		reg = devm_regulator_get(&spi->dev, "vdrive");
+		if (IS_ERR(reg))
+			return PTR_ERR(reg);
+
+		ret = regulator_enable(reg);
+		if (ret)
+			return ret;
+
+		ret = devm_add_action_or_reset(&spi->dev, ad7476_reg_disable,
+					       reg);
+		if (ret)
+			return ret;
+	}
+
 	st->convst_gpio = devm_gpiod_get_optional(&spi->dev,
 						  "adi,conversion-start",
 						  GPIOD_OUT_LOW);
@@ -333,17 +411,17 @@  static int ad7476_probe(struct spi_device *spi)
 }
 
 static const struct spi_device_id ad7476_id[] = {
-	{"ad7091", ID_AD7091R},
+	{"ad7091", ID_AD7091},
 	{"ad7091r", ID_AD7091R},
-	{"ad7273", ID_AD7277},
-	{"ad7274", ID_AD7276},
+	{"ad7273", ID_AD7273},
+	{"ad7274", ID_AD7274},
 	{"ad7276", ID_AD7276},
 	{"ad7277", ID_AD7277},
 	{"ad7278", ID_AD7278},
 	{"ad7466", ID_AD7466},
 	{"ad7467", ID_AD7467},
 	{"ad7468", ID_AD7468},
-	{"ad7475", ID_AD7466},
+	{"ad7475", ID_AD7475},
 	{"ad7476", ID_AD7466},
 	{"ad7476a", ID_AD7466},
 	{"ad7477", ID_AD7467},