diff mbox series

[v8,1/2] dt-bindings: iio: adc: add max14001

Message ID 20230622143227.30147-1-kimseer.paller@analog.com
State Not Applicable, archived
Headers show
Series [v8,1/2] dt-bindings: iio: adc: add max14001 | expand

Checks

Context Check Description
robh/checkpatch success
robh/patch-applied success
robh/dtbs-check warning build log
robh/dt-meta-schema success

Commit Message

Paller, Kim Seer June 22, 2023, 2:32 p.m. UTC
The MAX14001 is a configurable, isolated 10-bit ADC for multi-range
binary inputs.

Signed-off-by: Kim Seer Paller <kimseer.paller@analog.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
---
V7 -> V8: Added "Reviewed-by" tag.
V6 -> V7: No changes.
V5 -> V6: Removed tags.
V3 -> V5: Added spaces between prefixes in subject. Fixed MAINTAINERS reference.

 .../bindings/iio/adc/adi,max14001.yaml        | 54 +++++++++++++++++++
 MAINTAINERS                                   |  7 +++
 2 files changed, 61 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iio/adc/adi,max14001.yaml


base-commit: 6f449d52b90fdd927fcf9df0388701de6d5381c6

Comments

Jonathan Cameron July 2, 2023, 10:04 a.m. UTC | #1
On Thu, 22 Jun 2023 22:32:27 +0800
Kim Seer Paller <kimseer.paller@analog.com> wrote:

> The MAX14001 is configurable, isolated 10-bit ADCs for multi-range
> binary inputs.
> 
> Signed-off-by: Kim Seer Paller <kimseer.paller@analog.com>
> Reported-by: kernel test robot <lkp@intel.com>
> Closes: https://lore.kernel.org/oe-kbuild-all/202306211545.7b6CdqsL-lkp@intel.com/

Hi, 

Two outstanding comments that I think I raised in earlier reviews..

Jonathan

> diff --git a/drivers/iio/adc/max14001.c b/drivers/iio/adc/max14001.c
> new file mode 100644
> index 000000000000..a21ebcde71fa
> --- /dev/null
> +++ b/drivers/iio/adc/max14001.c

...

> +static int max14001_read(void *context, unsigned int reg_addr, unsigned int *data)
> +{
> +	struct max14001_state *st = context;
> +	int ret;
> +
> +	struct spi_transfer xfers[] = {
> +		{
> +			.tx_buf = &st->spi_tx_buffer,
> +			.len = sizeof(st->spi_tx_buffer),
> +			.cs_change = 1,
> +		}, {
> +			.rx_buf = &st->spi_rx_buffer,
> +			.len = sizeof(st->spi_rx_buffer),
> +		},
> +	};
> +
> +	/*
> +	 * Convert transmit buffer to big-endian format and reverse transmit
> +	 * buffer to align with the LSB-first input on SDI port.
> +	 */
> +	st->spi_tx_buffer = cpu_to_be16(bitrev16(FIELD_PREP(MAX14001_ADDR_MASK,
> +								reg_addr)));
> +
> +	ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers));
> +	if (ret)
> +		return ret;
> +
> +	/*
> +	 * Align received data from the receive buffer, reversing and reordering
> +	 * it to match the expected MSB-first format.
> +	 */
> +	*data = (__force u16)(be16_to_cpu(bitrev16(st->spi_rx_buffer))) &
> +							MAX14001_DATA_MASK;
> +
These sequences still confuse me a lot because I'd expect the values in tx
to have the opposite operations applied to those for rx and that's not the
case.

Let's take a le system. 
tx = cpu_to_be16(bitrev16(x))
   = cpu_to_be16((__bitrev8(x & 0xff) << 8) | __bitrev8(x >> 8));
   = __bitrev8(x & 0xff) | (__bitrev8(x >> 8) << 8)
or swap all the bits in each byte, but don't swap the bytes.

rx = cpu_to_be16(bitrev16(x))
   = be16_to_cpu(((__bitrev8(x & 0xff) << 8) | __bitrev8(x >> 8)_
   = __bitrev8(x & 0xff) | __bitrev(x >> 8)
   
also swap all the bits in each byte, but don't swap the bytes.

So it is the reverse because the bytes swaps unwind themselves somewhat.
For a be system cpu_to_be16 etc are noop.
tx = (__bitrev8(x & 0xff) << 8) | __bitrev8(x >> 8)
rx = (__bitrev8(x & 0xff) << 8) | __bitrev8(x >> 8)

So in this case swap all 16 bits.

Now, given I'd expected them to be reversed for the tx vs rx case.
E.g.
tx = cpu_to_be16(bitrev16(x))
As above.
For rx, le host
rx = bitrev16(be16_to_cpu(x))
   = __bitrev8((x >> 8) & 0xff) << 8) |  __bitrev8((((x & 0xff) << 8) >> 8)
same as above (if you swap the two terms I think.

For be the be16_to_cpu is a noop again, so it's just bitrev16(x) as expected.

Hence if I've understood this correctly you could reverse the terms so that
it was 'obvious' you were doing the opposite for the tx term vs the rx one
without making the slightest bit of difference....
   
hmm. Might be worth doing simply to avoid questions.


> +	return 0;
> +}
> +static int max14001_reg_update(struct max14001_state *st,
> +				unsigned int reg_addr,
> +				unsigned int mask,
> +				unsigned int val)
> +{
> +	int ret;
> +	unsigned int reg_data;
> +
> +	/* Enable SPI Registers Write */
> +	ret = max14001_write(st, MAX14001_WEN, MAX14001_WRITE_WEN);
> +	if (ret)
> +		return ret;
> +
> +	ret = max14001_read(st, reg_addr, &reg_data);
> +	if (ret)
> +		return ret;
> +
> +	reg_data |= FIELD_PREP(mask, val);

This is still a problem if the compiler happens to fail to figure out
that mask is a compile time constant.  Given it only ever takes one value
I'd suggest either calling the FIELD_PREP at the caller, or just 
pushing all this code inline so that you can put the definition
inline.

> +
> +	ret = max14001_write(st, reg_addr, reg_data);
> +	if (ret)
> +		return ret;
> +
> +	/* Write Verification Register */
> +	ret = max14001_write_verification_reg(st, reg_addr);
> +	if (ret)
> +		return ret;
> +
> +	/* Disable SPI Registers Write */
> +	return max14001_write(st, MAX14001_WEN, 0);
> +}
Paller, Kim Seer July 4, 2023, 9:40 a.m. UTC | #2
> -----Original Message-----
> From: Jonathan Cameron <Jonathan.Cameron@Huawei.com>
> Sent: Sunday, July 2, 2023 6:04 PM
> To: Paller, Kim Seer <KimSeer.Paller@analog.com>
> Cc: jic23@kernel.org; lars@metafoo.de; lgirdwood@gmail.com;
> broonie@kernel.org; Hennerich, Michael <Michael.Hennerich@analog.com>;
> andy.shevchenko@gmail.com; robh@kernel.org;
> krzysztof.kozlowski@linaro.org; conor+dt@kernel.org; linux-
> iio@vger.kernel.org; linux-kernel@vger.kernel.org; devicetree@vger.kernel.org;
> kernel test robot <lkp@intel.com>
> Subject: Re: [PATCH v8 2/2] iio: adc: max14001: New driver
> 
> [External]
> 
> On Thu, 22 Jun 2023 22:32:27 +0800
> Kim Seer Paller <kimseer.paller@analog.com> wrote:
> 
> > The MAX14001 is configurable, isolated 10-bit ADCs for multi-range
> > binary inputs.
> >
> > Signed-off-by: Kim Seer Paller <kimseer.paller@analog.com>
> > Reported-by: kernel test robot <lkp@intel.com>
> > Closes:
> > https://urldefense.com/v3/__https://lore.kernel.org/oe-kbuild-all/2023
> > 06211545.7b6CdqsL-
> lkp@intel.com/__;!!A3Ni8CS0y2Y!4npD8X6TpKmeLcUf8QqQW
> >
> yEFp_Z1ORKb2dZNpuqfj0ZK74NiCYKQLNWEfKzVmuKTHJO0RW8n01vdXURqBvc
> ueb3V1Sb
> > GQdI$
> 
> Hi,
> 
> Two outstanding comments that I think I raised in earlier reviews..
> 
> Jonathan
> 
> > diff --git a/drivers/iio/adc/max14001.c b/drivers/iio/adc/max14001.c
> > new file mode 100644 index 000000000000..a21ebcde71fa
> > --- /dev/null
> > +++ b/drivers/iio/adc/max14001.c
> 
> ...
> 
> > +static int max14001_read(void *context, unsigned int reg_addr, unsigned int
> *data)
> > +{
> > +	struct max14001_state *st = context;
> > +	int ret;
> > +
> > +	struct spi_transfer xfers[] = {
> > +		{
> > +			.tx_buf = &st->spi_tx_buffer,
> > +			.len = sizeof(st->spi_tx_buffer),
> > +			.cs_change = 1,
> > +		}, {
> > +			.rx_buf = &st->spi_rx_buffer,
> > +			.len = sizeof(st->spi_rx_buffer),
> > +		},
> > +	};
> > +
> > +	/*
> > +	 * Convert transmit buffer to big-endian format and reverse transmit
> > +	 * buffer to align with the LSB-first input on SDI port.
> > +	 */
> > +	st->spi_tx_buffer =
> cpu_to_be16(bitrev16(FIELD_PREP(MAX14001_ADDR_MASK,
> > +								reg_addr)));
> > +
> > +	ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers));
> > +	if (ret)
> > +		return ret;
> > +
> > +	/*
> > +	 * Align received data from the receive buffer, reversing and reordering
> > +	 * it to match the expected MSB-first format.
> > +	 */
> > +	*data = (__force u16)(be16_to_cpu(bitrev16(st->spi_rx_buffer))) &
> > +
> 	MAX14001_DATA_MASK;
> > +
> These sequences still confuse me a lot because I'd expect the values in tx
> to have the opposite operations applied to those for rx and that's not the
> case.
> 
> Let's take a le system.
> tx = cpu_to_be16(bitrev16(x))
>    = cpu_to_be16((__bitrev8(x & 0xff) << 8) | __bitrev8(x >> 8));
>    = __bitrev8(x & 0xff) | (__bitrev8(x >> 8) << 8)
> or swap all the bits in each byte, but don't swap the bytes.
> 
> rx = cpu_to_be16(bitrev16(x))
>    = be16_to_cpu(((__bitrev8(x & 0xff) << 8) | __bitrev8(x >> 8)_
>    = __bitrev8(x & 0xff) | __bitrev(x >> 8)
> 
> also swap all the bits in each byte, but don't swap the bytes.
> 
> So it is the reverse because the bytes swaps unwind themselves somewhat.
> For a be system cpu_to_be16 etc are noop.
> tx = (__bitrev8(x & 0xff) << 8) | __bitrev8(x >> 8)
> rx = (__bitrev8(x & 0xff) << 8) | __bitrev8(x >> 8)
> 
> So in this case swap all 16 bits.
> 
> Now, given I'd expected them to be reversed for the tx vs rx case.
> E.g.
> tx = cpu_to_be16(bitrev16(x))
> As above.
> For rx, le host
> rx = bitrev16(be16_to_cpu(x))
>    = __bitrev8((x >> 8) & 0xff) << 8) |  __bitrev8((((x & 0xff) << 8) >> 8)
> same as above (if you swap the two terms I think.
> 
> For be the be16_to_cpu is a noop again, so it's just bitrev16(x) as expected.
> 
> Hence if I've understood this correctly you could reverse the terms so that
> it was 'obvious' you were doing the opposite for the tx term vs the rx one
> without making the slightest bit of difference....
> 
> hmm. Might be worth doing simply to avoid questions.

Thank you for your feedback. I have tested the modifications based on your 
suggestions, taking the le system into account, and it appears that the code is 
functioning correctly. Before sending the new patch version, I would like to 
confirm if this aligns with your comments.

static int max14001_read(void *context, unsigned int reg_addr, unsigned int *data)
{
	struct max14001_state *st = context;
	int ret;

	struct spi_transfer xfers[] = {
		{
			.tx_buf = &st->spi_tx_buffer,
			.len = sizeof(st->spi_tx_buffer),
			.cs_change = 1,
		}, {
			.rx_buf = &st->spi_rx_buffer,
			.len = sizeof(st->spi_rx_buffer),
		},
	};

	st->spi_tx_buffer = cpu_to_be16(bitrev16(FIELD_PREP(MAX14001_ADDR_MASK, reg_addr)));

	ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers));
	if (ret)
		return ret;

	*data = cpu_to_be16(bitrev16(st->spi_rx_buffer));

	return 0;
}

static int max14001_write(void *context, unsigned int reg_addr, unsigned int data)
{
	struct max14001_state *st = context;

	st->spi_tx_buffer = cpu_to_be16(bitrev16(
				FIELD_PREP(MAX14001_ADDR_MASK, reg_addr) |
				FIELD_PREP(MAX14001_SET_WRITE_BIT, 1) |
				FIELD_PREP(MAX14001_DATA_MASK, data)));

	return spi_write(st->spi, &st->spi_tx_buffer, sizeof(st->spi_tx_buffer));
}
 
> > +	return 0;
> > +}
> > +static int max14001_reg_update(struct max14001_state *st,
> > +				unsigned int reg_addr,
> > +				unsigned int mask,
> > +				unsigned int val)
> > +{
> > +	int ret;
> > +	unsigned int reg_data;
> > +
> > +	/* Enable SPI Registers Write */
> > +	ret = max14001_write(st, MAX14001_WEN, MAX14001_WRITE_WEN);
> > +	if (ret)
> > +		return ret;
> > +
> > +	ret = max14001_read(st, reg_addr, &reg_data);
> > +	if (ret)
> > +		return ret;
> > +
> > +	reg_data |= FIELD_PREP(mask, val);
> 
> This is still a problem if the compiler happens to fail to figure out
> that mask is a compile time constant.  Given it only ever takes one value
> I'd suggest either calling the FIELD_PREP at the caller, or just
> pushing all this code inline so that you can put the definition
> inline.

I would like to confirm including the 'static inline' keyword for the 
max14001_reg_update function.

> > +
> > +	ret = max14001_write(st, reg_addr, reg_data);
> > +	if (ret)
> > +		return ret;
> > +
> > +	/* Write Verification Register */
> > +	ret = max14001_write_verification_reg(st, reg_addr);
> > +	if (ret)
> > +		return ret;
> > +
> > +	/* Disable SPI Registers Write */
> > +	return max14001_write(st, MAX14001_WEN, 0);
> > +}
> 

Best Regards,
Kim Seer Paller
Jonathan Cameron July 5, 2023, 7:55 a.m. UTC | #3
On Tue, 4 Jul 2023 09:40:56 +0000
"Paller, Kim Seer" <KimSeer.Paller@analog.com> wrote:

> > -----Original Message-----
> > From: Jonathan Cameron <Jonathan.Cameron@Huawei.com>
> > Sent: Sunday, July 2, 2023 6:04 PM
> > To: Paller, Kim Seer <KimSeer.Paller@analog.com>
> > Cc: jic23@kernel.org; lars@metafoo.de; lgirdwood@gmail.com;
> > broonie@kernel.org; Hennerich, Michael <Michael.Hennerich@analog.com>;
> > andy.shevchenko@gmail.com; robh@kernel.org;
> > krzysztof.kozlowski@linaro.org; conor+dt@kernel.org; linux-
> > iio@vger.kernel.org; linux-kernel@vger.kernel.org; devicetree@vger.kernel.org;
> > kernel test robot <lkp@intel.com>
> > Subject: Re: [PATCH v8 2/2] iio: adc: max14001: New driver
> > 
> > [External]
> > 
> > On Thu, 22 Jun 2023 22:32:27 +0800
> > Kim Seer Paller <kimseer.paller@analog.com> wrote:
> >   
> > > The MAX14001 is configurable, isolated 10-bit ADCs for multi-range
> > > binary inputs.
> > >
> > > Signed-off-by: Kim Seer Paller <kimseer.paller@analog.com>
> > > Reported-by: kernel test robot <lkp@intel.com>
> > > Closes:
> > > https://urldefense.com/v3/__https://lore.kernel.org/oe-kbuild-all/2023
> > > 06211545.7b6CdqsL-  
> > lkp@intel.com/__;!!A3Ni8CS0y2Y!4npD8X6TpKmeLcUf8QqQW  
> > >  
> > yEFp_Z1ORKb2dZNpuqfj0ZK74NiCYKQLNWEfKzVmuKTHJO0RW8n01vdXURqBvc
> > ueb3V1Sb  
> > > GQdI$  
> > 
> > Hi,
> > 
> > Two outstanding comments that I think I raised in earlier reviews..
> > 
> > Jonathan
> >   
> > > diff --git a/drivers/iio/adc/max14001.c b/drivers/iio/adc/max14001.c
> > > new file mode 100644 index 000000000000..a21ebcde71fa
> > > --- /dev/null
> > > +++ b/drivers/iio/adc/max14001.c  
> > 
> > ...
> >   
> > > +static int max14001_read(void *context, unsigned int reg_addr, unsigned int  
> > *data)  
> > > +{
> > > +	struct max14001_state *st = context;
> > > +	int ret;
> > > +
> > > +	struct spi_transfer xfers[] = {
> > > +		{
> > > +			.tx_buf = &st->spi_tx_buffer,
> > > +			.len = sizeof(st->spi_tx_buffer),
> > > +			.cs_change = 1,
> > > +		}, {
> > > +			.rx_buf = &st->spi_rx_buffer,
> > > +			.len = sizeof(st->spi_rx_buffer),
> > > +		},
> > > +	};
> > > +
> > > +	/*
> > > +	 * Convert transmit buffer to big-endian format and reverse transmit
> > > +	 * buffer to align with the LSB-first input on SDI port.
> > > +	 */
> > > +	st->spi_tx_buffer =  
> > cpu_to_be16(bitrev16(FIELD_PREP(MAX14001_ADDR_MASK,  
> > > +								reg_addr)));
> > > +
> > > +	ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers));
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	/*
> > > +	 * Align received data from the receive buffer, reversing and reordering
> > > +	 * it to match the expected MSB-first format.
> > > +	 */
> > > +	*data = (__force u16)(be16_to_cpu(bitrev16(st->spi_rx_buffer))) &
> > > +  
> > 	MAX14001_DATA_MASK;  
> > > +  
> > These sequences still confuse me a lot because I'd expect the values in tx
> > to have the opposite operations applied to those for rx and that's not the
> > case.
> > 
> > Let's take a le system.
> > tx = cpu_to_be16(bitrev16(x))
> >    = cpu_to_be16((__bitrev8(x & 0xff) << 8) | __bitrev8(x >> 8));
> >    = __bitrev8(x & 0xff) | (__bitrev8(x >> 8) << 8)
> > or swap all the bits in each byte, but don't swap the bytes.
> > 
> > rx = cpu_to_be16(bitrev16(x))
> >    = be16_to_cpu(((__bitrev8(x & 0xff) << 8) | __bitrev8(x >> 8)_
> >    = __bitrev8(x & 0xff) | __bitrev(x >> 8)
> > 
> > also swap all the bits in each byte, but don't swap the bytes.
> > 
> > So it is the reverse because the bytes swaps unwind themselves somewhat.
> > For a be system cpu_to_be16 etc are noop.
> > tx = (__bitrev8(x & 0xff) << 8) | __bitrev8(x >> 8)
> > rx = (__bitrev8(x & 0xff) << 8) | __bitrev8(x >> 8)
> > 
> > So in this case swap all 16 bits.
> > 
> > Now, given I'd expected them to be reversed for the tx vs rx case.
> > E.g.
> > tx = cpu_to_be16(bitrev16(x))
> > As above.
> > For rx, le host
> > rx = bitrev16(be16_to_cpu(x))
> >    = __bitrev8((x >> 8) & 0xff) << 8) |  __bitrev8((((x & 0xff) << 8) >> 8)
> > same as above (if you swap the two terms I think.
> > 
> > For be the be16_to_cpu is a noop again, so it's just bitrev16(x) as expected.
> > 
> > Hence if I've understood this correctly you could reverse the terms so that
> > it was 'obvious' you were doing the opposite for the tx term vs the rx one
> > without making the slightest bit of difference....
> > 
> > hmm. Might be worth doing simply to avoid questions.  
> 
> Thank you for your feedback. I have tested the modifications based on your 
> suggestions, taking the le system into account, and it appears that the code is 
> functioning correctly. Before sending the new patch version, I would like to 
> confirm if this aligns with your comments.
Yes. This looks good to me.

> 
> static int max14001_read(void *context, unsigned int reg_addr, unsigned int *data)
> {
> 	struct max14001_state *st = context;
> 	int ret;
> 
> 	struct spi_transfer xfers[] = {
> 		{
> 			.tx_buf = &st->spi_tx_buffer,
> 			.len = sizeof(st->spi_tx_buffer),
> 			.cs_change = 1,
> 		}, {
> 			.rx_buf = &st->spi_rx_buffer,
> 			.len = sizeof(st->spi_rx_buffer),
> 		},
> 	};
> 
> 	st->spi_tx_buffer = cpu_to_be16(bitrev16(FIELD_PREP(MAX14001_ADDR_MASK, reg_addr)));
> 
> 	ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers));
> 	if (ret)
> 		return ret;
> 
> 	*data = cpu_to_be16(bitrev16(st->spi_rx_buffer));
> 
> 	return 0;
> }
> 
> static int max14001_write(void *context, unsigned int reg_addr, unsigned int data)
> {
> 	struct max14001_state *st = context;
> 
> 	st->spi_tx_buffer = cpu_to_be16(bitrev16(
> 				FIELD_PREP(MAX14001_ADDR_MASK, reg_addr) |
> 				FIELD_PREP(MAX14001_SET_WRITE_BIT, 1) |
> 				FIELD_PREP(MAX14001_DATA_MASK, data)));
> 
> 	return spi_write(st->spi, &st->spi_tx_buffer, sizeof(st->spi_tx_buffer));
> }
>  
> > > +	return 0;
> > > +}
> > > +static int max14001_reg_update(struct max14001_state *st,
> > > +				unsigned int reg_addr,
> > > +				unsigned int mask,
> > > +				unsigned int val)
> > > +{
> > > +	int ret;
> > > +	unsigned int reg_data;
> > > +
> > > +	/* Enable SPI Registers Write */
> > > +	ret = max14001_write(st, MAX14001_WEN, MAX14001_WRITE_WEN);
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	ret = max14001_read(st, reg_addr, &reg_data);
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	reg_data |= FIELD_PREP(mask, val);  
> > 
> > This is still a problem if the compiler happens to fail to figure out
> > that mask is a compile time constant.  Given it only ever takes one value
> > I'd suggest either calling the FIELD_PREP at the caller, or just
> > pushing all this code inline so that you can put the definition
> > inline.  
> 
> I would like to confirm including the 'static inline' keyword for the 
> max14001_reg_update function.

I think it's not sufficient as the compiler is allowed to ignore that.
There are ways to force it but they aren't pretty so don't use them!

Better to reorganize the code so that the value is clearly const
without the compiler having to be clever.

Jonathan

> 
> > > +
> > > +	ret = max14001_write(st, reg_addr, reg_data);
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	/* Write Verification Register */
> > > +	ret = max14001_write_verification_reg(st, reg_addr);
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	/* Disable SPI Registers Write */
> > > +	return max14001_write(st, MAX14001_WEN, 0);
> > > +}  
> >   
> 
> Best Regards,
> Kim Seer Paller
> 
>
Andy Shevchenko July 5, 2023, 8:53 a.m. UTC | #4
On Wed, Jul 5, 2023 at 10:55 AM Jonathan Cameron
<Jonathan.Cameron@huawei.com> wrote:
> > > From: Jonathan Cameron <Jonathan.Cameron@Huawei.com>
> > > Sent: Sunday, July 2, 2023 6:04 PM
> > > On Thu, 22 Jun 2023 22:32:27 +0800
> > > Kim Seer Paller <kimseer.paller@analog.com> wrote:

...

> > > > + /*
> > > > +  * Convert transmit buffer to big-endian format and reverse transmit
> > > > +  * buffer to align with the LSB-first input on SDI port.
> > > > +  */
> > > > + st->spi_tx_buffer =
> > > cpu_to_be16(bitrev16(FIELD_PREP(MAX14001_ADDR_MASK,
> > > > +                                                         reg_addr)));
> > > > +
> > > > + ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers));
> > > > + if (ret)
> > > > +         return ret;
> > > > +
> > > > + /*
> > > > +  * Align received data from the receive buffer, reversing and reordering
> > > > +  * it to match the expected MSB-first format.
> > > > +  */
> > > > + *data = (__force u16)(be16_to_cpu(bitrev16(st->spi_rx_buffer))) &
> > > > +
> > >     MAX14001_DATA_MASK;
> > > > +
> > > These sequences still confuse me a lot because I'd expect the values in tx
> > > to have the opposite operations applied to those for rx and that's not the
> > > case.
> > >
> > > Let's take a le system.
> > > tx = cpu_to_be16(bitrev16(x))
> > >    = cpu_to_be16((__bitrev8(x & 0xff) << 8) | __bitrev8(x >> 8));
> > >    = __bitrev8(x & 0xff) | (__bitrev8(x >> 8) << 8)
> > > or swap all the bits in each byte, but don't swap the bytes.
> > >
> > > rx = cpu_to_be16(bitrev16(x))
> > >    = be16_to_cpu(((__bitrev8(x & 0xff) << 8) | __bitrev8(x >> 8)_
> > >    = __bitrev8(x & 0xff) | __bitrev(x >> 8)
> > >
> > > also swap all the bits in each byte, but don't swap the bytes.
> > >
> > > So it is the reverse because the bytes swaps unwind themselves somewhat.
> > > For a be system cpu_to_be16 etc are noop.
> > > tx = (__bitrev8(x & 0xff) << 8) | __bitrev8(x >> 8)
> > > rx = (__bitrev8(x & 0xff) << 8) | __bitrev8(x >> 8)
> > >
> > > So in this case swap all 16 bits.
> > >
> > > Now, given I'd expected them to be reversed for the tx vs rx case.
> > > E.g.
> > > tx = cpu_to_be16(bitrev16(x))
> > > As above.
> > > For rx, le host
> > > rx = bitrev16(be16_to_cpu(x))
> > >    = __bitrev8((x >> 8) & 0xff) << 8) |  __bitrev8((((x & 0xff) << 8) >> 8)
> > > same as above (if you swap the two terms I think.
> > >
> > > For be the be16_to_cpu is a noop again, so it's just bitrev16(x) as expected.
> > >
> > > Hence if I've understood this correctly you could reverse the terms so that
> > > it was 'obvious' you were doing the opposite for the tx term vs the rx one
> > > without making the slightest bit of difference....
> > >
> > > hmm. Might be worth doing simply to avoid questions.
> >
> > Thank you for your feedback. I have tested the modifications based on your
> > suggestions, taking the le system into account, and it appears that the code is
> > functioning correctly. Before sending the new patch version, I would like to
> > confirm if this aligns with your comments.

> Yes. This looks good to me.

I think the implementation is still incorrect. See below.

> > static int max14001_read(void *context, unsigned int reg_addr, unsigned int *data)
> > {
> >       struct max14001_state *st = context;
> >       int ret;
> >
> >       struct spi_transfer xfers[] = {
> >               {
> >                       .tx_buf = &st->spi_tx_buffer,
> >                       .len = sizeof(st->spi_tx_buffer),
> >                       .cs_change = 1,
> >               }, {
> >                       .rx_buf = &st->spi_rx_buffer,
> >                       .len = sizeof(st->spi_rx_buffer),
> >               },
> >       };

> >       st->spi_tx_buffer = cpu_to_be16(bitrev16(FIELD_PREP(MAX14001_ADDR_MASK, reg_addr)));

Here we got bits in CPU order, reversed them and converted to BE16.

> >       ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers));
> >       if (ret)
> >               return ret;

> >       *data = cpu_to_be16(bitrev16(st->spi_rx_buffer));

Here we take __be16 response, reverse them and convert to BE16?!
This is weird. You should have be16_to_cpu() somewhere, not the opposite.

> >       return 0;
> > }

Isn't, btw, the reinvented spi_...write_then_read() (or what is it
called?) call?

> > static int max14001_write(void *context, unsigned int reg_addr, unsigned int data)
> > {
> >       struct max14001_state *st = context;
> >
> >       st->spi_tx_buffer = cpu_to_be16(bitrev16(
> >                               FIELD_PREP(MAX14001_ADDR_MASK, reg_addr) |
> >                               FIELD_PREP(MAX14001_SET_WRITE_BIT, 1) |
> >                               FIELD_PREP(MAX14001_DATA_MASK, data)));
> >
> >       return spi_write(st->spi, &st->spi_tx_buffer, sizeof(st->spi_tx_buffer));
> > }
Jonathan Cameron July 5, 2023, 9:28 a.m. UTC | #5
On Wed, 5 Jul 2023 11:53:17 +0300
Andy Shevchenko <andy.shevchenko@gmail.com> wrote:

> On Wed, Jul 5, 2023 at 10:55 AM Jonathan Cameron
> <Jonathan.Cameron@huawei.com> wrote:
> > > > From: Jonathan Cameron <Jonathan.Cameron@Huawei.com>
> > > > Sent: Sunday, July 2, 2023 6:04 PM
> > > > On Thu, 22 Jun 2023 22:32:27 +0800
> > > > Kim Seer Paller <kimseer.paller@analog.com> wrote:  
> 
> ...
> 
> > > > > + /*
> > > > > +  * Convert transmit buffer to big-endian format and reverse transmit
> > > > > +  * buffer to align with the LSB-first input on SDI port.
> > > > > +  */
> > > > > + st->spi_tx_buffer =  
> > > > cpu_to_be16(bitrev16(FIELD_PREP(MAX14001_ADDR_MASK,  
> > > > > +                                                         reg_addr)));
> > > > > +
> > > > > + ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers));
> > > > > + if (ret)
> > > > > +         return ret;
> > > > > +
> > > > > + /*
> > > > > +  * Align received data from the receive buffer, reversing and reordering
> > > > > +  * it to match the expected MSB-first format.
> > > > > +  */
> > > > > + *data = (__force u16)(be16_to_cpu(bitrev16(st->spi_rx_buffer))) &
> > > > > +  
> > > >     MAX14001_DATA_MASK;  
> > > > > +  
> > > > These sequences still confuse me a lot because I'd expect the values in tx
> > > > to have the opposite operations applied to those for rx and that's not the
> > > > case.
> > > >
> > > > Let's take a le system.
> > > > tx = cpu_to_be16(bitrev16(x))
> > > >    = cpu_to_be16((__bitrev8(x & 0xff) << 8) | __bitrev8(x >> 8));
> > > >    = __bitrev8(x & 0xff) | (__bitrev8(x >> 8) << 8)
> > > > or swap all the bits in each byte, but don't swap the bytes.
> > > >
> > > > rx = cpu_to_be16(bitrev16(x))
> > > >    = be16_to_cpu(((__bitrev8(x & 0xff) << 8) | __bitrev8(x >> 8)_
> > > >    = __bitrev8(x & 0xff) | __bitrev(x >> 8)
> > > >
> > > > also swap all the bits in each byte, but don't swap the bytes.
> > > >
> > > > So it is the reverse because the bytes swaps unwind themselves somewhat.
> > > > For a be system cpu_to_be16 etc are noop.
> > > > tx = (__bitrev8(x & 0xff) << 8) | __bitrev8(x >> 8)
> > > > rx = (__bitrev8(x & 0xff) << 8) | __bitrev8(x >> 8)
> > > >
> > > > So in this case swap all 16 bits.
> > > >
> > > > Now, given I'd expected them to be reversed for the tx vs rx case.
> > > > E.g.
> > > > tx = cpu_to_be16(bitrev16(x))
> > > > As above.
> > > > For rx, le host
> > > > rx = bitrev16(be16_to_cpu(x))
> > > >    = __bitrev8((x >> 8) & 0xff) << 8) |  __bitrev8((((x & 0xff) << 8) >> 8)
> > > > same as above (if you swap the two terms I think.
> > > >
> > > > For be the be16_to_cpu is a noop again, so it's just bitrev16(x) as expected.
> > > >
> > > > Hence if I've understood this correctly you could reverse the terms so that
> > > > it was 'obvious' you were doing the opposite for the tx term vs the rx one
> > > > without making the slightest bit of difference....
> > > >
> > > > hmm. Might be worth doing simply to avoid questions.  
> > >
> > > Thank you for your feedback. I have tested the modifications based on your
> > > suggestions, taking the le system into account, and it appears that the code is
> > > functioning correctly. Before sending the new patch version, I would like to
> > > confirm if this aligns with your comments.  
> 
> > Yes. This looks good to me.  
> 
> I think the implementation is still incorrect. See below.
> 
> > > static int max14001_read(void *context, unsigned int reg_addr, unsigned int *data)
> > > {
> > >       struct max14001_state *st = context;
> > >       int ret;
> > >
> > >       struct spi_transfer xfers[] = {
> > >               {
> > >                       .tx_buf = &st->spi_tx_buffer,
> > >                       .len = sizeof(st->spi_tx_buffer),
> > >                       .cs_change = 1,
> > >               }, {
> > >                       .rx_buf = &st->spi_rx_buffer,
> > >                       .len = sizeof(st->spi_rx_buffer),
> > >               },
> > >       };  
> 
> > >       st->spi_tx_buffer = cpu_to_be16(bitrev16(FIELD_PREP(MAX14001_ADDR_MASK, reg_addr)));  
> 
> Here we got bits in CPU order, reversed them and converted to BE16.
> 
> > >       ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers));
> > >       if (ret)
> > >               return ret;  
> 
> > >       *data = cpu_to_be16(bitrev16(st->spi_rx_buffer));  
> 
> Here we take __be16 response, reverse them and convert to BE16?!
> This is weird. You should have be16_to_cpu() somewhere, not the opposite.
Good point - though functionally they end up the same (and the bitrev
is making mess of type markings anyway). It is more logical
to ensure the direction is reversed as you suggest.

> 
> > >       return 0;
> > > }  
> 
> Isn't, btw, the reinvented spi_...write_then_read() (or what is it
> called?) call?

I think the cs_change = 1 prevents using that.

Jonathan


> 
> > > static int max14001_write(void *context, unsigned int reg_addr, unsigned int data)
> > > {
> > >       struct max14001_state *st = context;
> > >
> > >       st->spi_tx_buffer = cpu_to_be16(bitrev16(
> > >                               FIELD_PREP(MAX14001_ADDR_MASK, reg_addr) |
> > >                               FIELD_PREP(MAX14001_SET_WRITE_BIT, 1) |
> > >                               FIELD_PREP(MAX14001_DATA_MASK, data)));
> > >
> > >       return spi_write(st->spi, &st->spi_tx_buffer, sizeof(st->spi_tx_buffer));
> > > }  
>
Andy Shevchenko July 5, 2023, 9:36 a.m. UTC | #6
On Wed, Jul 5, 2023 at 12:28 PM Jonathan Cameron
<Jonathan.Cameron@huawei.com> wrote:
> On Wed, 5 Jul 2023 11:53:17 +0300
> Andy Shevchenko <andy.shevchenko@gmail.com> wrote:
> > On Wed, Jul 5, 2023 at 10:55 AM Jonathan Cameron
> > <Jonathan.Cameron@huawei.com> wrote:
> > > > > From: Jonathan Cameron <Jonathan.Cameron@Huawei.com>
> > > > > Sent: Sunday, July 2, 2023 6:04 PM
> > > > > On Thu, 22 Jun 2023 22:32:27 +0800
> > > > > Kim Seer Paller <kimseer.paller@analog.com> wrote:

...

> > > > > > + /*
> > > > > > +  * Convert transmit buffer to big-endian format and reverse transmit
> > > > > > +  * buffer to align with the LSB-first input on SDI port.
> > > > > > +  */
> > > > > > + st->spi_tx_buffer =
> > > > > cpu_to_be16(bitrev16(FIELD_PREP(MAX14001_ADDR_MASK,
> > > > > > +                                                         reg_addr)));
> > > > > > +
> > > > > > + ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers));
> > > > > > + if (ret)
> > > > > > +         return ret;
> > > > > > +
> > > > > > + /*
> > > > > > +  * Align received data from the receive buffer, reversing and reordering
> > > > > > +  * it to match the expected MSB-first format.
> > > > > > +  */
> > > > > > + *data = (__force u16)(be16_to_cpu(bitrev16(st->spi_rx_buffer))) &
> > > > > > +
> > > > >     MAX14001_DATA_MASK;
> > > > > > +
> > > > > These sequences still confuse me a lot because I'd expect the values in tx
> > > > > to have the opposite operations applied to those for rx and that's not the
> > > > > case.
> > > > >
> > > > > Let's take a le system.
> > > > > tx = cpu_to_be16(bitrev16(x))
> > > > >    = cpu_to_be16((__bitrev8(x & 0xff) << 8) | __bitrev8(x >> 8));
> > > > >    = __bitrev8(x & 0xff) | (__bitrev8(x >> 8) << 8)
> > > > > or swap all the bits in each byte, but don't swap the bytes.
> > > > >
> > > > > rx = cpu_to_be16(bitrev16(x))
> > > > >    = be16_to_cpu(((__bitrev8(x & 0xff) << 8) | __bitrev8(x >> 8)_
> > > > >    = __bitrev8(x & 0xff) | __bitrev(x >> 8)
> > > > >
> > > > > also swap all the bits in each byte, but don't swap the bytes.
> > > > >
> > > > > So it is the reverse because the bytes swaps unwind themselves somewhat.
> > > > > For a be system cpu_to_be16 etc are noop.
> > > > > tx = (__bitrev8(x & 0xff) << 8) | __bitrev8(x >> 8)
> > > > > rx = (__bitrev8(x & 0xff) << 8) | __bitrev8(x >> 8)
> > > > >
> > > > > So in this case swap all 16 bits.
> > > > >
> > > > > Now, given I'd expected them to be reversed for the tx vs rx case.
> > > > > E.g.
> > > > > tx = cpu_to_be16(bitrev16(x))
> > > > > As above.
> > > > > For rx, le host
> > > > > rx = bitrev16(be16_to_cpu(x))
> > > > >    = __bitrev8((x >> 8) & 0xff) << 8) |  __bitrev8((((x & 0xff) << 8) >> 8)
> > > > > same as above (if you swap the two terms I think.
> > > > >
> > > > > For be the be16_to_cpu is a noop again, so it's just bitrev16(x) as expected.
> > > > >
> > > > > Hence if I've understood this correctly you could reverse the terms so that
> > > > > it was 'obvious' you were doing the opposite for the tx term vs the rx one
> > > > > without making the slightest bit of difference....
> > > > >
> > > > > hmm. Might be worth doing simply to avoid questions.
> > > >
> > > > Thank you for your feedback. I have tested the modifications based on your
> > > > suggestions, taking the le system into account, and it appears that the code is
> > > > functioning correctly. Before sending the new patch version, I would like to
> > > > confirm if this aligns with your comments.
> >
> > > Yes. This looks good to me.
> >
> > I think the implementation is still incorrect. See below.
> >
> > > > static int max14001_read(void *context, unsigned int reg_addr, unsigned int *data)
> > > > {
> > > >       struct max14001_state *st = context;
> > > >       int ret;
> > > >
> > > >       struct spi_transfer xfers[] = {
> > > >               {
> > > >                       .tx_buf = &st->spi_tx_buffer,
> > > >                       .len = sizeof(st->spi_tx_buffer),
> > > >                       .cs_change = 1,
> > > >               }, {
> > > >                       .rx_buf = &st->spi_rx_buffer,
> > > >                       .len = sizeof(st->spi_rx_buffer),
> > > >               },
> > > >       };
> >
> > > >       st->spi_tx_buffer = cpu_to_be16(bitrev16(FIELD_PREP(MAX14001_ADDR_MASK, reg_addr)));
> >
> > Here we got bits in CPU order, reversed them and converted to BE16.
> >
> > > >       ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers));
> > > >       if (ret)
> > > >               return ret;
> >
> > > >       *data = cpu_to_be16(bitrev16(st->spi_rx_buffer));
> >
> > Here we take __be16 response, reverse them and convert to BE16?!
> > This is weird. You should have be16_to_cpu() somewhere, not the opposite.
> Good point - though functionally they end up the same (and the bitrev
> is making mess of type markings anyway). It is more logical
> to ensure the direction is reversed as you suggest.

Also a question why we don't do that in reversed order.
Logically it sounds like bitrev16(be16_to_cpu()) should be.
Will it give the wrong results?

All in all this algo should be described in the comment in the code
(if not yet).

> > > >       return 0;
> > > > }
Jonathan Cameron July 6, 2023, 1:25 a.m. UTC | #7
On Wed, 5 Jul 2023 12:36:40 +0300
Andy Shevchenko <andy.shevchenko@gmail.com> wrote:

> On Wed, Jul 5, 2023 at 12:28 PM Jonathan Cameron
> <Jonathan.Cameron@huawei.com> wrote:
> > On Wed, 5 Jul 2023 11:53:17 +0300
> > Andy Shevchenko <andy.shevchenko@gmail.com> wrote:  
> > > On Wed, Jul 5, 2023 at 10:55 AM Jonathan Cameron
> > > <Jonathan.Cameron@huawei.com> wrote:  
> > > > > > From: Jonathan Cameron <Jonathan.Cameron@Huawei.com>
> > > > > > Sent: Sunday, July 2, 2023 6:04 PM
> > > > > > On Thu, 22 Jun 2023 22:32:27 +0800
> > > > > > Kim Seer Paller <kimseer.paller@analog.com> wrote:  
> 
> ...
> 
> > > > > > > + /*
> > > > > > > +  * Convert transmit buffer to big-endian format and reverse transmit
> > > > > > > +  * buffer to align with the LSB-first input on SDI port.
> > > > > > > +  */
> > > > > > > + st->spi_tx_buffer =  
> > > > > > cpu_to_be16(bitrev16(FIELD_PREP(MAX14001_ADDR_MASK,  
> > > > > > > +                                                         reg_addr)));
> > > > > > > +
> > > > > > > + ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers));
> > > > > > > + if (ret)
> > > > > > > +         return ret;
> > > > > > > +
> > > > > > > + /*
> > > > > > > +  * Align received data from the receive buffer, reversing and reordering
> > > > > > > +  * it to match the expected MSB-first format.
> > > > > > > +  */
> > > > > > > + *data = (__force u16)(be16_to_cpu(bitrev16(st->spi_rx_buffer))) &
> > > > > > > +  
> > > > > >     MAX14001_DATA_MASK;  
> > > > > > > +  
> > > > > > These sequences still confuse me a lot because I'd expect the values in tx
> > > > > > to have the opposite operations applied to those for rx and that's not the
> > > > > > case.
> > > > > >
> > > > > > Let's take a le system.
> > > > > > tx = cpu_to_be16(bitrev16(x))
> > > > > >    = cpu_to_be16((__bitrev8(x & 0xff) << 8) | __bitrev8(x >> 8));
> > > > > >    = __bitrev8(x & 0xff) | (__bitrev8(x >> 8) << 8)
> > > > > > or swap all the bits in each byte, but don't swap the bytes.
> > > > > >
> > > > > > rx = cpu_to_be16(bitrev16(x))
> > > > > >    = be16_to_cpu(((__bitrev8(x & 0xff) << 8) | __bitrev8(x >> 8)_
> > > > > >    = __bitrev8(x & 0xff) | __bitrev(x >> 8)
> > > > > >
> > > > > > also swap all the bits in each byte, but don't swap the bytes.
> > > > > >
> > > > > > So it is the reverse because the bytes swaps unwind themselves somewhat.
> > > > > > For a be system cpu_to_be16 etc are noop.
> > > > > > tx = (__bitrev8(x & 0xff) << 8) | __bitrev8(x >> 8)
> > > > > > rx = (__bitrev8(x & 0xff) << 8) | __bitrev8(x >> 8)
> > > > > >
> > > > > > So in this case swap all 16 bits.
> > > > > >
> > > > > > Now, given I'd expected them to be reversed for the tx vs rx case.
> > > > > > E.g.
> > > > > > tx = cpu_to_be16(bitrev16(x))
> > > > > > As above.
> > > > > > For rx, le host
> > > > > > rx = bitrev16(be16_to_cpu(x))
> > > > > >    = __bitrev8((x >> 8) & 0xff) << 8) |  __bitrev8((((x & 0xff) << 8) >> 8)
> > > > > > same as above (if you swap the two terms I think.
> > > > > >
> > > > > > For be the be16_to_cpu is a noop again, so it's just bitrev16(x) as expected.
> > > > > >
> > > > > > Hence if I've understood this correctly you could reverse the terms so that
> > > > > > it was 'obvious' you were doing the opposite for the tx term vs the rx one
> > > > > > without making the slightest bit of difference....
> > > > > >
> > > > > > hmm. Might be worth doing simply to avoid questions.  
> > > > >
> > > > > Thank you for your feedback. I have tested the modifications based on your
> > > > > suggestions, taking the le system into account, and it appears that the code is
> > > > > functioning correctly. Before sending the new patch version, I would like to
> > > > > confirm if this aligns with your comments.  
> > >  
> > > > Yes. This looks good to me.  
> > >
> > > I think the implementation is still incorrect. See below.
> > >  
> > > > > static int max14001_read(void *context, unsigned int reg_addr, unsigned int *data)
> > > > > {
> > > > >       struct max14001_state *st = context;
> > > > >       int ret;
> > > > >
> > > > >       struct spi_transfer xfers[] = {
> > > > >               {
> > > > >                       .tx_buf = &st->spi_tx_buffer,
> > > > >                       .len = sizeof(st->spi_tx_buffer),
> > > > >                       .cs_change = 1,
> > > > >               }, {
> > > > >                       .rx_buf = &st->spi_rx_buffer,
> > > > >                       .len = sizeof(st->spi_rx_buffer),
> > > > >               },
> > > > >       };  
> > >  
> > > > >       st->spi_tx_buffer = cpu_to_be16(bitrev16(FIELD_PREP(MAX14001_ADDR_MASK, reg_addr)));  
> > >
> > > Here we got bits in CPU order, reversed them and converted to BE16.
> > >  
> > > > >       ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers));
> > > > >       if (ret)
> > > > >               return ret;  
> > >  
> > > > >       *data = cpu_to_be16(bitrev16(st->spi_rx_buffer));  
> > >
> > > Here we take __be16 response, reverse them and convert to BE16?!
> > > This is weird. You should have be16_to_cpu() somewhere, not the opposite.  
> > Good point - though functionally they end up the same (and the bitrev
> > is making mess of type markings anyway). It is more logical
> > to ensure the direction is reversed as you suggest.  
> 
> Also a question why we don't do that in reversed order.
> Logically it sounds like bitrev16(be16_to_cpu()) should be.
> Will it give the wrong results?
Shouldn't make any difference as the two operations commute.
I'd missed this.  You are right that the other order makes more
sense.

Jonathan

> 
> All in all this algo should be described in the comment in the code
> (if not yet).
> 
> > > > >       return 0;
> > > > > }  
>
diff mbox series

Patch

diff --git a/Documentation/devicetree/bindings/iio/adc/adi,max14001.yaml b/Documentation/devicetree/bindings/iio/adc/adi,max14001.yaml
new file mode 100644
index 000000000000..9d03c611fca3
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/adi,max14001.yaml
@@ -0,0 +1,54 @@ 
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright 2023 Analog Devices Inc.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/adc/adi,max14001.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices MAX14001 ADC
+
+maintainers:
+  - Kim Seer Paller <kimseer.paller@analog.com>
+
+description: |
+    Single channel 10 bit ADC with SPI interface. Datasheet
+    can be found here:
+      https://www.analog.com/media/en/technical-documentation/data-sheets/MAX14001-MAX14002.pdf
+
+properties:
+  compatible:
+    enum:
+      - adi,max14001
+
+  reg:
+    maxItems: 1
+
+  spi-max-frequency:
+    maximum: 5000000
+
+  vref-supply:
+    description: Voltage reference to establish input scaling.
+
+required:
+  - compatible
+  - reg
+
+allOf:
+  - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    spi {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        adc@0 {
+            compatible = "adi,max14001";
+            reg = <0>;
+            spi-max-frequency = <5000000>;
+            vref-supply = <&vref_reg>;
+        };
+    };
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index f794002a192e..dcea2c31f920 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -12670,6 +12670,13 @@  S:	Maintained
 F:	Documentation/devicetree/bindings/sound/max9860.txt
 F:	sound/soc/codecs/max9860.*
 
+MAX14001 IIO ADC DRIVER
+M:	Kim Seer Paller <kimseer.paller@analog.com>
+L:	linux-iio@vger.kernel.org
+S:	Supported
+W:	https://ez.analog.com/linux-software-drivers
+F:	Documentation/devicetree/bindings/iio/adc/adi,max14001.yaml
+
 MAXBOTIX ULTRASONIC RANGER IIO DRIVER
 M:	Andreas Klinger <ak@it-klinger.de>
 L:	linux-iio@vger.kernel.org