Hi Antoniu, A first, not in depth, review from my side... On Thu, 2025-02-20 at 15:54 +0200, Antoniu Miclaus wrote: > Add support for AD4080 high-speed, low noise, low distortion, > 20-bit, Easy Drive, successive approximation register (SAR) > analog-to-digital converter (ADC). > > Signed-off-by: Antoniu Miclaus <antoniu.miclaus@xxxxxxxxxx> > --- > drivers/iio/adc/Kconfig | 15 + > drivers/iio/adc/Makefile | 1 + > drivers/iio/adc/ad4080.c | 768 +++++++++++++++++++++++++++++++++++++++ > 3 files changed, 784 insertions(+) > create mode 100644 drivers/iio/adc/ad4080.c > > diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig > index 27413516216c..b198a93c10b7 100644 > --- a/drivers/iio/adc/Kconfig > +++ b/drivers/iio/adc/Kconfig > @@ -47,6 +47,21 @@ config AD4030 > To compile this driver as a module, choose M here: the module will > be > called ad4030. > > +config AD4080 > + tristate "Analog Devices AD4080 high speed ADC" > + depends on SPI > + select REGMAP_SPI > + select IIO_BACKEND > + help > + Say yes here to build support for Analog Devices AD4080 > + high speed, low noise, low distortion, 20-bit, Easy Drive, > + successive approximation register (SAR) analog-to-digital > + converter (ADC). > + > + To compile this driver as a module, choose M here: the module will > be > + called ad4080. > + > + > config AD4130 > tristate "Analog Device AD4130 ADC Driver" > depends on SPI > diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile > index 9f26d5eca822..e6efed5b4e7a 100644 > --- a/drivers/iio/adc/Makefile > +++ b/drivers/iio/adc/Makefile > @@ -8,6 +8,7 @@ obj-$(CONFIG_AB8500_GPADC) += ab8500-gpadc.o > obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o > obj-$(CONFIG_AD4000) += ad4000.o > obj-$(CONFIG_AD4030) += ad4030.o > +obj-$(CONFIG_AD4080) += ad4080.o > obj-$(CONFIG_AD4130) += ad4130.o > obj-$(CONFIG_AD4695) += ad4695.o > obj-$(CONFIG_AD4851) += ad4851.o > diff --git a/drivers/iio/adc/ad4080.c b/drivers/iio/adc/ad4080.c > new file mode 100644 > index 000000000000..71c443965e10 > --- /dev/null > +++ b/drivers/iio/adc/ad4080.c > @@ -0,0 +1,768 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +/* > + * Analog Devices AD4080 SPI ADC driver > + * > + * Copyright 2025 Analog Devices Inc. > + */ ... > > +static int ad4080_write_raw(struct iio_dev *indio_dev, > + struct iio_chan_spec const *chan, > + int val, int val2, long mask) > +{ > + struct ad4080_state *st = iio_priv(indio_dev); > + unsigned long s_clk; > + int dec_rate = 1; > + > + switch (mask) { > + case IIO_CHAN_INFO_SCALE: > + return -EINVAL; > + case IIO_CHAN_INFO_SAMP_FREQ: > + s_clk = clk_round_rate(st->clk, val); > + > + if (st->filter_enabled) { > + if (st->filter_mode == SINC_5_COMP) > + dec_rate = ad4080_dec_rate_value[st- > >dec_rate] * 2; > + else > + dec_rate = ad4080_dec_rate_value[st- > >dec_rate]; > + } > + > + s_clk *= dec_rate; > + > + if (s_clk < AD4080_MIN_SAMP_FREQ) > + s_clk = AD4080_MIN_SAMP_FREQ; > + if (s_clk > AD4080_MAX_SAMP_FREQ) > + s_clk = AD4080_MAX_SAMP_FREQ; > + > + return clk_set_rate(st->clk, s_clk); It seems to me that we could skip the dec_rate attribute. Given the available values we have, can't we compute the available sampling frequencies during .probe() after getting our ref clock? > + default: > + return -EINVAL; > + } > + > + return 0; > +} > + > +static ssize_t ad4080_lvds_sync_write(struct iio_dev *indio_dev, > + uintptr_t private, > + const struct iio_chan_spec *chan, > + const char *buf, size_t len) > +{ > + struct ad4080_state *st = iio_priv(indio_dev); > + unsigned int timeout = 100; > + bool sync_en; > + int ret; > + > + guard(mutex)(&st->lock); > + if (st->num_lanes == 1) > + ret = regmap_write(st->regmap, > AD4080_REG_ADC_DATA_INTF_CONFIG_A, > + AD4080_RESERVED_CONFIG_A_MSK | > + AD4080_INTF_CHK_EN_MSK); > + else > + ret = regmap_write(st->regmap, > AD4080_REG_ADC_DATA_INTF_CONFIG_A, > + AD4080_RESERVED_CONFIG_A_MSK | > + AD4080_INTF_CHK_EN_MSK | > + AD4080_SPI_LVDS_LANES_MSK); > + if (ret) > + return ret; > + > + ret = iio_backend_self_sync_enable(st->back); > + if (ret) > + return ret; > + > + ret = iio_backend_num_lanes_set(st->back, st->num_lanes); > + if (ret) > + return ret; The number of lanes is a DT property so it seems to me that we can do the above only once during probe. Otherwise I would expect a comment on why we need to do this again... > + > + ret = iio_backend_bitslip_enable(st->back); > + if (ret) > + return ret; AFAIU, bit slip seems to be something very specific to AMD/Xilinx isn't it? It also looks like this is mostly about adjusting the alignment of incoming data at the interface level for data integrity. So we could maybe rename the API for something more generic like iio_backend_data_alignment_enable()? I'm open for suggestions here :) > + > + do { > + ret = iio_backend_sync_status_get(st->back, &sync_en); > + if (ret) > + return ret; Since this is about waiting on some alignment/synchronization process to complete, we could also think on a better name and API for this. I think we could pass a timeout parameter and do the waiting (with some regmap polling) in the backend returning 0 on success. Thoughts? > + > + if (!sync_en) > + dev_info(&st->spi->dev, "Not Locked: Running Bit > Slip\n"); > + else > + break; > + } while (--timeout); > Now comes my question about this process. This looks like some kind of interface calibration or am I completely wrong? I wonder if this is something that really needs to be a control that userspace can randomly use? Or is this something we should only do once during probe? Or every time before buffering? Or everytime we change the sampling frequency? Gut feeling is that we should do this after changing the sampling frequency but I can be totally wrong. Other thing that I'm confused about is that during probe we do iio_backend_self_sync_enable() and we can start buffering without running the lvds_sync code. My point is that after running lvds_sync we are left with iio_backend_bitslip_enable() so I'm wondering how this all should work? Should bitslip be always enabled or only for this process? The Docs are also a bit confusing: BITSLIP_ENABLE - Enables the sync process. SELF_SYNC - Controls if the data capture synchronization is done through CNV signal or bit-slip.