From 12509f00f3c86db5af0f7004c53ceaa4091cfcb3 Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Wed, 14 Jan 2026 06:27:03 -0300 Subject: [PATCH 01/46] units: add conversion macros for percentage related units Add macros to convert between ratio and percentage related units, including percent (1/100), permille (1/1,000), permyriad (1/10,000, also equivalent to one Basis point) and per cent mille (1/100,000). Those are Used for precise fractional calculations in engineering, finance, and measurement applications. Signed-off-by: Jonathan Santos Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- include/linux/units.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/include/linux/units.h b/include/linux/units.h index 00e15de33eca2f..3471c5a38dcf4e 100644 --- a/include/linux/units.h +++ b/include/linux/units.h @@ -21,6 +21,25 @@ #define PICO 1000000000000ULL #define FEMTO 1000000000000000ULL +/* + * Percentage and related scaling units + * + * These macros define scaling factors used to convert between ratio and + * percentage-based representations with different decimal resolutions. + * They are used for precise fractional calculations in engineering, finance, + * and measurement applications. + * + * Examples: + * 1% = 0.01 = 1 / PERCENT + * 0.1% = 0.001 = 1 / PERMILLE + * 0.01% = 0.0001 = 1 / PERMYRIAD (1 basis point) + * 0.001% = 0.00001 = 1 / PERCENTMILLE + */ +#define PERCENT 100 +#define PERMILLE 1000 +#define PERMYRIAD 10000 +#define PERCENTMILLE 100000 + #define NANOHZ_PER_HZ 1000000000UL #define MICROHZ_PER_HZ 1000000UL #define MILLIHZ_PER_HZ 1000UL From 9c9fc5c5af0df8c14ee6c53bf4852189911fef60 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 8 Nov 2024 16:07:37 +0200 Subject: [PATCH 02/46] regmap: provide regmap_assign_bits() Add another bits helper to regmap API: this one sets given bits if value is true and clears them if it's false. Suggested-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski Signed-off-by: Tomi Valkeinen Link: https://patch.msgid.link/20241108-assign-bits-v1-1-382790562d99@ideasonboard.com Signed-off-by: Mark Brown --- include/linux/regmap.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/include/linux/regmap.h b/include/linux/regmap.h index f9ccad32fc5cba..23965991920343 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -1328,6 +1328,15 @@ static inline int regmap_clear_bits(struct regmap *map, return regmap_update_bits_base(map, reg, bits, 0, NULL, false, false); } +static inline int regmap_assign_bits(struct regmap *map, unsigned int reg, + unsigned int bits, bool value) +{ + if (value) + return regmap_set_bits(map, reg, bits); + else + return regmap_clear_bits(map, reg, bits); +} + int regmap_test_bits(struct regmap *map, unsigned int reg, unsigned int bits); /** @@ -1796,6 +1805,13 @@ static inline int regmap_clear_bits(struct regmap *map, return -EINVAL; } +static inline int regmap_assign_bits(struct regmap *map, unsigned int reg, + unsigned int bits, bool value) +{ + WARN_ONCE(1, "regmap API is disabled"); + return -EINVAL; +} + static inline int regmap_test_bits(struct regmap *map, unsigned int reg, unsigned int bits) { From 27e8f2743a8286c5c24345b16f75e31766c0424e Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 13 Apr 2025 11:34:28 +0100 Subject: [PATCH 03/46] iio: introduced iio_push_to_buffers_with_ts() that takes a data_total_len argument. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check that data_total_len argument against iio_dev->scan_bytes. The size needs to be at least as big as the scan. It can be larger, which is typical if only part of fixed sized storage is used due to a subset of channels being enabled. Reviewed-by: Nuno Sá Reviewed-by: David Lechner Link: https://patch.msgid.link/20250413103443.2420727-6-jic23@kernel.org Signed-off-by: Jonathan Cameron --- include/linux/iio/buffer.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/linux/iio/buffer.h b/include/linux/iio/buffer.h index 418b1307d3f2cb..62748a1ba909c2 100644 --- a/include/linux/iio/buffer.h +++ b/include/linux/iio/buffer.h @@ -45,6 +45,18 @@ static inline int iio_push_to_buffers_with_timestamp(struct iio_dev *indio_dev, return iio_push_to_buffers(indio_dev, data); } +static inline int iio_push_to_buffers_with_ts(struct iio_dev *indio_dev, + void *data, size_t data_total_len, + s64 timestamp) +{ + if (unlikely(data_total_len < indio_dev->scan_bytes)) { + dev_err(&indio_dev->dev, "Undersized storage pushed to buffer\n"); + return -ENOSPC; + } + + return iio_push_to_buffers_with_timestamp(indio_dev, data, timestamp); +} + int iio_push_to_buffers_with_ts_unaligned(struct iio_dev *indio_dev, const void *data, size_t data_sz, int64_t timestamp); From 72188049e982f226fd7c478e46db8acfb833f369 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 17 Apr 2025 18:24:46 +0300 Subject: [PATCH 04/46] spi: Add spi_bpw_to_bytes() helper and use it This helper converts the given bits per word to bytes. The result will always be power-of-two, e.g., =============== ================= Input (in bits) Output (in bytes) =============== ================= 5 1 9 2 21 4 37 8 =============== ================= It will return 0 for the 0 input. There are a couple of cases in SPI that are using the same approach and at least one more (in IIO) would benefit of it. Add a helper for everyone. Signed-off-by: Andy Shevchenko Reviewed-by: David Lechner Link: https://patch.msgid.link/20250417152529.490582-2-andriy.shevchenko@linux.intel.com Acked-by: Mukesh Kumar Savaliya Signed-off-by: Mark Brown --- drivers/spi/spi.c | 2 +- include/linux/spi/spi.h | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index bb551ab7088ca1..fa0f5f23cb5d68 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -3943,7 +3943,7 @@ int spi_split_transfers_maxwords(struct spi_controller *ctlr, size_t maxsize; int ret; - maxsize = maxwords * roundup_pow_of_two(BITS_TO_BYTES(xfer->bits_per_word)); + maxsize = maxwords * spi_bpw_to_bytes(xfer->bits_per_word); if (xfer->len > maxsize) { ret = __spi_split_transfer_maxsize(ctlr, msg, &xfer, maxsize); diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index c27a11d33a0f0f..f6a7516ad4ad0a 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -1388,6 +1388,32 @@ static inline bool spi_is_bpw_supported(struct spi_device *spi, u32 bpw) return false; } +/** + * spi_bpw_to_bytes - Covert bits per word to bytes + * @bpw: Bits per word + * + * This function converts the given @bpw to bytes. The result is always + * power-of-two, e.g., + * + * =============== ================= + * Input (in bits) Output (in bytes) + * =============== ================= + * 5 1 + * 9 2 + * 21 4 + * 37 8 + * =============== ================= + * + * It will return 0 for the 0 input. + * + * Returns: + * Bytes for the given @bpw. + */ +static inline u32 spi_bpw_to_bytes(u32 bpw) +{ + return roundup_pow_of_two(BITS_TO_BYTES(bpw)); +} + /** * spi_controller_xfer_timeout - Compute a suitable timeout value * @ctlr: SPI device From aef410e2422e9ff2d3d54317afeecb6ec9ec8f19 Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Wed, 11 Mar 2026 15:46:06 -0300 Subject: [PATCH 05/46] iio: adc: ad7768-1: Backport driver from kernel 6.12 Replace the current implementation with the version on kernel 6.12 to enable a clean backport of the rest of the features from upstream. This results on the removal of GPIO reset, SPI offload support, GPIO controller support and regulator provider support. Signed-off-by: Jonathan Santos --- drivers/iio/adc/Kconfig | 2 - drivers/iio/adc/ad7768-1.c | 426 ++++++------------------------------- 2 files changed, 67 insertions(+), 361 deletions(-) diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index cae86f7837e06a..76a60d5894424f 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -379,8 +379,6 @@ config AD7768_1 select IIO_BUFFER select IIO_TRIGGER select IIO_TRIGGERED_BUFFER - select IIO_BUFFER_DMA - select IIO_BUFFER_DMAENGINE help Say yes here to build support for Analog Devices AD7768-1 SPI simultaneously sampling sigma-delta analog to digital converter (ADC). diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index 0784a952fd72fa..113703fb724544 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -8,23 +8,15 @@ #include #include #include -#include -#include #include -#include -#include -#include #include #include #include #include #include #include -#include #include -#include -#include #include #include #include @@ -84,19 +76,6 @@ #define AD7768_CONV_MODE_MSK GENMASK(2, 0) #define AD7768_CONV_MODE(x) FIELD_PREP(AD7768_CONV_MODE_MSK, x) -/* AD7768_REG_GPIO_CONTROL */ -#define AD7768_GPIO_CONTROL_MSK GENMASK(3, 0) -#define AD7768_GPIO_UNIVERSAL_EN BIT(7) - -/* AD7768_REG_GPIO_WRITE */ -#define AD7768_GPIO_WRITE_MSK GENMASK(3, 0) - -/* AD7768_REG_GPIO_READ */ -#define AD7768_GPIO_READ_MSK GENMASK(3, 0) - -#define AD7768_GPIO_INPUT(x) 0x00 -#define AD7768_GPIO_OUTPUT(x) BIT(x) - #define AD7768_RD_FLAG_MSK(x) (BIT(6) | ((x) & 0x3F)) #define AD7768_WR_FLAG_MSK(x) ((x) & 0x3F) @@ -139,18 +118,9 @@ struct ad7768_clk_configuration { enum ad7768_pwrmode pwrmode; }; -static const char * const ad7768_vcm_modes[] = { - "(AVDD1-AVSS)/2", - "2V5", - "2V05", - "1V9", - "1V65", - "1V1", - "0V9", - "OFF", -}; - static const struct ad7768_clk_configuration ad7768_clk_config[] = { + { AD7768_MCLK_DIV_2, AD7768_DEC_RATE_8, 16, AD7768_FAST_MODE }, + { AD7768_MCLK_DIV_2, AD7768_DEC_RATE_16, 32, AD7768_FAST_MODE }, { AD7768_MCLK_DIV_2, AD7768_DEC_RATE_32, 64, AD7768_FAST_MODE }, { AD7768_MCLK_DIV_2, AD7768_DEC_RATE_64, 128, AD7768_FAST_MODE }, { AD7768_MCLK_DIV_2, AD7768_DEC_RATE_128, 256, AD7768_FAST_MODE }, @@ -162,42 +132,21 @@ static const struct ad7768_clk_configuration ad7768_clk_config[] = { { AD7768_MCLK_DIV_16, AD7768_DEC_RATE_1024, 16384, AD7768_ECO_MODE }, }; -static int ad7768_get_vcm(struct iio_dev *dev, const struct iio_chan_spec *chan); -static int ad7768_set_vcm(struct iio_dev *dev, const struct iio_chan_spec *chan, - unsigned int mode); - -static const struct iio_enum ad7768_vcm_mode_enum = { - .items = ad7768_vcm_modes, - .num_items = ARRAY_SIZE(ad7768_vcm_modes), - .set = ad7768_set_vcm, - .get = ad7768_get_vcm, -}; - -static struct iio_chan_spec_ext_info ad7768_ext_info[] = { - IIO_ENUM("common_mode_voltage", - IIO_SHARED_BY_ALL, - &ad7768_vcm_mode_enum), - IIO_ENUM_AVAILABLE("common_mode_voltage", - IIO_SHARED_BY_ALL, - &ad7768_vcm_mode_enum), - { }, -}; - static const struct iio_chan_spec ad7768_channels[] = { { .type = IIO_VOLTAGE, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), - .ext_info = ad7768_ext_info, .indexed = 1, .channel = 0, .scan_index = 0, .scan_type = { - .sign = 's', + .sign = 'u', .realbits = 24, .storagebits = 32, .shift = 8, + .endianness = IIO_BE, }, }, }; @@ -207,93 +156,61 @@ struct ad7768_state { struct regulator *vref; struct mutex lock; struct clk *mclk; - struct gpio_chip gpiochip; - unsigned int gpio_avail_map; unsigned int mclk_freq; unsigned int samp_freq; - unsigned int common_mode_voltage; struct completion completion; struct iio_trigger *trig; struct gpio_desc *gpio_sync_in; const char *labels[ARRAY_SIZE(ad7768_channels)]; - struct gpio_desc *gpio_reset; - bool spi_is_dma_mapped; - int irq; /* * DMA (thus cache coherency maintenance) may require the * transfer buffers to live in their own cache lines. */ union { - unsigned char buf[6]; - __be32 word; struct { __be32 chan; s64 timestamp; } scan; + __be32 d32; + u8 d8[2]; } data __aligned(IIO_DMA_MINALIGN); }; static int ad7768_spi_reg_read(struct ad7768_state *st, unsigned int addr, - unsigned int *data, unsigned int len) + unsigned int len) { - struct spi_transfer xfer = { - .rx_buf = st->data.buf, - .len = len + 1, - .bits_per_word = (len == 3 ? 32 : 16), - }; - unsigned char tx_data[4]; + unsigned int shift; int ret; - tx_data[0] = AD7768_RD_FLAG_MSK(addr); - xfer.tx_buf = tx_data; - ret = spi_sync_transfer(st->spi, &xfer, 1); + shift = 32 - (8 * len); + st->data.d8[0] = AD7768_RD_FLAG_MSK(addr); + + ret = spi_write_then_read(st->spi, st->data.d8, 1, + &st->data.d32, len); if (ret < 0) return ret; - *data = (len == 1 ? st->data.buf[0] : st->data.word); - return ret; + return (be32_to_cpu(st->data.d32) >> shift); } static int ad7768_spi_reg_write(struct ad7768_state *st, unsigned int addr, unsigned int val) { - struct spi_transfer xfer = { - .rx_buf = st->data.buf, - .len = 2, - .bits_per_word = 16, - }; - unsigned char tx_data[2]; - - tx_data[0] = AD7768_WR_FLAG_MSK(addr); - tx_data[1] = val & 0xFF; - xfer.tx_buf = tx_data; - return spi_sync_transfer(st->spi, &xfer, 1); -} - -static int ad7768_spi_reg_write_masked(struct ad7768_state *st, - unsigned int addr, - unsigned int mask, - unsigned int val) -{ - unsigned int reg_val; - int ret; + st->data.d8[0] = AD7768_WR_FLAG_MSK(addr); + st->data.d8[1] = val & 0xFF; - ret = ad7768_spi_reg_read(st, addr, ®_val, 1); - if (ret < 0) - return ret; - - return ad7768_spi_reg_write(st, addr, (reg_val & ~mask) | val); + return spi_write(st->spi, st->data.d8, 2); } static int ad7768_set_mode(struct ad7768_state *st, enum ad7768_conv_mode mode) { - int ret, regval; + int regval; - ret = ad7768_spi_reg_read(st, AD7768_REG_CONVERSION, ®val, 1); - if (ret < 0) - return ret; + regval = ad7768_spi_reg_read(st, AD7768_REG_CONVERSION, 1); + if (regval < 0) + return regval; regval &= ~AD7768_CONV_MODE_MSK; regval |= AD7768_CONV_MODE(mode); @@ -306,23 +223,20 @@ static int ad7768_scan_direct(struct iio_dev *indio_dev) struct ad7768_state *st = iio_priv(indio_dev); int readval, ret; - if (!st->spi_is_dma_mapped) - reinit_completion(&st->completion); + reinit_completion(&st->completion); ret = ad7768_set_mode(st, AD7768_ONE_SHOT); if (ret < 0) return ret; - if (!st->spi_is_dma_mapped) { - ret = wait_for_completion_timeout(&st->completion, + ret = wait_for_completion_timeout(&st->completion, msecs_to_jiffies(1000)); - if (!ret) - return -ETIMEDOUT; - } + if (!ret) + return -ETIMEDOUT; - ret = ad7768_spi_reg_read(st, AD7768_REG_ADC_DATA, &readval, 3); - if (ret < 0) - return ret; + readval = ad7768_spi_reg_read(st, AD7768_REG_ADC_DATA, 3); + if (readval < 0) + return readval; /* * Any SPI configuration of the AD7768-1 can only be * performed in continuous conversion mode. @@ -344,9 +258,11 @@ static int ad7768_reg_access(struct iio_dev *indio_dev, mutex_lock(&st->lock); if (readval) { - ret = ad7768_spi_reg_read(st, reg, readval, 1); + ret = ad7768_spi_reg_read(st, reg, 1); if (ret < 0) goto err_unlock; + *readval = ret; + ret = 0; } else { ret = ad7768_spi_reg_write(st, reg, writeval); } @@ -378,122 +294,6 @@ static int ad7768_set_dig_fil(struct ad7768_state *st, return 0; } -static int ad7768_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) -{ - struct ad7768_state *st = gpiochip_get_data(chip); - int ret; - - mutex_lock(&st->lock); - ret = ad7768_spi_reg_write_masked(st, - AD7768_REG_GPIO_CONTROL, - BIT(offset), - AD7768_GPIO_INPUT(offset)); - mutex_unlock(&st->lock); - - return ret; -} - -static int ad7768_gpio_direction_output(struct gpio_chip *chip, - unsigned int offset, int value) -{ - struct ad7768_state *st = gpiochip_get_data(chip); - int ret; - - mutex_lock(&st->lock); - ret = ad7768_spi_reg_write_masked(st, - AD7768_REG_GPIO_CONTROL, - BIT(offset), - AD7768_GPIO_OUTPUT(offset)); - mutex_unlock(&st->lock); - - return ret; -} - -static int ad7768_gpio_get(struct gpio_chip *chip, unsigned int offset) -{ - struct ad7768_state *st = gpiochip_get_data(chip); - unsigned int val; - int ret; - - mutex_lock(&st->lock); - ret = ad7768_spi_reg_read(st, AD7768_REG_GPIO_CONTROL, &val, 1); - if (ret < 0) - goto gpio_get_err; - - if (val & BIT(offset)) - ret = ad7768_spi_reg_read(st, AD7768_REG_GPIO_WRITE, &val, 1); - else - ret = ad7768_spi_reg_read(st, AD7768_REG_GPIO_READ, &val, 1); - if (ret < 0) - goto gpio_get_err; - - ret = !!(val & BIT(offset)); - -gpio_get_err: - mutex_unlock(&st->lock); - - return ret; -} - -static void ad7768_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) -{ - struct ad7768_state *st = gpiochip_get_data(chip); - unsigned int val; - int ret; - - mutex_lock(&st->lock); - ret = ad7768_spi_reg_read(st, AD7768_REG_GPIO_CONTROL, &val, 1); - if (ret < 0) - goto gpio_set_err; - - if (val & BIT(offset)) - ad7768_spi_reg_write_masked(st, - AD7768_REG_GPIO_WRITE, - BIT(offset), - (value << offset)); - -gpio_set_err: - mutex_unlock(&st->lock); -} - -static int ad7768_gpio_request(struct gpio_chip *chip, unsigned int offset) -{ - struct ad7768_state *st = gpiochip_get_data(chip); - - if (!(st->gpio_avail_map & BIT(offset))) - return -ENODEV; - - st->gpio_avail_map &= ~BIT(offset); - - return 0; -} - -static int ad7768_gpio_init(struct ad7768_state *st) -{ - int ret; - - ret = ad7768_spi_reg_write(st, - AD7768_REG_GPIO_CONTROL, - AD7768_GPIO_UNIVERSAL_EN); - if (ret < 0) - return ret; - - st->gpio_avail_map = AD7768_GPIO_CONTROL_MSK; - st->gpiochip.label = "ad7768_1_gpios"; - st->gpiochip.base = -1; - st->gpiochip.ngpio = 4; - st->gpiochip.parent = &st->spi->dev; - st->gpiochip.can_sleep = true; - st->gpiochip.direction_input = ad7768_gpio_direction_input; - st->gpiochip.direction_output = ad7768_gpio_direction_output; - st->gpiochip.get = ad7768_gpio_get; - st->gpiochip.set = ad7768_gpio_set; - st->gpiochip.request = ad7768_gpio_request; - st->gpiochip.owner = THIS_MODULE; - - return gpiochip_add_data(&st->gpiochip, st); -} - static int ad7768_set_freq(struct ad7768_state *st, unsigned int freq) { @@ -534,28 +334,6 @@ static int ad7768_set_freq(struct ad7768_state *st, return 0; } -static int ad7768_get_vcm(struct iio_dev *dev, const struct iio_chan_spec *chan) -{ - struct ad7768_state *st = iio_priv(dev); - - return st->common_mode_voltage; -} - -static int ad7768_set_vcm(struct iio_dev *dev, - const struct iio_chan_spec *chan, - unsigned int mode) -{ - int ret; - struct ad7768_state *st = iio_priv(dev); - - ret = ad7768_spi_reg_write(st, AD7768_REG_ANALOG2, mode); - - if (ret == 0) - st->common_mode_voltage = mode; - - return ret; -} - static ssize_t ad7768_sampling_freq_avail(struct device *dev, struct device_attribute *attr, char *buf) @@ -593,7 +371,7 @@ static int ad7768_read_raw(struct iio_dev *indio_dev, ret = ad7768_scan_direct(indio_dev); if (ret >= 0) - *val = sign_extend32(ret, chan->scan_type.realbits - 1); + *val = ret; iio_device_release_direct_mode(indio_dev); if (ret < 0) @@ -663,18 +441,6 @@ static int ad7768_setup(struct ad7768_state *st) { int ret; - st->gpio_reset = devm_gpiod_get_optional(&st->spi->dev, "reset", - GPIOD_OUT_LOW); - if (IS_ERR(st->gpio_reset)) - return PTR_ERR(st->gpio_reset); - - if (st->gpio_reset) { - gpiod_direction_output(st->gpio_reset, 1); - usleep_range(10, 15); - gpiod_direction_output(st->gpio_reset, 0); - usleep_range(10, 15); - } - /* * Two writes to the SPI_RESET[1:0] bits are required to initiate * a software reset. The bits must first be set to 11, and then @@ -694,15 +460,8 @@ static int ad7768_setup(struct ad7768_state *st) if (IS_ERR(st->gpio_sync_in)) return PTR_ERR(st->gpio_sync_in); - ret = ad7768_gpio_init(st); - if (ret < 0) - return ret; - - /** - * Set the default sampling frequency to 256 kSPS for hardware buffer, - * or 32 kSPS for triggered buffer - */ - return ad7768_set_freq(st, st->spi_is_dma_mapped ? 256000 : 32000); + /* Set the default sampling frequency to 32000 kSPS */ + return ad7768_set_freq(st, 32000); } static irqreturn_t ad7768_trigger_handler(int irq, void *p) @@ -744,55 +503,24 @@ static irqreturn_t ad7768_interrupt(int irq, void *dev_id) static int ad7768_buffer_postenable(struct iio_dev *indio_dev) { struct ad7768_state *st = iio_priv(indio_dev); - struct spi_transfer xfer = { - .len = 1, - .bits_per_word = 32 - }; - unsigned int rx_data[2]; - unsigned int tx_data[2]; - struct spi_message msg; - int ret; /* - * Write a 1 to the LSB of the INTERFACE_FORMAT register to enter - * continuous read mode. Subsequent data reads do not require an - * initial 8-bit write to query the ADC_DATA register. - */ - ret = ad7768_spi_reg_write(st, AD7768_REG_INTERFACE_FORMAT, 0x01); - if (ret) - return ret; - - if (st->spi_is_dma_mapped) { - spi_bus_lock(st->spi->controller); - - tx_data[0] = AD7768_RD_FLAG_MSK(AD7768_REG_ADC_DATA) << 24; - xfer.tx_buf = tx_data; - xfer.rx_buf = rx_data; - spi_message_init_with_transfers(&msg, &xfer, 1); - ret = legacy_spi_engine_offload_load_msg(st->spi, &msg); - if (ret < 0) - return ret; - legacy_spi_engine_offload_enable(st->spi, true); - } - - return ret; + * Write a 1 to the LSB of the INTERFACE_FORMAT register to enter + * continuous read mode. Subsequent data reads do not require an + * initial 8-bit write to query the ADC_DATA register. + */ + return ad7768_spi_reg_write(st, AD7768_REG_INTERFACE_FORMAT, 0x01); } static int ad7768_buffer_predisable(struct iio_dev *indio_dev) { struct ad7768_state *st = iio_priv(indio_dev); - unsigned int regval; - - if (st->spi_is_dma_mapped) { - legacy_spi_engine_offload_enable(st->spi, false); - spi_bus_unlock(st->spi->controller); - } /* * To exit continuous read mode, perform a single read of the ADC_DATA * reg (0x2C), which allows further configuration of the device. */ - return ad7768_spi_reg_read(st, AD7768_REG_ADC_DATA, ®val, 3); + return ad7768_spi_reg_read(st, AD7768_REG_ADC_DATA, 3); } static const struct iio_buffer_setup_ops ad7768_buffer_ops = { @@ -811,46 +539,6 @@ static void ad7768_regulator_disable(void *data) regulator_disable(st->vref); } -static int ad7768_triggered_buffer_alloc(struct iio_dev *indio_dev) -{ - struct ad7768_state *st = iio_priv(indio_dev); - int ret; - - st->trig = devm_iio_trigger_alloc(indio_dev->dev.parent, "%s-dev%d", - indio_dev->name, iio_device_id(indio_dev)); - if (!st->trig) - return -ENOMEM; - - st->trig->ops = &ad7768_trigger_ops; - 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); - - init_completion(&st->completion); - - ret = devm_request_irq(indio_dev->dev.parent, st->irq, - &ad7768_interrupt, - IRQF_TRIGGER_RISING | IRQF_ONESHOT, - 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, - &ad7768_trigger_handler, - &ad7768_buffer_ops); -} - -static int ad7768_hardware_buffer_alloc(struct iio_dev *indio_dev) -{ - indio_dev->setup_ops = &ad7768_buffer_ops; - return devm_iio_dmaengine_buffer_setup(indio_dev->dev.parent, - indio_dev, "rx"); -} - static int ad7768_set_channel_label(struct iio_dev *indio_dev, int num_channels) { @@ -907,8 +595,6 @@ static int ad7768_probe(struct spi_device *spi) return PTR_ERR(st->mclk); st->mclk_freq = clk_get_rate(st->mclk); - st->spi_is_dma_mapped = legacy_spi_engine_offload_supported(spi); - st->irq = spi->irq; mutex_init(&st->lock); @@ -924,14 +610,37 @@ static int ad7768_probe(struct spi_device *spi) return ret; } + st->trig = devm_iio_trigger_alloc(&spi->dev, "%s-dev%d", + indio_dev->name, + iio_device_id(indio_dev)); + if (!st->trig) + return -ENOMEM; + + st->trig->ops = &ad7768_trigger_ops; + iio_trigger_set_drvdata(st->trig, indio_dev); + ret = devm_iio_trigger_register(&spi->dev, st->trig); + if (ret) + return ret; + + indio_dev->trig = iio_trigger_get(st->trig); + + init_completion(&st->completion); + ret = ad7768_set_channel_label(indio_dev, ARRAY_SIZE(ad7768_channels)); if (ret) return ret; - if (st->spi_is_dma_mapped) - ret = ad7768_hardware_buffer_alloc(indio_dev); - else - ret = ad7768_triggered_buffer_alloc(indio_dev); + ret = devm_request_irq(&spi->dev, spi->irq, + &ad7768_interrupt, + IRQF_TRIGGER_RISING | IRQF_ONESHOT, + indio_dev->name, indio_dev); + if (ret) + return ret; + + ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, + &iio_pollfunc_store_time, + &ad7768_trigger_handler, + &ad7768_buffer_ops); if (ret) return ret; @@ -963,4 +672,3 @@ module_spi_driver(ad7768_driver); MODULE_AUTHOR("Stefan Popa "); MODULE_DESCRIPTION("Analog Devices AD7768-1 ADC driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_DMAENGINE_BUFFER); From a7b88933d99fbc0d51141dfed6faacdabf6e6820 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Mon, 17 Feb 2025 14:16:12 +0000 Subject: [PATCH 06/46] iio: adc: ad7768-1: Move setting of val a bit later to avoid unnecessary return value check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The data used is all in local variables so there is no advantage in setting *val = ret with the direct mode claim held. Move it later to after error check. Reviewed-by: Nuno Sá Link: https://patch.msgid.link/20250217141630.897334-13-jic23@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7768-1.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index 113703fb724544..c2ba357b82d858 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -370,12 +370,11 @@ static int ad7768_read_raw(struct iio_dev *indio_dev, return ret; ret = ad7768_scan_direct(indio_dev); - if (ret >= 0) - *val = ret; iio_device_release_direct_mode(indio_dev); if (ret < 0) return ret; + *val = ret; return IIO_VAL_INT; From 425555cf0b3aef735d50426ecf4451c70b8f5b3a Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Mon, 17 Feb 2025 14:16:13 +0000 Subject: [PATCH 07/46] iio: adc: ad7768-1: Switch to sparse friendly iio_device_claim/release_direct() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These new functions allow sparse to find failures to release direct mode reducing chances of bugs over the claim_direct_mode() functions that are deprecated. Reviewed-by: Nuno Sá Link: https://patch.msgid.link/20250217141630.897334-14-jic23@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7768-1.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index c2ba357b82d858..ea829c51e80b5d 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -365,13 +365,12 @@ static int ad7768_read_raw(struct iio_dev *indio_dev, switch (info) { case IIO_CHAN_INFO_RAW: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; ret = ad7768_scan_direct(indio_dev); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); if (ret < 0) return ret; *val = ret; From e2988c9ebbbab3b44f6a45545012cd8656caed92 Mon Sep 17 00:00:00 2001 From: Sergiu Cuciurean Date: Thu, 6 Mar 2025 18:00:29 -0300 Subject: [PATCH 08/46] iio: adc: ad7768-1: Fix conversion result sign The ad7768-1 ADC output code is two's complement, meaning that the voltage conversion result is a signed value.. Since the value is a 24 bit one, stored in a 32 bit variable, the sign should be extended in order to get the correct representation. Also the channel description has been updated to signed representation, to match the ADC specifications. Fixes: a5f8c7da3dbe ("iio: adc: Add AD7768-1 ADC basic support") Reviewed-by: David Lechner Reviewed-by: Marcelo Schmitt Signed-off-by: Sergiu Cuciurean Signed-off-by: Jonathan Santos Cc: Link: https://patch.msgid.link/505994d3b71c2aa38ba714d909a68e021f12124c.1741268122.git.Jonathan.Santos@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7768-1.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index ea829c51e80b5d..09e7cccfd51cfd 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -142,7 +142,7 @@ static const struct iio_chan_spec ad7768_channels[] = { .channel = 0, .scan_index = 0, .scan_type = { - .sign = 'u', + .sign = 's', .realbits = 24, .storagebits = 32, .shift = 8, @@ -373,7 +373,7 @@ static int ad7768_read_raw(struct iio_dev *indio_dev, iio_device_release_direct(indio_dev); if (ret < 0) return ret; - *val = ret; + *val = sign_extend32(ret, chan->scan_type.realbits - 1); return IIO_VAL_INT; From b0db6998b61c6e18be9ca25abeae6474483638cc Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Thu, 6 Mar 2025 18:00:43 -0300 Subject: [PATCH 09/46] iio: adc: ad7768-1: set MOSI idle state to prevent accidental reset Datasheet recommends Setting the MOSI idle state to high in order to prevent accidental reset of the device when SCLK is free running. This happens when the controller clocks out a 1 followed by 63 zeros while the CS is held low. Check if SPI controller supports SPI_MOSI_IDLE_HIGH flag and set it. Fixes: a5f8c7da3dbe ("iio: adc: Add AD7768-1 ADC basic support") Signed-off-by: Jonathan Santos Reviewed-by: Marcelo Schmitt Link: https://patch.msgid.link/c2a2b0f3d54829079763a5511359a1fa80516cfb.1741268122.git.Jonathan.Santos@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7768-1.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index 09e7cccfd51cfd..a75247cdcaa7bf 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -572,6 +572,21 @@ static int ad7768_probe(struct spi_device *spi) return -ENOMEM; st = iio_priv(indio_dev); + /* + * Datasheet recommends SDI line to be kept high when data is not being + * clocked out of the controller and the spi clock is free running, + * to prevent accidental reset. + * Since many controllers do not support the SPI_MOSI_IDLE_HIGH flag + * yet, only request the MOSI idle state to enable if the controller + * supports it. + */ + if (spi->controller->mode_bits & SPI_MOSI_IDLE_HIGH) { + spi->mode |= SPI_MOSI_IDLE_HIGH; + ret = spi_setup(spi); + if (ret < 0) + return ret; + } + st->spi = spi; st->vref = devm_regulator_get(&spi->dev, "vref"); From 32939e906c99cd97cdca9d47bacf9769c04ae140 Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Thu, 6 Mar 2025 18:01:51 -0300 Subject: [PATCH 10/46] iio: adc: ad7768-1: remove unnecessary locking The current locking is only preventing a triggered buffer Transfer and a debugfs register access from happening at the same time. If a register access happens during a buffered read, the action is doomed to fail anyway, since we need to write a magic value to exit continuous read mode. Remove locking from the trigger handler and use iio_device_claim_direct() instead in the register access function. Reviewed-by: David Lechner Signed-off-by: Jonathan Santos Link: https://patch.msgid.link/d0450b7c5d8467e54913ef905f6147baa2b866b3.1741268122.git.Jonathan.Santos@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7768-1.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index a75247cdcaa7bf..5a863005aca6d1 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -154,7 +154,6 @@ static const struct iio_chan_spec ad7768_channels[] = { struct ad7768_state { struct spi_device *spi; struct regulator *vref; - struct mutex lock; struct clk *mclk; unsigned int mclk_freq; unsigned int samp_freq; @@ -256,18 +255,20 @@ static int ad7768_reg_access(struct iio_dev *indio_dev, struct ad7768_state *st = iio_priv(indio_dev); int ret; - mutex_lock(&st->lock); + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + if (readval) { ret = ad7768_spi_reg_read(st, reg, 1); if (ret < 0) - goto err_unlock; + goto err_release; *readval = ret; ret = 0; } else { ret = ad7768_spi_reg_write(st, reg, writeval); } -err_unlock: - mutex_unlock(&st->lock); +err_release: + iio_device_release_direct(indio_dev); return ret; } @@ -469,18 +470,15 @@ static irqreturn_t ad7768_trigger_handler(int irq, void *p) struct ad7768_state *st = iio_priv(indio_dev); int ret; - mutex_lock(&st->lock); - ret = spi_read(st->spi, &st->data.scan.chan, 3); if (ret < 0) - goto err_unlock; + goto out; iio_push_to_buffers_with_timestamp(indio_dev, &st->data.scan, iio_get_time_ns(indio_dev)); -err_unlock: +out: iio_trigger_notify_done(indio_dev->trig); - mutex_unlock(&st->lock); return IRQ_HANDLED; } @@ -609,8 +607,6 @@ static int ad7768_probe(struct spi_device *spi) st->mclk_freq = clk_get_rate(st->mclk); - mutex_init(&st->lock); - indio_dev->channels = ad7768_channels; indio_dev->num_channels = ARRAY_SIZE(ad7768_channels); indio_dev->name = spi_get_device_id(spi)->name; From baea66998a5239060ff4f0edf32f27a830b497a2 Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Fri, 11 Apr 2025 12:56:56 -0300 Subject: [PATCH 11/46] iio: adc: ad7768-1: convert driver to use regmap Convert the AD7768-1 driver to use the regmap API for register access. This change simplifies and standardizes register interactions, reducing code duplication and improving maintainability. Create two regmap configurations, one for 8-bit register values and other for 24-bit register values. Since we are using regmap now, define the remaining registers from 0x32 to 0x34. Reviewed-by: David Lechner Signed-off-by: Jonathan Santos Link: https://patch.msgid.link/aec9e5452c1ac16d5379a80dfce97c00d85614a2.1744325346.git.Jonathan.Santos@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/Kconfig | 1 + drivers/iio/adc/ad7768-1.c | 160 +++++++++++++++++++++++++------------ 2 files changed, 110 insertions(+), 51 deletions(-) diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 76a60d5894424f..8fd50628f43e54 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -376,6 +376,7 @@ config AD7768 config AD7768_1 tristate "Analog Devices AD7768-1 ADC driver" depends on SPI + select REGMAP_SPI select IIO_BUFFER select IIO_TRIGGER select IIO_TRIGGERED_BUFFER diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index 5a863005aca6d1..017d24d0bcd852 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -53,12 +54,15 @@ #define AD7768_REG_SPI_DIAG_ENABLE 0x28 #define AD7768_REG_ADC_DIAG_ENABLE 0x29 #define AD7768_REG_DIG_DIAG_ENABLE 0x2A -#define AD7768_REG_ADC_DATA 0x2C +#define AD7768_REG24_ADC_DATA 0x2C #define AD7768_REG_MASTER_STATUS 0x2D #define AD7768_REG_SPI_DIAG_STATUS 0x2E #define AD7768_REG_ADC_DIAG_STATUS 0x2F #define AD7768_REG_DIG_DIAG_STATUS 0x30 #define AD7768_REG_MCLK_COUNTER 0x31 +#define AD7768_REG_COEFF_CONTROL 0x32 +#define AD7768_REG24_COEFF_DATA 0x33 +#define AD7768_REG_ACCESS_KEY 0x34 /* AD7768_REG_POWER_CLOCK */ #define AD7768_PWR_MCLK_DIV_MSK GENMASK(5, 4) @@ -76,9 +80,6 @@ #define AD7768_CONV_MODE_MSK GENMASK(2, 0) #define AD7768_CONV_MODE(x) FIELD_PREP(AD7768_CONV_MODE_MSK, x) -#define AD7768_RD_FLAG_MSK(x) (BIT(6) | ((x) & 0x3F)) -#define AD7768_WR_FLAG_MSK(x) ((x) & 0x3F) - enum ad7768_conv_mode { AD7768_CONTINUOUS, AD7768_ONE_SHOT, @@ -153,6 +154,8 @@ static const struct iio_chan_spec ad7768_channels[] = { struct ad7768_state { struct spi_device *spi; + struct regmap *regmap; + struct regmap *regmap24; struct regulator *vref; struct clk *mclk; unsigned int mclk_freq; @@ -175,46 +178,82 @@ struct ad7768_state { } data __aligned(IIO_DMA_MINALIGN); }; -static int ad7768_spi_reg_read(struct ad7768_state *st, unsigned int addr, - unsigned int len) -{ - unsigned int shift; - int ret; +static const struct regmap_range ad7768_regmap_rd_ranges[] = { + regmap_reg_range(AD7768_REG_CHIP_TYPE, AD7768_REG_CHIP_GRADE), + regmap_reg_range(AD7768_REG_SCRATCH_PAD, AD7768_REG_SCRATCH_PAD), + regmap_reg_range(AD7768_REG_VENDOR_L, AD7768_REG_VENDOR_H), + regmap_reg_range(AD7768_REG_INTERFACE_FORMAT, AD7768_REG_GAIN_LO), + regmap_reg_range(AD7768_REG_SPI_DIAG_ENABLE, AD7768_REG_DIG_DIAG_ENABLE), + regmap_reg_range(AD7768_REG_MASTER_STATUS, AD7768_REG_COEFF_CONTROL), + regmap_reg_range(AD7768_REG_ACCESS_KEY, AD7768_REG_ACCESS_KEY), +}; - shift = 32 - (8 * len); - st->data.d8[0] = AD7768_RD_FLAG_MSK(addr); +static const struct regmap_access_table ad7768_regmap_rd_table = { + .yes_ranges = ad7768_regmap_rd_ranges, + .n_yes_ranges = ARRAY_SIZE(ad7768_regmap_rd_ranges), +}; - ret = spi_write_then_read(st->spi, st->data.d8, 1, - &st->data.d32, len); - if (ret < 0) - return ret; +static const struct regmap_range ad7768_regmap_wr_ranges[] = { + regmap_reg_range(AD7768_REG_SCRATCH_PAD, AD7768_REG_SCRATCH_PAD), + regmap_reg_range(AD7768_REG_INTERFACE_FORMAT, AD7768_REG_GPIO_WRITE), + regmap_reg_range(AD7768_REG_OFFSET_HI, AD7768_REG_GAIN_LO), + regmap_reg_range(AD7768_REG_SPI_DIAG_ENABLE, AD7768_REG_DIG_DIAG_ENABLE), + regmap_reg_range(AD7768_REG_SPI_DIAG_STATUS, AD7768_REG_SPI_DIAG_STATUS), + regmap_reg_range(AD7768_REG_COEFF_CONTROL, AD7768_REG_COEFF_CONTROL), + regmap_reg_range(AD7768_REG_ACCESS_KEY, AD7768_REG_ACCESS_KEY), +}; - return (be32_to_cpu(st->data.d32) >> shift); -} +static const struct regmap_access_table ad7768_regmap_wr_table = { + .yes_ranges = ad7768_regmap_wr_ranges, + .n_yes_ranges = ARRAY_SIZE(ad7768_regmap_wr_ranges), +}; -static int ad7768_spi_reg_write(struct ad7768_state *st, - unsigned int addr, - unsigned int val) -{ - st->data.d8[0] = AD7768_WR_FLAG_MSK(addr); - st->data.d8[1] = val & 0xFF; +static const struct regmap_config ad7768_regmap_config = { + .name = "ad7768-1-8", + .reg_bits = 8, + .val_bits = 8, + .read_flag_mask = BIT(6), + .rd_table = &ad7768_regmap_rd_table, + .wr_table = &ad7768_regmap_wr_table, + .max_register = AD7768_REG_ACCESS_KEY, + .use_single_write = true, + .use_single_read = true, +}; - return spi_write(st->spi, st->data.d8, 2); -} +static const struct regmap_range ad7768_regmap24_rd_ranges[] = { + regmap_reg_range(AD7768_REG24_ADC_DATA, AD7768_REG24_ADC_DATA), + regmap_reg_range(AD7768_REG24_COEFF_DATA, AD7768_REG24_COEFF_DATA), +}; -static int ad7768_set_mode(struct ad7768_state *st, - enum ad7768_conv_mode mode) -{ - int regval; +static const struct regmap_access_table ad7768_regmap24_rd_table = { + .yes_ranges = ad7768_regmap24_rd_ranges, + .n_yes_ranges = ARRAY_SIZE(ad7768_regmap24_rd_ranges), +}; - regval = ad7768_spi_reg_read(st, AD7768_REG_CONVERSION, 1); - if (regval < 0) - return regval; +static const struct regmap_range ad7768_regmap24_wr_ranges[] = { + regmap_reg_range(AD7768_REG24_COEFF_DATA, AD7768_REG24_COEFF_DATA), +}; - regval &= ~AD7768_CONV_MODE_MSK; - regval |= AD7768_CONV_MODE(mode); +static const struct regmap_access_table ad7768_regmap24_wr_table = { + .yes_ranges = ad7768_regmap24_wr_ranges, + .n_yes_ranges = ARRAY_SIZE(ad7768_regmap24_wr_ranges), +}; - return ad7768_spi_reg_write(st, AD7768_REG_CONVERSION, regval); +static const struct regmap_config ad7768_regmap24_config = { + .name = "ad7768-1-24", + .reg_bits = 8, + .val_bits = 24, + .read_flag_mask = BIT(6), + .rd_table = &ad7768_regmap24_rd_table, + .wr_table = &ad7768_regmap24_wr_table, + .max_register = AD7768_REG24_COEFF_DATA, +}; + +static int ad7768_set_mode(struct ad7768_state *st, + enum ad7768_conv_mode mode) +{ + return regmap_update_bits(st->regmap, AD7768_REG_CONVERSION, + AD7768_CONV_MODE_MSK, AD7768_CONV_MODE(mode)); } static int ad7768_scan_direct(struct iio_dev *indio_dev) @@ -233,9 +272,10 @@ static int ad7768_scan_direct(struct iio_dev *indio_dev) if (!ret) return -ETIMEDOUT; - readval = ad7768_spi_reg_read(st, AD7768_REG_ADC_DATA, 3); - if (readval < 0) - return readval; + ret = regmap_read(st->regmap24, AD7768_REG24_ADC_DATA, &readval); + if (ret) + return ret; + /* * Any SPI configuration of the AD7768-1 can only be * performed in continuous conversion mode. @@ -258,16 +298,23 @@ static int ad7768_reg_access(struct iio_dev *indio_dev, if (!iio_device_claim_direct(indio_dev)) return -EBUSY; + ret = -EINVAL; if (readval) { - ret = ad7768_spi_reg_read(st, reg, 1); - if (ret < 0) - goto err_release; - *readval = ret; - ret = 0; + if (regmap_check_range_table(st->regmap, reg, &ad7768_regmap_rd_table)) + ret = regmap_read(st->regmap, reg, readval); + + if (regmap_check_range_table(st->regmap24, reg, &ad7768_regmap24_rd_table)) + ret = regmap_read(st->regmap24, reg, readval); + } else { - ret = ad7768_spi_reg_write(st, reg, writeval); + if (regmap_check_range_table(st->regmap, reg, &ad7768_regmap_wr_table)) + ret = regmap_write(st->regmap, reg, writeval); + + if (regmap_check_range_table(st->regmap24, reg, &ad7768_regmap24_wr_table)) + ret = regmap_write(st->regmap24, reg, writeval); + } -err_release: + iio_device_release_direct(indio_dev); return ret; @@ -284,7 +331,7 @@ static int ad7768_set_dig_fil(struct ad7768_state *st, else mode = AD7768_DIG_FIL_DEC_RATE(dec_rate); - ret = ad7768_spi_reg_write(st, AD7768_REG_DIGITAL_FILTER, mode); + ret = regmap_write(st->regmap, AD7768_REG_DIGITAL_FILTER, mode); if (ret < 0) return ret; @@ -321,7 +368,7 @@ static int ad7768_set_freq(struct ad7768_state *st, */ pwr_mode = AD7768_PWR_MCLK_DIV(ad7768_clk_config[idx].mclk_div) | AD7768_PWR_PWRMODE(ad7768_clk_config[idx].pwrmode); - ret = ad7768_spi_reg_write(st, AD7768_REG_POWER_CLOCK, pwr_mode); + ret = regmap_write(st->regmap, AD7768_REG_POWER_CLOCK, pwr_mode); if (ret < 0) return ret; @@ -446,11 +493,11 @@ static int ad7768_setup(struct ad7768_state *st) * to 10. When the sequence is detected, the reset occurs. * See the datasheet, page 70. */ - ret = ad7768_spi_reg_write(st, AD7768_REG_SYNC_RESET, 0x3); + ret = regmap_write(st->regmap, AD7768_REG_SYNC_RESET, 0x3); if (ret) return ret; - ret = ad7768_spi_reg_write(st, AD7768_REG_SYNC_RESET, 0x2); + ret = regmap_write(st->regmap, AD7768_REG_SYNC_RESET, 0x2); if (ret) return ret; @@ -505,18 +552,19 @@ static int ad7768_buffer_postenable(struct iio_dev *indio_dev) * continuous read mode. Subsequent data reads do not require an * initial 8-bit write to query the ADC_DATA register. */ - return ad7768_spi_reg_write(st, AD7768_REG_INTERFACE_FORMAT, 0x01); + return regmap_write(st->regmap, AD7768_REG_INTERFACE_FORMAT, 0x01); } static int ad7768_buffer_predisable(struct iio_dev *indio_dev) { struct ad7768_state *st = iio_priv(indio_dev); + unsigned int unused; /* * To exit continuous read mode, perform a single read of the ADC_DATA * reg (0x2C), which allows further configuration of the device. */ - return ad7768_spi_reg_read(st, AD7768_REG_ADC_DATA, 3); + return regmap_read(st->regmap24, AD7768_REG24_ADC_DATA, &unused); } static const struct iio_buffer_setup_ops ad7768_buffer_ops = { @@ -587,6 +635,16 @@ static int ad7768_probe(struct spi_device *spi) st->spi = spi; + st->regmap = devm_regmap_init_spi(spi, &ad7768_regmap_config); + if (IS_ERR(st->regmap)) + return dev_err_probe(&spi->dev, PTR_ERR(st->regmap), + "Failed to initialize regmap"); + + st->regmap24 = devm_regmap_init_spi(spi, &ad7768_regmap24_config); + if (IS_ERR(st->regmap24)) + return dev_err_probe(&spi->dev, PTR_ERR(st->regmap24), + "Failed to initialize regmap24"); + st->vref = devm_regulator_get(&spi->dev, "vref"); if (IS_ERR(st->vref)) return PTR_ERR(st->vref); From 9f698eeb2d94cdba16924d860f0d85bad994cded Mon Sep 17 00:00:00 2001 From: Sergiu Cuciurean Date: Fri, 11 Apr 2025 12:57:09 -0300 Subject: [PATCH 12/46] iio: adc: ad7768-1: Add reset gpio Implement asynchronous hardware reset GPIO. Reviewed-by: David Lechner Reviewed-by: Marcelo Schmitt Signed-off-by: Sergiu Cuciurean Co-developed-by: Jonathan Santos Signed-off-by: Jonathan Santos Link: https://patch.msgid.link/25a413babeddf29583f1c26abf4234dfd606a595.1744325346.git.Jonathan.Santos@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7768-1.c | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index 017d24d0bcd852..34712d3756e228 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -163,6 +163,7 @@ struct ad7768_state { struct completion completion; struct iio_trigger *trig; struct gpio_desc *gpio_sync_in; + struct gpio_desc *gpio_reset; const char *labels[ARRAY_SIZE(ad7768_channels)]; /* * DMA (thus cache coherency maintenance) may require the @@ -487,19 +488,30 @@ static int ad7768_setup(struct ad7768_state *st) { int ret; - /* - * Two writes to the SPI_RESET[1:0] bits are required to initiate - * a software reset. The bits must first be set to 11, and then - * to 10. When the sequence is detected, the reset occurs. - * See the datasheet, page 70. - */ - ret = regmap_write(st->regmap, AD7768_REG_SYNC_RESET, 0x3); - if (ret) - return ret; + st->gpio_reset = devm_gpiod_get_optional(&st->spi->dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(st->gpio_reset)) + return PTR_ERR(st->gpio_reset); - ret = regmap_write(st->regmap, AD7768_REG_SYNC_RESET, 0x2); - if (ret) - return ret; + if (st->gpio_reset) { + fsleep(10); + gpiod_set_value_cansleep(st->gpio_reset, 0); + fsleep(200); + } else { + /* + * Two writes to the SPI_RESET[1:0] bits are required to initiate + * a software reset. The bits must first be set to 11, and then + * to 10. When the sequence is detected, the reset occurs. + * See the datasheet, page 70. + */ + ret = regmap_write(st->regmap, AD7768_REG_SYNC_RESET, 0x3); + if (ret) + return ret; + + ret = regmap_write(st->regmap, AD7768_REG_SYNC_RESET, 0x2); + if (ret) + return ret; + } st->gpio_sync_in = devm_gpiod_get(&st->spi->dev, "adi,sync-in", GPIOD_OUT_LOW); From b3128a2af393d41d4dbc911c2598ba6f7b14b102 Mon Sep 17 00:00:00 2001 From: Sergiu Cuciurean Date: Fri, 11 Apr 2025 12:57:23 -0300 Subject: [PATCH 13/46] iio: adc: ad7768-1: Move buffer allocation to a separate function This change moves the buffer allocation and related trigger allocation in a separate function, making space for adding another type of iio buffer if needed. Reviewed-by: Marcelo Schmitt Reviewed-by: David Lechner Signed-off-by: Sergiu Cuciurean Signed-off-by: Jonathan Santos Link: https://patch.msgid.link/11c1777b406875ce1a7216dc4b094ff99af8da7f.1744325346.git.Jonathan.Santos@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7768-1.c | 44 ++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index 34712d3756e228..66087fabe1816c 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -619,6 +619,31 @@ static int ad7768_set_channel_label(struct iio_dev *indio_dev, return 0; } +static int ad7768_triggered_buffer_alloc(struct iio_dev *indio_dev) +{ + struct ad7768_state *st = iio_priv(indio_dev); + int ret; + + st->trig = devm_iio_trigger_alloc(indio_dev->dev.parent, "%s-dev%d", + indio_dev->name, + iio_device_id(indio_dev)); + if (!st->trig) + return -ENOMEM; + + st->trig->ops = &ad7768_trigger_ops; + 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); + + return devm_iio_triggered_buffer_setup(indio_dev->dev.parent, indio_dev, + &iio_pollfunc_store_time, + &ad7768_trigger_handler, + &ad7768_buffer_ops); +} + static int ad7768_probe(struct spi_device *spi) { struct ad7768_state *st; @@ -689,20 +714,6 @@ static int ad7768_probe(struct spi_device *spi) return ret; } - st->trig = devm_iio_trigger_alloc(&spi->dev, "%s-dev%d", - indio_dev->name, - iio_device_id(indio_dev)); - if (!st->trig) - return -ENOMEM; - - st->trig->ops = &ad7768_trigger_ops; - iio_trigger_set_drvdata(st->trig, indio_dev); - ret = devm_iio_trigger_register(&spi->dev, st->trig); - if (ret) - return ret; - - indio_dev->trig = iio_trigger_get(st->trig); - init_completion(&st->completion); ret = ad7768_set_channel_label(indio_dev, ARRAY_SIZE(ad7768_channels)); @@ -716,10 +727,7 @@ static int ad7768_probe(struct spi_device *spi) if (ret) return ret; - ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, - &iio_pollfunc_store_time, - &ad7768_trigger_handler, - &ad7768_buffer_ops); + ret = ad7768_triggered_buffer_alloc(indio_dev); if (ret) return ret; From 47082930027d480d5dc72338000a00485f5b9c7b Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 11 Apr 2025 15:49:34 -0500 Subject: [PATCH 14/46] iio: normalize array sentinel style Use `\t(\{ ?\},|\{\}|\{\s*/\*.*\*/\s*\},?)$` regex to find and replace the array sentinel in all IIO drivers to the same style. For some time, we've been trying to consistently use `{ }` (no trailing comma, no comment, one space between braces) for array sentinels in the IIO subsystem. Still nearly 50% of existing code uses a different style. To save reviewers from having to request this trivial change as frequently, let's normalize the style in all existing IIO drivers. At least when code is copy/pasted to new drivers, the style will be consistent. Signed-off-by: David Lechner Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20250411-iio-sentinel-normalization-v1-1-d293de3e3d93@baylibre.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7768-1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index 66087fabe1816c..09e4ab76e2b60d 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -736,7 +736,7 @@ static int ad7768_probe(struct spi_device *spi) static const struct spi_device_id ad7768_id_table[] = { { "ad7768-1", 0 }, - {} + { } }; MODULE_DEVICE_TABLE(spi, ad7768_id_table); From 7c90950f3721f88379381c228428129791da039c Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 13 Apr 2025 11:34:32 +0100 Subject: [PATCH 15/46] iio: adc: Use iio_push_to_buffers_with_ts() to provide length for runtime checks. This new function allows us to perform debug checks in the helper to ensure that the overrun does not occur. Use it in all the simple cases where either a static buffer or a structure is used in the drivers. Reviewed-by: David Lechner Link: https://patch.msgid.link/20250413103443.2420727-10-jic23@kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7768-1.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index 09e4ab76e2b60d..47a6ad43358558 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -533,8 +533,9 @@ static irqreturn_t ad7768_trigger_handler(int irq, void *p) if (ret < 0) goto out; - iio_push_to_buffers_with_timestamp(indio_dev, &st->data.scan, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &st->data.scan, + sizeof(st->data.scan), + iio_get_time_ns(indio_dev)); out: iio_trigger_notify_done(indio_dev->trig); From 20ecb78e4c64af3a44db8cd78a42864d2a286786 Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Thu, 8 May 2025 14:03:04 -0300 Subject: [PATCH 16/46] iio: adc: ad7768-1: reorganize driver headers Remove kernel.h since it adds a lot of unnecessary dependencies. Add specific headers to ensure all functions and macros used in the driver are directly declared. Suggested-by: Andy Shevchenko Signed-off-by: Jonathan Santos Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/1f7677d31a0165cb30d7eb3b4d613e1337937f9a.1746662899.git.Jonathan.Santos@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7768-1.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index 47a6ad43358558..9d39a643ab6959 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -4,13 +4,15 @@ * * Copyright 2017 Analog Devices Inc. */ +#include #include #include +#include #include #include #include #include -#include +#include #include #include #include From d0885ca1991b0755cdb0c4ef727abe8c7c592d3a Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Wed, 4 Jun 2025 16:35:21 -0300 Subject: [PATCH 17/46] iio: adc: ad7768-1: Ensure SYNC_IN pulse minimum timing requirement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SYNC_IN pulse width must be at least 1.5 x Tmclk, corresponding to ~2.5 µs at the lowest supported MCLK frequency. Add a 3 µs delay to ensure reliable synchronization timing even for the worst-case scenario. Signed-off-by: Jonathan Santos Reviewed-by: David Lechner Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/d3ee92a533cd1207cf5c5cc4d7bdbb5c6c267f68.1749063024.git.Jonathan.Santos@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7768-1.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index 9d39a643ab6959..b96fb97d58795a 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -252,6 +252,24 @@ static const struct regmap_config ad7768_regmap24_config = { .max_register = AD7768_REG24_COEFF_DATA, }; +static int ad7768_send_sync_pulse(struct ad7768_state *st) +{ + /* + * The datasheet specifies a minimum SYNC_IN pulse width of 1.5 × Tmclk, + * where Tmclk is the MCLK period. The supported MCLK frequencies range + * from 0.6 MHz to 17 MHz, which corresponds to a minimum SYNC_IN pulse + * width of approximately 2.5 µs in the worst-case scenario (0.6 MHz). + * + * Add a delay to ensure the pulse width is always sufficient to + * trigger synchronization. + */ + gpiod_set_value_cansleep(st->gpio_sync_in, 1); + fsleep(3); + gpiod_set_value_cansleep(st->gpio_sync_in, 0); + + return 0; +} + static int ad7768_set_mode(struct ad7768_state *st, enum ad7768_conv_mode mode) { @@ -339,10 +357,7 @@ static int ad7768_set_dig_fil(struct ad7768_state *st, return ret; /* A sync-in pulse is required every time the filter dec rate changes */ - gpiod_set_value(st->gpio_sync_in, 1); - gpiod_set_value(st->gpio_sync_in, 0); - - return 0; + return ad7768_send_sync_pulse(st); } static int ad7768_set_freq(struct ad7768_state *st, From d95f97e56a6e50d8c6a94b206965d20666d6e566 Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Wed, 11 Jun 2025 08:50:01 -0300 Subject: [PATCH 18/46] dt-bindings: iio: adc: ad7768-1: document regulator provider property The AD7768-1 provides a buffered common-mode voltage output on the VCM pin that can be used to bias analog input signals. Add regulators property to enable the use of the VCM output, referenced here as vcm-output, by any other device. Acked-by: Conor Dooley Signed-off-by: Jonathan Santos Link: https://patch.msgid.link/33c02a1fb9d839f62da5237f9476ccbf14271b6d.1749569957.git.Jonathan.Santos@analog.com Signed-off-by: Jonathan Cameron --- .../bindings/iio/adc/adi,ad7768-1.yaml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.yaml index 3ce59d4d065f5d..0e651820e2cfe1 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.yaml @@ -47,6 +47,19 @@ properties: in any way, for example if the filter decimation rate changes. As the line is active low, it should be marked GPIO_ACTIVE_LOW. + regulators: + type: object + description: + list of regulators provided by this controller. + + properties: + vcm-output: + $ref: /schemas/regulator/regulator.yaml# + type: object + unevaluatedProperties: false + + additionalProperties: false + reset-gpios: maxItems: 1 @@ -120,6 +133,12 @@ examples: reg = <0>; label = "channel_0"; }; + + regulators { + vcm_reg: vcm-output { + regulator-name = "ad7768-1-vcm"; + }; + }; }; }; ... From 5d31f3070a85c72e9de3f8783bf34d2a9df6f600 Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Wed, 11 Jun 2025 08:50:14 -0300 Subject: [PATCH 19/46] dt-bindings: iio: adc: ad7768-1: Document GPIO controller The AD7768-1 ADC exports four bidirectional GPIOs accessible via register map. Document GPIO properties necessary to enable GPIO controller for this device. Acked-by: Bartosz Golaszewski Reviewed-by: Linus Walleij Reviewed-by: Rob Herring (Arm) Signed-off-by: Jonathan Santos Link: https://patch.msgid.link/2ac34fc1e0b02886073ae0bb196c7e8d4d442c3f.1749569957.git.Jonathan.Santos@analog.com Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/adc/adi,ad7768-1.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.yaml index 0e651820e2cfe1..89db6f56a379f5 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.yaml @@ -70,6 +70,14 @@ properties: "#io-channel-cells": const: 1 + gpio-controller: true + + "#gpio-cells": + const: 2 + description: | + The first cell is for the GPIO number: 0 to 3. + The second cell takes standard GPIO flags. + required: - compatible - reg @@ -118,6 +126,8 @@ examples: spi-max-frequency = <2000000>; spi-cpol; spi-cpha; + gpio-controller; + #gpio-cells = <2>; vref-supply = <&adc_vref>; interrupts = <25 IRQ_TYPE_EDGE_RISING>; interrupt-parent = <&gpio>; From 023bd5d5f7d21a999396176a0bf59cd271389177 Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Wed, 11 Jun 2025 08:50:27 -0300 Subject: [PATCH 20/46] dt-bindings: iio: adc: ad7768-1: add trigger-sources property In addition to GPIO synchronization, The AD7768-1 also supports synchronization over SPI, which use is recommended when the GPIO cannot provide a pulse synchronous with the base MCLK signal. It consists of looping back the SYNC_OUT to the SYNC_IN pin and send a command via SPI to trigger the synchronization. Introduce the 'trigger-sources' property to enable SPI-based synchronization via SYNC_OUT pin, along with additional optional entries for GPIO3 and DRDY pins. Also create #trigger-source-cells property to differentiate the trigger sources provided by the ADC. To improve readability, create a adi,ad7768-1.h header with the macros for the cell values. While at it, add description to the interrupts property. Acked-by: Conor Dooley Reviewed-by: David Lechner Signed-off-by: Jonathan Santos Link: https://patch.msgid.link/713fd786010c75858700efaec8bb285274e7057e.1749569957.git.Jonathan.Santos@analog.com Signed-off-by: Jonathan Cameron --- .../bindings/iio/adc/adi,ad7768-1.yaml | 39 ++++++++++++++++++- MAINTAINERS | 1 + include/dt-bindings/iio/adc/adi,ad7768-1.h | 10 +++++ 3 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 include/dt-bindings/iio/adc/adi,ad7768-1.h diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.yaml index 89db6f56a379f5..c06d0fc791d393 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.yaml @@ -26,7 +26,26 @@ properties: clock-names: const: mclk + trigger-sources: + $ref: /schemas/types.yaml#/definitions/phandle-array + minItems: 1 + maxItems: 2 + description: | + A list of phandles referencing trigger source providers. Each entry + represents a trigger source for the ADC: + + - First entry specifies the device responsible for driving the + synchronization (SYNC_IN) pin, as an alternative to adi,sync-in-gpios. + This can be a `gpio-trigger` or another `ad7768-1` device. If the + device's own SYNC_OUT pin is internally connected to its SYNC_IN pin, + reference the device itself or omit this property. + - Second entry optionally defines a GPIO3 pin used as a START signal trigger. + + Use the accompanying trigger source cell to identify the type of each entry. + interrupts: + description: + DRDY (Data Ready) pin, which signals conversion results are available. maxItems: 1 '#address-cells': @@ -70,6 +89,15 @@ properties: "#io-channel-cells": const: 1 + "#trigger-source-cells": + description: | + Cell indicates the trigger output signal: 0 = SYNC_OUT, 1 = GPIO3, + 2 = DRDY. + + For better readability, macros for these values are available in + dt-bindings/iio/adc/adi,ad7768-1.h. + const: 1 + gpio-controller: true "#gpio-cells": @@ -86,7 +114,16 @@ required: - vref-supply - spi-cpol - spi-cpha - - adi,sync-in-gpios + +dependencies: + adi,sync-in-gpios: + not: + required: + - trigger-sources + trigger-sources: + not: + required: + - adi,sync-in-gpios patternProperties: "^channel@([0-9]|1[0-5])$": diff --git a/MAINTAINERS b/MAINTAINERS index 8c75d385358a86..0b0509bcdcc597 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1429,6 +1429,7 @@ S: Supported W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.yaml F: drivers/iio/adc/ad7768-1.c +F: include/dt-bindings/iio/adc/adi,ad7768-1.h ANALOG DEVICES INC AD7780 DRIVER M: Michael Hennerich diff --git a/include/dt-bindings/iio/adc/adi,ad7768-1.h b/include/dt-bindings/iio/adc/adi,ad7768-1.h new file mode 100644 index 00000000000000..34d92856a50b1b --- /dev/null +++ b/include/dt-bindings/iio/adc/adi,ad7768-1.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ + +#ifndef _DT_BINDINGS_ADI_AD7768_1_H +#define _DT_BINDINGS_ADI_AD7768_1_H + +#define AD7768_TRIGGER_SOURCE_SYNC_OUT 0 +#define AD7768_TRIGGER_SOURCE_GPIO3 1 +#define AD7768_TRIGGER_SOURCE_DRDY 2 + +#endif /* _DT_BINDINGS_ADI_AD7768_1_H */ From 620a5bc92c44108c9a99fb0c940ea97800bf2e5c Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Wed, 11 Jun 2025 08:50:44 -0300 Subject: [PATCH 21/46] iio: adc: ad7768-1: add regulator to control VCM output The VCM output voltage can be used as a common-mode voltage within the amplifier preconditioning circuits external to the AD7768-1. This change allows the user to configure VCM output using the regulator framework. Acked-by: Marcelo Schmitt Reviewed-by: David Lechner Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Santos Link: https://patch.msgid.link/1f02312fdc4131168b194d59f4b1688dc68ea36e.1749569957.git.Jonathan.Santos@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7768-1.c | 159 +++++++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index b96fb97d58795a..3aab4b9becf5d7 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -13,9 +13,11 @@ #include #include #include +#include #include #include #include +#include #include #include @@ -82,6 +84,12 @@ #define AD7768_CONV_MODE_MSK GENMASK(2, 0) #define AD7768_CONV_MODE(x) FIELD_PREP(AD7768_CONV_MODE_MSK, x) +/* AD7768_REG_ANALOG2 */ +#define AD7768_REG_ANALOG2_VCM_MSK GENMASK(2, 0) +#define AD7768_REG_ANALOG2_VCM(x) FIELD_PREP(AD7768_REG_ANALOG2_VCM_MSK, (x)) + +#define AD7768_VCM_OFF 0x07 + enum ad7768_conv_mode { AD7768_CONTINUOUS, AD7768_ONE_SHOT, @@ -159,6 +167,8 @@ struct ad7768_state { struct regmap *regmap; struct regmap *regmap24; struct regulator *vref; + struct regulator_dev *vcm_rdev; + unsigned int vcm_output_sel; struct clk *mclk; unsigned int mclk_freq; unsigned int samp_freq; @@ -662,6 +672,150 @@ static int ad7768_triggered_buffer_alloc(struct iio_dev *indio_dev) &ad7768_buffer_ops); } +static int ad7768_vcm_enable(struct regulator_dev *rdev) +{ + struct iio_dev *indio_dev = rdev_get_drvdata(rdev); + struct ad7768_state *st = iio_priv(indio_dev); + int ret, regval; + + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + + /* To enable, set the last selected output */ + regval = AD7768_REG_ANALOG2_VCM(st->vcm_output_sel + 1); + ret = regmap_update_bits(st->regmap, AD7768_REG_ANALOG2, + AD7768_REG_ANALOG2_VCM_MSK, regval); + iio_device_release_direct(indio_dev); + + return ret; +} + +static int ad7768_vcm_disable(struct regulator_dev *rdev) +{ + struct iio_dev *indio_dev = rdev_get_drvdata(rdev); + struct ad7768_state *st = iio_priv(indio_dev); + int ret; + + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + + ret = regmap_update_bits(st->regmap, AD7768_REG_ANALOG2, + AD7768_REG_ANALOG2_VCM_MSK, AD7768_VCM_OFF); + iio_device_release_direct(indio_dev); + + return ret; +} + +static int ad7768_vcm_is_enabled(struct regulator_dev *rdev) +{ + struct iio_dev *indio_dev = rdev_get_drvdata(rdev); + struct ad7768_state *st = iio_priv(indio_dev); + int ret, val; + + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + + ret = regmap_read(st->regmap, AD7768_REG_ANALOG2, &val); + iio_device_release_direct(indio_dev); + if (ret) + return ret; + + return FIELD_GET(AD7768_REG_ANALOG2_VCM_MSK, val) != AD7768_VCM_OFF; +} + +static int ad7768_set_voltage_sel(struct regulator_dev *rdev, + unsigned int selector) +{ + unsigned int regval = AD7768_REG_ANALOG2_VCM(selector + 1); + struct iio_dev *indio_dev = rdev_get_drvdata(rdev); + struct ad7768_state *st = iio_priv(indio_dev); + int ret; + + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + + ret = regmap_update_bits(st->regmap, AD7768_REG_ANALOG2, + AD7768_REG_ANALOG2_VCM_MSK, regval); + iio_device_release_direct(indio_dev); + if (ret) + return ret; + + st->vcm_output_sel = selector; + + return 0; +} + +static int ad7768_get_voltage_sel(struct regulator_dev *rdev) +{ + struct iio_dev *indio_dev = rdev_get_drvdata(rdev); + struct ad7768_state *st = iio_priv(indio_dev); + int ret, val; + + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + + ret = regmap_read(st->regmap, AD7768_REG_ANALOG2, &val); + iio_device_release_direct(indio_dev); + if (ret) + return ret; + + val = FIELD_GET(AD7768_REG_ANALOG2_VCM_MSK, val); + + return clamp(val, 1, rdev->desc->n_voltages) - 1; +} + +static const struct regulator_ops vcm_regulator_ops = { + .enable = ad7768_vcm_enable, + .disable = ad7768_vcm_disable, + .is_enabled = ad7768_vcm_is_enabled, + .list_voltage = regulator_list_voltage_table, + .set_voltage_sel = ad7768_set_voltage_sel, + .get_voltage_sel = ad7768_get_voltage_sel, +}; + +static const unsigned int vcm_voltage_table[] = { + 2500000, + 2050000, + 1650000, + 1900000, + 1100000, + 900000, +}; + +static const struct regulator_desc vcm_desc = { + .name = "ad7768-1-vcm", + .of_match = "vcm-output", + .regulators_node = "regulators", + .n_voltages = ARRAY_SIZE(vcm_voltage_table), + .volt_table = vcm_voltage_table, + .ops = &vcm_regulator_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, +}; + +static int ad7768_register_regulators(struct device *dev, struct ad7768_state *st, + struct iio_dev *indio_dev) +{ + struct regulator_config config = { + .dev = dev, + .driver_data = indio_dev, + }; + int ret; + + /* Disable the regulator before registering it */ + ret = regmap_update_bits(st->regmap, AD7768_REG_ANALOG2, + AD7768_REG_ANALOG2_VCM_MSK, AD7768_VCM_OFF); + if (ret) + return ret; + + st->vcm_rdev = devm_regulator_register(dev, &vcm_desc, &config); + if (IS_ERR(st->vcm_rdev)) + return dev_err_probe(dev, PTR_ERR(st->vcm_rdev), + "failed to register VCM regulator\n"); + + return 0; +} + static int ad7768_probe(struct spi_device *spi) { struct ad7768_state *st; @@ -726,6 +880,11 @@ static int ad7768_probe(struct spi_device *spi) indio_dev->info = &ad7768_info; indio_dev->modes = INDIO_DIRECT_MODE; + /* Register VCM output regulator */ + ret = ad7768_register_regulators(&spi->dev, st, indio_dev); + if (ret) + return ret; + ret = ad7768_setup(st); if (ret < 0) { dev_err(&spi->dev, "AD7768 setup failed\n"); From abb41ad06f1cb260091e417935d66e3234f72304 Mon Sep 17 00:00:00 2001 From: Sergiu Cuciurean Date: Wed, 11 Jun 2025 08:50:56 -0300 Subject: [PATCH 22/46] iio: adc: ad7768-1: Add GPIO controller support The AD7768-1 has the ability to control other local hardware (such as gain stages),to power down other blocks in the signal chain, or read local status signals over the SPI interface. Add direct mode conditional locks in the GPIO callbacks to prevent register access when the device is in buffered mode. This change exports the AD7768-1's four GPIOs and makes them accessible at an upper layer. OBS: GPIO set is not returning due to feature not available in kernel 6.12. Reviewed-by: Marcelo Schmitt Acked-by: Bartosz Golaszewski Reviewed-by: Linus Walleij Reviewed-by: Andy Shevchenko Signed-off-by: Sergiu Cuciurean Co-developed-by: Jonathan Santos Signed-off-by: Jonathan Santos Link: https://patch.msgid.link/8abca580f43cb31d7088d07a7414b5f7efe91ead.1749569957.git.Jonathan.Santos@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7768-1.c | 141 ++++++++++++++++++++++++++++++++++++- 1 file changed, 139 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index 3aab4b9becf5d7..cc9a347f710910 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -88,6 +89,16 @@ #define AD7768_REG_ANALOG2_VCM_MSK GENMASK(2, 0) #define AD7768_REG_ANALOG2_VCM(x) FIELD_PREP(AD7768_REG_ANALOG2_VCM_MSK, (x)) +/* AD7768_REG_GPIO_CONTROL */ +#define AD7768_GPIO_UNIVERSAL_EN BIT(7) +#define AD7768_GPIO_CONTROL_MSK GENMASK(3, 0) + +/* AD7768_REG_GPIO_WRITE */ +#define AD7768_GPIO_WRITE_MSK GENMASK(3, 0) + +/* AD7768_REG_GPIO_READ */ +#define AD7768_GPIO_READ_MSK GENMASK(3, 0) + #define AD7768_VCM_OFF 0x07 enum ad7768_conv_mode { @@ -177,6 +188,7 @@ struct ad7768_state { struct gpio_desc *gpio_sync_in; struct gpio_desc *gpio_reset; const char *labels[ARRAY_SIZE(ad7768_channels)]; + struct gpio_chip gpiochip; /* * DMA (thus cache coherency maintenance) may require the * transfer buffers to live in their own cache lines. @@ -370,6 +382,123 @@ static int ad7768_set_dig_fil(struct ad7768_state *st, return ad7768_send_sync_pulse(st); } +static int ad7768_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) +{ + struct iio_dev *indio_dev = gpiochip_get_data(chip); + struct ad7768_state *st = iio_priv(indio_dev); + int ret; + + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + + ret = regmap_clear_bits(st->regmap, AD7768_REG_GPIO_CONTROL, + BIT(offset)); + iio_device_release_direct(indio_dev); + + return ret; +} + +static int ad7768_gpio_direction_output(struct gpio_chip *chip, + unsigned int offset, int value) +{ + struct iio_dev *indio_dev = gpiochip_get_data(chip); + struct ad7768_state *st = iio_priv(indio_dev); + int ret; + + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + + ret = regmap_set_bits(st->regmap, AD7768_REG_GPIO_CONTROL, + BIT(offset)); + iio_device_release_direct(indio_dev); + + return ret; +} + +static int ad7768_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct iio_dev *indio_dev = gpiochip_get_data(chip); + struct ad7768_state *st = iio_priv(indio_dev); + unsigned int val; + int ret; + + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + + ret = regmap_read(st->regmap, AD7768_REG_GPIO_CONTROL, &val); + if (ret) + goto err_release; + + /* + * If the GPIO is configured as an output, read the current value from + * AD7768_REG_GPIO_WRITE. Otherwise, read the input value from + * AD7768_REG_GPIO_READ. + */ + if (val & BIT(offset)) + ret = regmap_read(st->regmap, AD7768_REG_GPIO_WRITE, &val); + else + ret = regmap_read(st->regmap, AD7768_REG_GPIO_READ, &val); + if (ret) + goto err_release; + + ret = !!(val & BIT(offset)); +err_release: + iio_device_release_direct(indio_dev); + + return ret; +} + +static void ad7768_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) +{ + struct iio_dev *indio_dev = gpiochip_get_data(chip); + struct ad7768_state *st = iio_priv(indio_dev); + unsigned int val; + int ret; + + if (!iio_device_claim_direct(indio_dev)) + return; + + ret = regmap_read(st->regmap, AD7768_REG_GPIO_CONTROL, &val); + if (ret) + goto err_release; + + if (val & BIT(offset)) { + ret = regmap_assign_bits(st->regmap, AD7768_REG_GPIO_WRITE, + BIT(offset), value); + if (ret) + dev_err(&indio_dev->dev, "Failed to set GPIO %u: %d\n", offset, ret); + } + +err_release: + iio_device_release_direct(indio_dev); +} + +static int ad7768_gpio_init(struct iio_dev *indio_dev) +{ + struct ad7768_state *st = iio_priv(indio_dev); + int ret; + + ret = regmap_write(st->regmap, AD7768_REG_GPIO_CONTROL, + AD7768_GPIO_UNIVERSAL_EN); + if (ret) + return ret; + + st->gpiochip = (struct gpio_chip) { + .label = "ad7768_1_gpios", + .base = -1, + .ngpio = 4, + .parent = &st->spi->dev, + .can_sleep = true, + .direction_input = ad7768_gpio_direction_input, + .direction_output = ad7768_gpio_direction_output, + .get = ad7768_gpio_get, + .set = ad7768_gpio_set, + .owner = THIS_MODULE, + }; + + return devm_gpiochip_add_data(&st->spi->dev, &st->gpiochip, indio_dev); +} + static int ad7768_set_freq(struct ad7768_state *st, unsigned int freq) { @@ -511,8 +640,9 @@ static const struct iio_info ad7768_info = { .debugfs_reg_access = &ad7768_reg_access, }; -static int ad7768_setup(struct ad7768_state *st) +static int ad7768_setup(struct iio_dev *indio_dev) { + struct ad7768_state *st = iio_priv(indio_dev); int ret; st->gpio_reset = devm_gpiod_get_optional(&st->spi->dev, "reset", @@ -545,6 +675,13 @@ static int ad7768_setup(struct ad7768_state *st) if (IS_ERR(st->gpio_sync_in)) return PTR_ERR(st->gpio_sync_in); + /* Only create a Chip GPIO if flagged for it */ + if (device_property_read_bool(&st->spi->dev, "gpio-controller")) { + ret = ad7768_gpio_init(indio_dev); + if (ret) + return ret; + } + /* Set the default sampling frequency to 32000 kSPS */ return ad7768_set_freq(st, 32000); } @@ -885,7 +1022,7 @@ static int ad7768_probe(struct spi_device *spi) if (ret) return ret; - ret = ad7768_setup(st); + ret = ad7768_setup(indio_dev); if (ret < 0) { dev_err(&spi->dev, "AD7768 setup failed\n"); return ret; From c3d984ee160b43da5950fbf27bcf9a1cf564a183 Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Wed, 11 Jun 2025 08:51:11 -0300 Subject: [PATCH 23/46] iio: adc: ad7768-1: add multiple scan types to support 16-bits mode When the device is configured to decimation x8, only possible in the sinc5 filter, output data is reduced to 16 bits in order to support 1 MHz of sampling frequency due to clock limitation. Use multiple scan types feature to enable the driver to switch scan type at runtime, making it possible to support both 24-bit and 16-bit resolution. Reviewed-by: Marcelo Schmitt Reviewed-by: David Lechner Signed-off-by: Jonathan Santos Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/08780fd4a59885f1f250759ce655420bd1dbb383.1749569957.git.Jonathan.Santos@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7768-1.c | 74 ++++++++++++++++++++++++++++++++------ 1 file changed, 64 insertions(+), 10 deletions(-) diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index cc9a347f710910..fbdf92d194c8fe 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -140,6 +140,15 @@ struct ad7768_clk_configuration { enum ad7768_pwrmode pwrmode; }; +enum ad7768_scan_type { + AD7768_SCAN_TYPE_NORMAL, + AD7768_SCAN_TYPE_HIGH_SPEED, +}; + +static const int ad7768_mclk_div_rates[] = { + 16, 8, 4, 2, +}; + static const struct ad7768_clk_configuration ad7768_clk_config[] = { { AD7768_MCLK_DIV_2, AD7768_DEC_RATE_8, 16, AD7768_FAST_MODE }, { AD7768_MCLK_DIV_2, AD7768_DEC_RATE_16, 32, AD7768_FAST_MODE }, @@ -154,6 +163,22 @@ static const struct ad7768_clk_configuration ad7768_clk_config[] = { { AD7768_MCLK_DIV_16, AD7768_DEC_RATE_1024, 16384, AD7768_ECO_MODE }, }; +static const struct iio_scan_type ad7768_scan_type[] = { + [AD7768_SCAN_TYPE_NORMAL] = { + .sign = 's', + .realbits = 24, + .storagebits = 32, + .shift = 8, + .endianness = IIO_BE, + }, + [AD7768_SCAN_TYPE_HIGH_SPEED] = { + .sign = 's', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_BE, + }, +}; + static const struct iio_chan_spec ad7768_channels[] = { { .type = IIO_VOLTAGE, @@ -163,13 +188,9 @@ static const struct iio_chan_spec ad7768_channels[] = { .indexed = 1, .channel = 0, .scan_index = 0, - .scan_type = { - .sign = 's', - .realbits = 24, - .storagebits = 32, - .shift = 8, - .endianness = IIO_BE, - }, + .has_ext_scan_type = 1, + .ext_scan_type = ad7768_scan_type, + .num_ext_scan_type = ARRAY_SIZE(ad7768_scan_type), }, }; @@ -182,6 +203,7 @@ struct ad7768_state { unsigned int vcm_output_sel; struct clk *mclk; unsigned int mclk_freq; + unsigned int dec_rate; unsigned int samp_freq; struct completion completion; struct iio_trigger *trig; @@ -319,6 +341,15 @@ static int ad7768_scan_direct(struct iio_dev *indio_dev) if (ret) return ret; + /* + * When the decimation rate is set to x8, the ADC data precision is + * reduced from 24 bits to 16 bits. Since the AD7768_REG_ADC_DATA + * register provides 24-bit data, the precision is reduced by + * right-shifting the read value by 8 bits. + */ + if (st->dec_rate == 8) + readval >>= 8; + /* * Any SPI configuration of the AD7768-1 can only be * performed in continuous conversion mode. @@ -533,6 +564,8 @@ static int ad7768_set_freq(struct ad7768_state *st, if (ret < 0) return ret; + st->dec_rate = ad7768_clk_config[idx].clk_div / + ad7768_mclk_div_rates[ad7768_clk_config[idx].mclk_div]; st->samp_freq = DIV_ROUND_CLOSEST(st->mclk_freq, ad7768_clk_config[idx].clk_div); @@ -566,8 +599,13 @@ static int ad7768_read_raw(struct iio_dev *indio_dev, int *val, int *val2, long info) { struct ad7768_state *st = iio_priv(indio_dev); + const struct iio_scan_type *scan_type; int scale_uv, ret; + scan_type = iio_get_current_scan_type(indio_dev, chan); + if (IS_ERR(scan_type)) + return PTR_ERR(scan_type); + switch (info) { case IIO_CHAN_INFO_RAW: if (!iio_device_claim_direct(indio_dev)) @@ -578,7 +616,7 @@ static int ad7768_read_raw(struct iio_dev *indio_dev, iio_device_release_direct(indio_dev); if (ret < 0) return ret; - *val = sign_extend32(ret, chan->scan_type.realbits - 1); + *val = sign_extend32(ret, scan_type->realbits - 1); return IIO_VAL_INT; @@ -588,7 +626,7 @@ static int ad7768_read_raw(struct iio_dev *indio_dev, return scale_uv; *val = (scale_uv * 2) / 1000; - *val2 = chan->scan_type.realbits; + *val2 = scan_type->realbits; return IIO_VAL_FRACTIONAL_LOG2; @@ -632,11 +670,21 @@ static const struct attribute_group ad7768_group = { .attrs = ad7768_attributes, }; +static int ad7768_get_current_scan_type(const struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct ad7768_state *st = iio_priv(indio_dev); + + return st->dec_rate == 8 ? + AD7768_SCAN_TYPE_HIGH_SPEED : AD7768_SCAN_TYPE_NORMAL; +} + static const struct iio_info ad7768_info = { .attrs = &ad7768_group, .read_raw = &ad7768_read_raw, .write_raw = &ad7768_write_raw, .read_label = ad7768_read_label, + .get_current_scan_type = &ad7768_get_current_scan_type, .debugfs_reg_access = &ad7768_reg_access, }; @@ -691,9 +739,15 @@ static irqreturn_t ad7768_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct ad7768_state *st = iio_priv(indio_dev); + const struct iio_scan_type *scan_type; int ret; - ret = spi_read(st->spi, &st->data.scan.chan, 3); + scan_type = iio_get_current_scan_type(indio_dev, &indio_dev->channels[0]); + if (IS_ERR(scan_type)) + goto out; + + ret = spi_read(st->spi, &st->data.scan.chan, + BITS_TO_BYTES(scan_type->realbits)); if (ret < 0) goto out; From 65eb358dbceae2fde92c6c22a38b29d8c00d7b22 Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Wed, 11 Jun 2025 08:51:23 -0300 Subject: [PATCH 24/46] iio: adc: ad7768-1: add support for Synchronization over SPI The synchronization method using GPIO requires the generated pulse to be truly synchronous with the base MCLK signal. When it is not possible to do that in hardware, the datasheet recommends using synchronization over SPI, where the generated pulse is already synchronous with MCLK. This requires the SYNC_OUT pin to be connected to the SYNC_IN pin. Use trigger-sources property to enable device synchronization over SPI and multi-device synchronization while replacing sync-in-gpios property. Reviewed-by: David Lechner Signed-off-by: Jonathan Santos Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/05aea6d1551fce94f290d68f1dba548513e1632f.1749569957.git.Jonathan.Santos@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7768-1.c | 93 +++++++++++++++++++++++++++++++++++++- 1 file changed, 91 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index fbdf92d194c8fe..c14ba7061634ef 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -29,6 +29,8 @@ #include #include +#include + /* AD7768 registers definition */ #define AD7768_REG_CHIP_TYPE 0x3 #define AD7768_REG_PROD_ID_L 0x4 @@ -101,6 +103,8 @@ #define AD7768_VCM_OFF 0x07 +#define AD7768_TRIGGER_SOURCE_SYNC_IDX 0 + enum ad7768_conv_mode { AD7768_CONTINUOUS, AD7768_ONE_SHOT, @@ -211,6 +215,7 @@ struct ad7768_state { struct gpio_desc *gpio_reset; const char *labels[ARRAY_SIZE(ad7768_channels)]; struct gpio_chip gpiochip; + bool en_spi_sync; /* * DMA (thus cache coherency maintenance) may require the * transfer buffers to live in their own cache lines. @@ -298,6 +303,9 @@ static const struct regmap_config ad7768_regmap24_config = { static int ad7768_send_sync_pulse(struct ad7768_state *st) { + if (st->en_spi_sync) + return regmap_write(st->regmap, AD7768_REG_SYNC_RESET, 0x00); + /* * The datasheet specifies a minimum SYNC_IN pulse width of 1.5 × Tmclk, * where Tmclk is the MCLK period. The supported MCLK frequencies range @@ -688,6 +696,76 @@ static const struct iio_info ad7768_info = { .debugfs_reg_access = &ad7768_reg_access, }; +static struct fwnode_handle * +ad7768_fwnode_find_reference_args(const struct fwnode_handle *fwnode, + const char *name, const char *nargs_prop, + unsigned int nargs, unsigned int index, + struct fwnode_reference_args *args) +{ + int ret; + + ret = fwnode_property_get_reference_args(fwnode, name, nargs_prop, + nargs, index, args); + return ret ? ERR_PTR(ret) : args->fwnode; +} + +static int ad7768_trigger_sources_sync_setup(struct device *dev, + struct fwnode_handle *fwnode, + struct ad7768_state *st) +{ + struct fwnode_reference_args args; + + struct fwnode_handle *ref __free(fwnode_handle) = + ad7768_fwnode_find_reference_args(fwnode, "trigger-sources", + "#trigger-source-cells", 0, + AD7768_TRIGGER_SOURCE_SYNC_IDX, + &args); + if (IS_ERR(ref)) + return PTR_ERR(ref); + + ref = args.fwnode; + /* First, try getting the GPIO trigger source */ + if (fwnode_device_is_compatible(ref, "gpio-trigger")) { + st->gpio_sync_in = devm_fwnode_gpiod_get_index(dev, ref, NULL, 0, + GPIOD_OUT_LOW, + "sync-in"); + return PTR_ERR_OR_ZERO(st->gpio_sync_in); + } + + /* + * TODO: Support the other cases when we have a trigger subsystem + * to reliably handle other types of devices as trigger sources. + * + * For now, return an error message. For self triggering, omit the + * trigger-sources property. + */ + return dev_err_probe(dev, -EOPNOTSUPP, "Invalid synchronization trigger source\n"); +} + +static int ad7768_trigger_sources_get_sync(struct device *dev, + struct ad7768_state *st) +{ + struct fwnode_handle *fwnode = dev_fwnode(dev); + + /* + * The AD7768-1 allows two primary methods for driving the SYNC_IN pin + * to synchronize one or more devices: + * 1. Using an external GPIO. + * 2. Using a SPI command, where the SYNC_OUT pin generates a + * synchronization pulse that drives the SYNC_IN pin. + */ + if (fwnode_property_present(fwnode, "trigger-sources")) + return ad7768_trigger_sources_sync_setup(dev, fwnode, st); + + /* + * In the absence of trigger-sources property, enable self + * synchronization over SPI (SYNC_OUT). + */ + st->en_spi_sync = true; + + return 0; +} + static int ad7768_setup(struct iio_dev *indio_dev) { struct ad7768_state *st = iio_priv(indio_dev); @@ -718,11 +796,22 @@ static int ad7768_setup(struct iio_dev *indio_dev) return ret; } - st->gpio_sync_in = devm_gpiod_get(&st->spi->dev, "adi,sync-in", - GPIOD_OUT_LOW); + /* For backwards compatibility, try the adi,sync-in-gpios property */ + st->gpio_sync_in = devm_gpiod_get_optional(&st->spi->dev, "adi,sync-in", + GPIOD_OUT_LOW); if (IS_ERR(st->gpio_sync_in)) return PTR_ERR(st->gpio_sync_in); + /* + * If the synchronization is not defined by adi,sync-in-gpios, try the + * trigger-sources. + */ + if (!st->gpio_sync_in) { + ret = ad7768_trigger_sources_get_sync(&st->spi->dev, st); + if (ret) + return ret; + } + /* Only create a Chip GPIO if flagged for it */ if (device_property_read_bool(&st->spi->dev, "gpio-controller")) { ret = ad7768_gpio_init(indio_dev); From 7386794169c6a3aff52273688a0b23344d50d5e1 Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Wed, 11 Jun 2025 08:51:38 -0300 Subject: [PATCH 25/46] iio: adc: ad7768-1: replace manual attribute declaration Use read_avail callback from struct iio_info to replace the manual declaration of sampling_frequency_available attribute. Reviewed-by: David Lechner Reviewed-by: Marcelo Schmitt Signed-off-by: Jonathan Santos Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/b2653d270131b2c873373a6f81cde9a5bdf5d1ff.1749569957.git.Jonathan.Santos@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7768-1.c | 63 +++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index c14ba7061634ef..aad2ec45ac2a5d 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -189,6 +189,7 @@ static const struct iio_chan_spec ad7768_channels[] = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), .indexed = 1, .channel = 0, .scan_index = 0, @@ -209,6 +210,7 @@ struct ad7768_state { unsigned int mclk_freq; unsigned int dec_rate; unsigned int samp_freq; + unsigned int samp_freq_avail[ARRAY_SIZE(ad7768_clk_config)]; struct completion completion; struct iio_trigger *trig; struct gpio_desc *gpio_sync_in; @@ -322,6 +324,15 @@ static int ad7768_send_sync_pulse(struct ad7768_state *st) return 0; } +static void ad7768_fill_samp_freq_tbl(struct ad7768_state *st) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(ad7768_clk_config); i++) + st->samp_freq_avail[i] = + DIV_ROUND_CLOSEST(st->mclk_freq, ad7768_clk_config[i].clk_div); +} + static int ad7768_set_mode(struct ad7768_state *st, enum ad7768_conv_mode mode) { @@ -580,28 +591,6 @@ static int ad7768_set_freq(struct ad7768_state *st, return 0; } -static ssize_t ad7768_sampling_freq_avail(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ad7768_state *st = iio_priv(indio_dev); - unsigned int freq; - int i, len = 0; - - for (i = 0; i < ARRAY_SIZE(ad7768_clk_config); i++) { - freq = DIV_ROUND_CLOSEST(st->mclk_freq, - ad7768_clk_config[i].clk_div); - len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", freq); - } - - buf[len - 1] = '\n'; - - return len; -} - -static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(ad7768_sampling_freq_avail); - static int ad7768_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long info) @@ -647,6 +636,24 @@ static int ad7768_read_raw(struct iio_dev *indio_dev, return -EINVAL; } +static int ad7768_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long info) +{ + struct ad7768_state *st = iio_priv(indio_dev); + + switch (info) { + case IIO_CHAN_INFO_SAMP_FREQ: + *vals = (int *)st->samp_freq_avail; + *length = ARRAY_SIZE(ad7768_clk_config); + *type = IIO_VAL_INT; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + static int ad7768_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long info) @@ -669,15 +676,6 @@ static int ad7768_read_label(struct iio_dev *indio_dev, return sprintf(label, "%s\n", st->labels[chan->channel]); } -static struct attribute *ad7768_attributes[] = { - &iio_dev_attr_sampling_frequency_available.dev_attr.attr, - NULL -}; - -static const struct attribute_group ad7768_group = { - .attrs = ad7768_attributes, -}; - static int ad7768_get_current_scan_type(const struct iio_dev *indio_dev, const struct iio_chan_spec *chan) { @@ -688,8 +686,8 @@ static int ad7768_get_current_scan_type(const struct iio_dev *indio_dev, } static const struct iio_info ad7768_info = { - .attrs = &ad7768_group, .read_raw = &ad7768_read_raw, + .read_avail = &ad7768_read_avail, .write_raw = &ad7768_write_raw, .read_label = ad7768_read_label, .get_current_scan_type = &ad7768_get_current_scan_type, @@ -1153,6 +1151,7 @@ static int ad7768_probe(struct spi_device *spi) return PTR_ERR(st->mclk); st->mclk_freq = clk_get_rate(st->mclk); + ad7768_fill_samp_freq_tbl(st); indio_dev->channels = ad7768_channels; indio_dev->num_channels = ARRAY_SIZE(ad7768_channels); From 76e5730c339884c0bb0b477683523d477cb6658b Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Wed, 11 Jun 2025 08:51:50 -0300 Subject: [PATCH 26/46] iio: adc: ad7768-1: add filter type and oversampling ratio attributes Separate filter type and decimation rate from the sampling frequency attribute. The new filter type attribute enables sinc3, sinc3+rej60 and wideband filters, which were previously unavailable. Previously, combining decimation and MCLK divider in the sampling frequency obscured performance trade-offs. Lower MCLK divider settings increase power usage, while lower decimation rates reduce precision by decreasing averaging. By creating an oversampling attribute, which controls the decimation, users gain finer control over performance. The addition of those attributes allows a wider range of sampling frequencies and more access to the device features. Sampling frequency table is updated after every digital filter parameter change. Changes in the sampling frequency are not allowed anymore while in buffered mode. Reviewed-by: David Lechner Co-developed-by: Pop Paul Signed-off-by: Pop Paul Signed-off-by: Jonathan Santos Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/cd3b60c44847d5c35cecc4385bbda6533be6825e.1749569957.git.Jonathan.Santos@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7768-1.c | 414 ++++++++++++++++++++++++++++--------- 1 file changed, 319 insertions(+), 95 deletions(-) diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index aad2ec45ac2a5d..d9dfb13ee40e40 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include #include @@ -78,6 +80,7 @@ #define AD7768_PWR_PWRMODE(x) FIELD_PREP(AD7768_PWR_PWRMODE_MSK, x) /* AD7768_REG_DIGITAL_FILTER */ +#define AD7768_DIG_FIL_EN_60HZ_REJ BIT(7) #define AD7768_DIG_FIL_FIL_MSK GENMASK(6, 4) #define AD7768_DIG_FIL_FIL(x) FIELD_PREP(AD7768_DIG_FIL_FIL_MSK, x) #define AD7768_DIG_FIL_DEC_MSK GENMASK(2, 0) @@ -105,6 +108,8 @@ #define AD7768_TRIGGER_SOURCE_SYNC_IDX 0 +#define AD7768_MAX_CHANNELS 1 + enum ad7768_conv_mode { AD7768_CONTINUOUS, AD7768_ONE_SHOT, @@ -126,22 +131,20 @@ enum ad7768_mclk_div { AD7768_MCLK_DIV_2 }; -enum ad7768_dec_rate { - AD7768_DEC_RATE_32 = 0, - AD7768_DEC_RATE_64 = 1, - AD7768_DEC_RATE_128 = 2, - AD7768_DEC_RATE_256 = 3, - AD7768_DEC_RATE_512 = 4, - AD7768_DEC_RATE_1024 = 5, - AD7768_DEC_RATE_8 = 9, - AD7768_DEC_RATE_16 = 10 +enum ad7768_filter_type { + AD7768_FILTER_SINC5, + AD7768_FILTER_SINC3, + AD7768_FILTER_WIDEBAND, + AD7768_FILTER_SINC3_REJ60, }; -struct ad7768_clk_configuration { - enum ad7768_mclk_div mclk_div; - enum ad7768_dec_rate dec_rate; - unsigned int clk_div; - enum ad7768_pwrmode pwrmode; +enum ad7768_filter_regval { + AD7768_FILTER_REGVAL_SINC5 = 0, + AD7768_FILTER_REGVAL_SINC5_X8 = 1, + AD7768_FILTER_REGVAL_SINC5_X16 = 2, + AD7768_FILTER_REGVAL_SINC3 = 3, + AD7768_FILTER_REGVAL_WIDEBAND = 4, + AD7768_FILTER_REGVAL_SINC3_REJ60 = 11, }; enum ad7768_scan_type { @@ -153,18 +156,36 @@ static const int ad7768_mclk_div_rates[] = { 16, 8, 4, 2, }; -static const struct ad7768_clk_configuration ad7768_clk_config[] = { - { AD7768_MCLK_DIV_2, AD7768_DEC_RATE_8, 16, AD7768_FAST_MODE }, - { AD7768_MCLK_DIV_2, AD7768_DEC_RATE_16, 32, AD7768_FAST_MODE }, - { AD7768_MCLK_DIV_2, AD7768_DEC_RATE_32, 64, AD7768_FAST_MODE }, - { AD7768_MCLK_DIV_2, AD7768_DEC_RATE_64, 128, AD7768_FAST_MODE }, - { AD7768_MCLK_DIV_2, AD7768_DEC_RATE_128, 256, AD7768_FAST_MODE }, - { AD7768_MCLK_DIV_4, AD7768_DEC_RATE_128, 512, AD7768_MED_MODE }, - { AD7768_MCLK_DIV_4, AD7768_DEC_RATE_256, 1024, AD7768_MED_MODE }, - { AD7768_MCLK_DIV_4, AD7768_DEC_RATE_512, 2048, AD7768_MED_MODE }, - { AD7768_MCLK_DIV_4, AD7768_DEC_RATE_1024, 4096, AD7768_MED_MODE }, - { AD7768_MCLK_DIV_8, AD7768_DEC_RATE_1024, 8192, AD7768_MED_MODE }, - { AD7768_MCLK_DIV_16, AD7768_DEC_RATE_1024, 16384, AD7768_ECO_MODE }, +static const int ad7768_dec_rate_values[8] = { + 8, 16, 32, 64, 128, 256, 512, 1024, +}; + +/* Decimation rate range for sinc3 filter */ +static const int ad7768_sinc3_dec_rate_range[3] = { + 32, 32, 163840, +}; + +/* + * The AD7768-1 supports three primary filter types: + * Sinc5, Sinc3, and Wideband. + * However, the filter register values can also encode additional parameters + * such as decimation rates and 60Hz rejection. This utility array separates + * the filter type from these parameters. + */ +static const int ad7768_filter_regval_to_type[] = { + [AD7768_FILTER_REGVAL_SINC5] = AD7768_FILTER_SINC5, + [AD7768_FILTER_REGVAL_SINC5_X8] = AD7768_FILTER_SINC5, + [AD7768_FILTER_REGVAL_SINC5_X16] = AD7768_FILTER_SINC5, + [AD7768_FILTER_REGVAL_SINC3] = AD7768_FILTER_SINC3, + [AD7768_FILTER_REGVAL_WIDEBAND] = AD7768_FILTER_WIDEBAND, + [AD7768_FILTER_REGVAL_SINC3_REJ60] = AD7768_FILTER_SINC3_REJ60, +}; + +static const char * const ad7768_filter_enum[] = { + [AD7768_FILTER_SINC5] = "sinc5", + [AD7768_FILTER_SINC3] = "sinc3", + [AD7768_FILTER_WIDEBAND] = "wideband", + [AD7768_FILTER_SINC3_REJ60] = "sinc3+rej60", }; static const struct iio_scan_type ad7768_scan_type[] = { @@ -183,22 +204,6 @@ static const struct iio_scan_type ad7768_scan_type[] = { }, }; -static const struct iio_chan_spec ad7768_channels[] = { - { - .type = IIO_VOLTAGE, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), - .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), - .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), - .indexed = 1, - .channel = 0, - .scan_index = 0, - .has_ext_scan_type = 1, - .ext_scan_type = ad7768_scan_type, - .num_ext_scan_type = ARRAY_SIZE(ad7768_scan_type), - }, -}; - struct ad7768_state { struct spi_device *spi; struct regmap *regmap; @@ -208,14 +213,17 @@ struct ad7768_state { unsigned int vcm_output_sel; struct clk *mclk; unsigned int mclk_freq; - unsigned int dec_rate; + unsigned int mclk_div; + unsigned int oversampling_ratio; + enum ad7768_filter_type filter_type; unsigned int samp_freq; - unsigned int samp_freq_avail[ARRAY_SIZE(ad7768_clk_config)]; + unsigned int samp_freq_avail[ARRAY_SIZE(ad7768_mclk_div_rates)]; + unsigned int samp_freq_avail_len; struct completion completion; struct iio_trigger *trig; struct gpio_desc *gpio_sync_in; struct gpio_desc *gpio_reset; - const char *labels[ARRAY_SIZE(ad7768_channels)]; + const char *labels[AD7768_MAX_CHANNELS]; struct gpio_chip gpiochip; bool en_spi_sync; /* @@ -326,11 +334,38 @@ static int ad7768_send_sync_pulse(struct ad7768_state *st) static void ad7768_fill_samp_freq_tbl(struct ad7768_state *st) { - unsigned int i; + unsigned int i, samp_freq_avail, freq_filtered; + unsigned int len = 0; + + freq_filtered = DIV_ROUND_CLOSEST(st->mclk_freq, st->oversampling_ratio); + for (i = 0; i < ARRAY_SIZE(ad7768_mclk_div_rates); i++) { + samp_freq_avail = DIV_ROUND_CLOSEST(freq_filtered, ad7768_mclk_div_rates[i]); + /* Sampling frequency cannot be lower than the minimum of 50 SPS */ + if (samp_freq_avail < 50) + continue; - for (i = 0; i < ARRAY_SIZE(ad7768_clk_config); i++) - st->samp_freq_avail[i] = - DIV_ROUND_CLOSEST(st->mclk_freq, ad7768_clk_config[i].clk_div); + st->samp_freq_avail[len++] = samp_freq_avail; + } + + st->samp_freq_avail_len = len; +} + +static int ad7768_set_mclk_div(struct ad7768_state *st, unsigned int mclk_div) +{ + unsigned int mclk_div_value; + + mclk_div_value = AD7768_PWR_MCLK_DIV(mclk_div); + /* + * Set power mode based on mclk_div value. + * ECO_MODE is only recommended for MCLK_DIV = 16. + */ + mclk_div_value |= mclk_div > AD7768_MCLK_DIV_16 ? + AD7768_PWR_PWRMODE(AD7768_FAST_MODE) : + AD7768_PWR_PWRMODE(AD7768_ECO_MODE); + + return regmap_update_bits(st->regmap, AD7768_REG_POWER_CLOCK, + AD7768_PWR_MCLK_DIV_MSK | AD7768_PWR_PWRMODE_MSK, + mclk_div_value); } static int ad7768_set_mode(struct ad7768_state *st, @@ -366,7 +401,7 @@ static int ad7768_scan_direct(struct iio_dev *indio_dev) * register provides 24-bit data, the precision is reduced by * right-shifting the read value by 8 bits. */ - if (st->dec_rate == 8) + if (st->oversampling_ratio == 8) readval >>= 8; /* @@ -413,22 +448,110 @@ static int ad7768_reg_access(struct iio_dev *indio_dev, return ret; } -static int ad7768_set_dig_fil(struct ad7768_state *st, - enum ad7768_dec_rate dec_rate) +static int ad7768_set_sinc3_dec_rate(struct ad7768_state *st, + unsigned int dec_rate) { - unsigned int mode; + unsigned int max_dec_rate; + u8 dec_rate_reg[2]; + u16 regval; int ret; - if (dec_rate == AD7768_DEC_RATE_8 || dec_rate == AD7768_DEC_RATE_16) - mode = AD7768_DIG_FIL_FIL(dec_rate); - else - mode = AD7768_DIG_FIL_DEC_RATE(dec_rate); + /* + * Maximum dec_rate is limited by the MCLK_DIV value and by the ODR. + * The edge case is for MCLK_DIV = 2, ODR = 50 SPS. + * max_dec_rate <= MCLK / (2 * 50) + */ + max_dec_rate = st->mclk_freq / 100; + dec_rate = clamp(dec_rate, 32, max_dec_rate); + /* + * Calculate the equivalent value to sinc3 decimation ratio + * to be written on the SINC3_DEC_RATE register: + * Value = (DEC_RATE / 32) - 1 + */ + dec_rate = DIV_ROUND_UP(dec_rate, 32) - 1; - ret = regmap_write(st->regmap, AD7768_REG_DIGITAL_FILTER, mode); - if (ret < 0) + /* + * The SINC3_DEC_RATE value is a 13-bit value split across two + * registers: MSB [12:8] and LSB [7:0]. Prepare the 13-bit value using + * FIELD_PREP() and store it with the right endianness in dec_rate_reg. + */ + regval = FIELD_PREP(GENMASK(12, 0), dec_rate); + put_unaligned_be16(regval, dec_rate_reg); + ret = regmap_bulk_write(st->regmap, AD7768_REG_SINC3_DEC_RATE_MSB, + dec_rate_reg, 2); + if (ret) + return ret; + + st->oversampling_ratio = (dec_rate + 1) * 32; + + return 0; +} + +static int ad7768_configure_dig_fil(struct iio_dev *dev, + enum ad7768_filter_type filter_type, + unsigned int dec_rate) +{ + struct ad7768_state *st = iio_priv(dev); + unsigned int dec_rate_idx, dig_filter_regval; + int ret; + + switch (filter_type) { + case AD7768_FILTER_SINC3: + dig_filter_regval = AD7768_DIG_FIL_FIL(AD7768_FILTER_REGVAL_SINC3); + break; + case AD7768_FILTER_SINC3_REJ60: + dig_filter_regval = AD7768_DIG_FIL_FIL(AD7768_FILTER_REGVAL_SINC3) | + AD7768_DIG_FIL_EN_60HZ_REJ; + break; + case AD7768_FILTER_WIDEBAND: + /* Skip decimations 8 and 16, not supported by the wideband filter */ + dec_rate_idx = find_closest(dec_rate, &ad7768_dec_rate_values[2], + ARRAY_SIZE(ad7768_dec_rate_values) - 2); + dig_filter_regval = AD7768_DIG_FIL_FIL(AD7768_FILTER_REGVAL_WIDEBAND) | + AD7768_DIG_FIL_DEC_RATE(dec_rate_idx); + /* Correct the index offset */ + dec_rate_idx += 2; + break; + case AD7768_FILTER_SINC5: + dec_rate_idx = find_closest(dec_rate, ad7768_dec_rate_values, + ARRAY_SIZE(ad7768_dec_rate_values)); + + /* + * Decimations 8 (idx 0) and 16 (idx 1) are set in the + * FILTER[6:4] field. The other decimations are set in the + * DEC_RATE[2:0] field, and the idx needs to be offsetted by two. + */ + if (dec_rate_idx == 0) + dig_filter_regval = AD7768_DIG_FIL_FIL(AD7768_FILTER_REGVAL_SINC5_X8); + else if (dec_rate_idx == 1) + dig_filter_regval = AD7768_DIG_FIL_FIL(AD7768_FILTER_REGVAL_SINC5_X16); + else + dig_filter_regval = AD7768_DIG_FIL_FIL(AD7768_FILTER_REGVAL_SINC5) | + AD7768_DIG_FIL_DEC_RATE(dec_rate_idx - 2); + break; + } + + ret = regmap_write(st->regmap, AD7768_REG_DIGITAL_FILTER, dig_filter_regval); + if (ret) return ret; - /* A sync-in pulse is required every time the filter dec rate changes */ + st->filter_type = filter_type; + /* + * The decimation for SINC3 filters are configured in different + * registers. + */ + if (filter_type == AD7768_FILTER_SINC3 || + filter_type == AD7768_FILTER_SINC3_REJ60) { + ret = ad7768_set_sinc3_dec_rate(st, dec_rate); + if (ret) + return ret; + } else { + st->oversampling_ratio = ad7768_dec_rate_values[dec_rate_idx]; + } + + ad7768_fill_samp_freq_tbl(st); + + /* A sync-in pulse is required after every configuration change */ return ad7768_send_sync_pulse(st); } @@ -552,45 +675,92 @@ static int ad7768_gpio_init(struct iio_dev *indio_dev) static int ad7768_set_freq(struct ad7768_state *st, unsigned int freq) { - unsigned int diff_new, diff_old, pwr_mode, i, idx; - int res, ret; - - diff_old = U32_MAX; - idx = 0; + unsigned int idx, mclk_div; + int ret; - res = DIV_ROUND_CLOSEST(st->mclk_freq, freq); + freq = clamp(freq, 50, 1024000); + if (freq == 0) + return -EINVAL; + mclk_div = DIV_ROUND_CLOSEST(st->mclk_freq, freq * st->oversampling_ratio); /* Find the closest match for the desired sampling frequency */ - for (i = 0; i < ARRAY_SIZE(ad7768_clk_config); i++) { - diff_new = abs(res - ad7768_clk_config[i].clk_div); - if (diff_new < diff_old) { - diff_old = diff_new; - idx = i; - } - } - - /* - * Set both the mclk_div and pwrmode with a single write to the - * POWER_CLOCK register - */ - pwr_mode = AD7768_PWR_MCLK_DIV(ad7768_clk_config[idx].mclk_div) | - AD7768_PWR_PWRMODE(ad7768_clk_config[idx].pwrmode); - ret = regmap_write(st->regmap, AD7768_REG_POWER_CLOCK, pwr_mode); - if (ret < 0) + idx = find_closest_descending(mclk_div, ad7768_mclk_div_rates, + ARRAY_SIZE(ad7768_mclk_div_rates)); + /* Set both the mclk_div and pwrmode */ + ret = ad7768_set_mclk_div(st, idx); + if (ret) return ret; - ret = ad7768_set_dig_fil(st, ad7768_clk_config[idx].dec_rate); - if (ret < 0) + st->samp_freq = DIV_ROUND_CLOSEST(st->mclk_freq, + ad7768_mclk_div_rates[idx] * st->oversampling_ratio); + + /* A sync-in pulse is required after every configuration change */ + return ad7768_send_sync_pulse(st); +} + +static int ad7768_set_filter_type_attr(struct iio_dev *dev, + const struct iio_chan_spec *chan, + unsigned int filter) +{ + struct ad7768_state *st = iio_priv(dev); + int ret; + + ret = ad7768_configure_dig_fil(dev, filter, st->oversampling_ratio); + if (ret) return ret; - st->dec_rate = ad7768_clk_config[idx].clk_div / - ad7768_mclk_div_rates[ad7768_clk_config[idx].mclk_div]; - st->samp_freq = DIV_ROUND_CLOSEST(st->mclk_freq, - ad7768_clk_config[idx].clk_div); + /* Update sampling frequency */ + return ad7768_set_freq(st, st->samp_freq); +} - return 0; +static int ad7768_get_filter_type_attr(struct iio_dev *dev, + const struct iio_chan_spec *chan) +{ + struct ad7768_state *st = iio_priv(dev); + int ret; + unsigned int mode, mask; + + ret = regmap_read(st->regmap, AD7768_REG_DIGITAL_FILTER, &mode); + if (ret) + return ret; + + mask = AD7768_DIG_FIL_EN_60HZ_REJ | AD7768_DIG_FIL_FIL_MSK; + /* From the register value, get the corresponding filter type */ + return ad7768_filter_regval_to_type[FIELD_GET(mask, mode)]; } +static const struct iio_enum ad7768_filter_type_iio_enum = { + .items = ad7768_filter_enum, + .num_items = ARRAY_SIZE(ad7768_filter_enum), + .set = ad7768_set_filter_type_attr, + .get = ad7768_get_filter_type_attr, +}; + +static const struct iio_chan_spec_ext_info ad7768_ext_info[] = { + IIO_ENUM("filter_type", IIO_SHARED_BY_ALL, &ad7768_filter_type_iio_enum), + IIO_ENUM_AVAILABLE("filter_type", IIO_SHARED_BY_ALL, &ad7768_filter_type_iio_enum), + { } +}; + +static const struct iio_chan_spec ad7768_channels[] = { + { + .type = IIO_VOLTAGE, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), + .ext_info = ad7768_ext_info, + .indexed = 1, + .channel = 0, + .scan_index = 0, + .has_ext_scan_type = 1, + .ext_scan_type = ad7768_scan_type, + .num_ext_scan_type = ARRAY_SIZE(ad7768_scan_type), + }, +}; + static int ad7768_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long info) @@ -630,6 +800,11 @@ static int ad7768_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_SAMP_FREQ: *val = st->samp_freq; + return IIO_VAL_INT; + + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + *val = st->oversampling_ratio; + return IIO_VAL_INT; } @@ -642,11 +817,29 @@ static int ad7768_read_avail(struct iio_dev *indio_dev, long info) { struct ad7768_state *st = iio_priv(indio_dev); + unsigned int shift; switch (info) { + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + /* + * Sinc3 filter allows a wider range of OSR values, so show + * the available values in range format. + */ + if (st->filter_type == AD7768_FILTER_SINC3 || + st->filter_type == AD7768_FILTER_SINC3_REJ60) { + *vals = (int *)ad7768_sinc3_dec_rate_range; + *type = IIO_VAL_INT; + return IIO_AVAIL_RANGE; + } + + shift = st->filter_type == AD7768_FILTER_SINC5 ? 0 : 2; + *vals = (int *)&ad7768_dec_rate_values[shift]; + *length = ARRAY_SIZE(ad7768_dec_rate_values) - shift; + *type = IIO_VAL_INT; + return IIO_AVAIL_LIST; case IIO_CHAN_INFO_SAMP_FREQ: *vals = (int *)st->samp_freq_avail; - *length = ARRAY_SIZE(ad7768_clk_config); + *length = st->samp_freq_avail_len; *type = IIO_VAL_INT; return IIO_AVAIL_LIST; default: @@ -654,20 +847,44 @@ static int ad7768_read_avail(struct iio_dev *indio_dev, } } -static int ad7768_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, int val2, long info) +static int __ad7768_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long info) { struct ad7768_state *st = iio_priv(indio_dev); + int ret; switch (info) { case IIO_CHAN_INFO_SAMP_FREQ: return ad7768_set_freq(st, val); + + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + ret = ad7768_configure_dig_fil(indio_dev, st->filter_type, val); + if (ret) + return ret; + + /* Update sampling frequency */ + return ad7768_set_freq(st, st->samp_freq); default: return -EINVAL; } } +static int ad7768_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long info) +{ + int ret; + + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + + ret = __ad7768_write_raw(indio_dev, chan, val, val2, info); + iio_device_release_direct(indio_dev); + + return ret; +} + static int ad7768_read_label(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, char *label) { @@ -681,7 +898,7 @@ static int ad7768_get_current_scan_type(const struct iio_dev *indio_dev, { struct ad7768_state *st = iio_priv(indio_dev); - return st->dec_rate == 8 ? + return st->oversampling_ratio == 8 ? AD7768_SCAN_TYPE_HIGH_SPEED : AD7768_SCAN_TYPE_NORMAL; } @@ -817,6 +1034,14 @@ static int ad7768_setup(struct iio_dev *indio_dev) return ret; } + /* + * Set Default Digital Filter configuration: + * SINC5 filter with x32 Decimation rate + */ + ret = ad7768_configure_dig_fil(indio_dev, AD7768_FILTER_SINC5, 32); + if (ret) + return ret; + /* Set the default sampling frequency to 32000 kSPS */ return ad7768_set_freq(st, 32000); } @@ -1151,7 +1376,6 @@ static int ad7768_probe(struct spi_device *spi) return PTR_ERR(st->mclk); st->mclk_freq = clk_get_rate(st->mclk); - ad7768_fill_samp_freq_tbl(st); indio_dev->channels = ad7768_channels; indio_dev->num_channels = ARRAY_SIZE(ad7768_channels); From f35f69d12651784907697e86deb8fb38801c6213 Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Wed, 11 Jun 2025 08:52:03 -0300 Subject: [PATCH 27/46] iio: adc: ad7768-1: add low pass -3dB cutoff attribute Ad7768-1 has a different -3db frequency multiplier depending on the filter type configured. The cutoff frequency also varies according to the current ODR. Add a readonly low pass -3dB frequency cutoff attribute to clarify to the user which bandwidth is being allowed depending on the filter configurations. Reviewed-by: Marcelo Schmitt Reviewed-by: David Lechner Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Santos Link: https://patch.msgid.link/804d66f1858014d7278aec3344d81c223661e878.1749569957.git.Jonathan.Santos@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7768-1.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index d9dfb13ee40e40..052683d279d4c1 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -152,6 +153,14 @@ enum ad7768_scan_type { AD7768_SCAN_TYPE_HIGH_SPEED, }; +/* -3dB cutoff frequency multipliers (relative to ODR) for each filter type. */ +static const int ad7768_filter_3db_odr_multiplier[] = { + [AD7768_FILTER_SINC5] = 204, /* 0.204 */ + [AD7768_FILTER_SINC3] = 262, /* 0.2617 */ + [AD7768_FILTER_SINC3_REJ60] = 262, /* 0.2617 */ + [AD7768_FILTER_WIDEBAND] = 433, /* 0.433 */ +}; + static const int ad7768_mclk_div_rates[] = { 16, 8, 4, 2, }; @@ -747,6 +756,7 @@ static const struct iio_chan_spec ad7768_channels[] = { .type = IIO_VOLTAGE, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), @@ -767,7 +777,7 @@ static int ad7768_read_raw(struct iio_dev *indio_dev, { struct ad7768_state *st = iio_priv(indio_dev); const struct iio_scan_type *scan_type; - int scale_uv, ret; + int scale_uv, ret, temp; scan_type = iio_get_current_scan_type(indio_dev, chan); if (IS_ERR(scan_type)) @@ -805,6 +815,12 @@ static int ad7768_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_OVERSAMPLING_RATIO: *val = st->oversampling_ratio; + return IIO_VAL_INT; + + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: + temp = st->samp_freq * ad7768_filter_3db_odr_multiplier[st->filter_type]; + *val = DIV_ROUND_CLOSEST(temp, MILLI); + return IIO_VAL_INT; } From 0aaba3aa0812ef46455f11cf9ed39d4528de9c1c Mon Sep 17 00:00:00 2001 From: Chandra Mohan Sundar Date: Sat, 16 Aug 2025 19:07:55 +0530 Subject: [PATCH 28/46] iio: adc: ad7768-1: Remove logically dead code The clamp macro returns a value within the specified range. In ad7768_set_freq(), the value returned from clamp() is checked against zero, which is not possible since the value would always be between 50 and 1024000. Removed the 'if' check. This issue was reported by static coverity analyser as logically dead code. Signed-off-by: Chandra Mohan Sundar Link: https://patch.msgid.link/20250816133757.98624-1-chandramohan.explore@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7768-1.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index 052683d279d4c1..5a14da75ec0a8a 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -688,8 +688,6 @@ static int ad7768_set_freq(struct ad7768_state *st, int ret; freq = clamp(freq, 50, 1024000); - if (freq == 0) - return -EINVAL; mclk_div = DIV_ROUND_CLOSEST(st->mclk_freq, freq * st->oversampling_ratio); /* Find the closest match for the desired sampling frequency */ From c162b7859a6e369e45a0115b52ca7ab4f56118f0 Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Sun, 24 Aug 2025 01:10:03 -0300 Subject: [PATCH 29/46] iio: adc: ad7768-1: use devm_regulator_get_enable_read_voltage() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use devm_regulator_get_enable_read_voltage() function as a standard and concise way of reading the voltage from the regulator and keep the regulator enabled. Replace the regulator descriptor with the direct voltage value in the device struct. Reviewed-by: Nuno Sá Reviewed-by: Marcelo Schmitt Signed-off-by: Jonathan Santos Link: https://patch.msgid.link/20250824041003.9727-1-Jonathan.Santos@analog.com Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7768-1.c | 35 ++++++++--------------------------- 1 file changed, 8 insertions(+), 27 deletions(-) diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index 5a14da75ec0a8a..713978fc2d99fe 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -217,7 +217,7 @@ struct ad7768_state { struct spi_device *spi; struct regmap *regmap; struct regmap *regmap24; - struct regulator *vref; + int vref_uv; struct regulator_dev *vcm_rdev; unsigned int vcm_output_sel; struct clk *mclk; @@ -775,7 +775,7 @@ static int ad7768_read_raw(struct iio_dev *indio_dev, { struct ad7768_state *st = iio_priv(indio_dev); const struct iio_scan_type *scan_type; - int scale_uv, ret, temp; + int ret, temp; scan_type = iio_get_current_scan_type(indio_dev, chan); if (IS_ERR(scan_type)) @@ -796,11 +796,7 @@ static int ad7768_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - scale_uv = regulator_get_voltage(st->vref); - if (scale_uv < 0) - return scale_uv; - - *val = (scale_uv * 2) / 1000; + *val = (st->vref_uv * 2) / 1000; *val2 = scan_type->realbits; return IIO_VAL_FRACTIONAL_LOG2; @@ -1133,13 +1129,6 @@ static const struct iio_trigger_ops ad7768_trigger_ops = { .validate_device = iio_trigger_validate_own_device, }; -static void ad7768_regulator_disable(void *data) -{ - struct ad7768_state *st = data; - - regulator_disable(st->vref); -} - static int ad7768_set_channel_label(struct iio_dev *indio_dev, int num_channels) { @@ -1371,19 +1360,11 @@ static int ad7768_probe(struct spi_device *spi) return dev_err_probe(&spi->dev, PTR_ERR(st->regmap24), "Failed to initialize regmap24"); - st->vref = devm_regulator_get(&spi->dev, "vref"); - if (IS_ERR(st->vref)) - return PTR_ERR(st->vref); - - ret = regulator_enable(st->vref); - if (ret) { - dev_err(&spi->dev, "Failed to enable specified vref supply\n"); - return ret; - } - - ret = devm_add_action_or_reset(&spi->dev, ad7768_regulator_disable, st); - if (ret) - return ret; + ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref"); + if (ret < 0) + return dev_err_probe(&spi->dev, ret, + "Failed to get VREF voltage\n"); + st->vref_uv = ret; st->mclk = devm_clk_get_enabled(&spi->dev, "mclk"); if (IS_ERR(st->mclk)) From 5429f33cc46eb6025b67c4c494e16a600a7d53ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Tue, 30 Sep 2025 16:33:11 +0100 Subject: [PATCH 30/46] iio: adc: ad7768-1: replace sprintf() with sysfs_emit() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update the ad7768_read_label() function to use sysfs_emit(() for generating labels. Signed-off-by: Nuno Sá Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7768-1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index 713978fc2d99fe..f550d29b1aecef 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -900,7 +900,7 @@ static int ad7768_read_label(struct iio_dev *indio_dev, { struct ad7768_state *st = iio_priv(indio_dev); - return sprintf(label, "%s\n", st->labels[chan->channel]); + return sysfs_emit(label, "%s\n", st->labels[chan->channel]); } static int ad7768_get_current_scan_type(const struct iio_dev *indio_dev, From 2952638f273f4f876bccc7e01bbfd2052fa37702 Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Wed, 14 Jan 2026 06:26:39 -0300 Subject: [PATCH 31/46] dt-bindings: iio: adc: ad7768-1: add new supported parts Add compatibles for supported parts in the ad7768-1 family: ADAQ7767-1, ADAQ7768-1 and ADAQ7769-1 Add property and checks for AFF gain, supported by ADAQ7767-1 and ADAQ7769-1, and for PGA gain, supported by ADAQ7768-1 and ADAQ7769-1: adi,aaf-gain-bp pga-gpios Reviewed-by: Krzysztof Kozlowski Signed-off-by: Jonathan Santos Signed-off-by: Jonathan Cameron --- .../bindings/iio/adc/adi,ad7768-1.yaml | 64 +++++++++++++++++-- 1 file changed, 60 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.yaml index c06d0fc791d393..dfa2d7fa9fb37e 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.yaml @@ -4,18 +4,26 @@ $id: http://devicetree.org/schemas/iio/adc/adi,ad7768-1.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Analog Devices AD7768-1 ADC device driver +title: Analog Devices AD7768-1 ADC family maintainers: - Michael Hennerich description: | - Datasheet at: - https://www.analog.com/media/en/technical-documentation/data-sheets/ad7768-1.pdf + Analog Devices AD7768-1 24-Bit Single Channel Low Power sigma-delta ADC family + + https://www.analog.com/media/en/technical-documentation/data-sheets/ad7768-1.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/adaq7767-1.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/adaq7768-1.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/adaq7769-1.pdf properties: compatible: - const: adi,ad7768-1 + enum: + - adi,ad7768-1 + - adi,adaq7767-1 + - adi,adaq7768-1 + - adi,adaq7769-1 reg: maxItems: 1 @@ -58,6 +66,25 @@ properties: description: ADC reference voltage supply + adi,aaf-gain-bp: + description: | + Specifies the gain applied by the Analog Anti-Aliasing Filter (AAF) + to the ADC input in basis points (one hundredth of a percent). + The hardware gain is determined by which input pin(s) the signal goes + through into the AAF. The possible connections are: + * For the ADAQ7767-1: Input connected to IN1±, IN2± or IN3±. + * For the ADAQ7769-1: OUT_PGA pin connected to IN1_AAF+, IN2_AAF+, + or IN3_AAF+. + enum: [1430, 3640, 10000] + default: 10000 + + pga-gpios: + description: + GAIN 0, GAIN1 and GAIN2 pins for gain selection. For devices that have + PGA configuration input pins, pga-gpios must be defined. + minItems: 3 + maxItems: 3 + adi,sync-in-gpios: maxItems: 1 description: @@ -147,6 +174,35 @@ patternProperties: allOf: - $ref: /schemas/spi/spi-peripheral-props.yaml# + # AAF Gain property only applies to ADAQ7767-1 and ADAQ7769-1 devices + - if: + properties: + compatible: + contains: + enum: + - adi,adaq7767-1 + - adi,adaq7769-1 + then: + required: + - adi,aaf-gain-bp + else: + properties: + adi,aaf-gain-bp: false + + - if: + properties: + compatible: + contains: + enum: + - adi,adaq7768-1 + - adi,adaq7769-1 + then: + required: + - pga-gpios + else: + properties: + pga-gpios: false + unevaluatedProperties: false examples: From 522c60a15ec53ddf001cd15710e88d7b0a990880 Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Mon, 2 Mar 2026 12:58:03 -0300 Subject: [PATCH 32/46] arm: dts: zynq-zed-adv7511-ad7768-1-evb: support new features update devicetree to support the new spi-engine implementation and regulator provider property. while at it, add channel description. Signed-off-by: Jonathan Santos --- .../xilinx/zynq-zed-adv7511-ad7768-1-evb.dts | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/xilinx/zynq-zed-adv7511-ad7768-1-evb.dts b/arch/arm/boot/dts/xilinx/zynq-zed-adv7511-ad7768-1-evb.dts index 90e378dd2cd4c4..ae837dddc046c1 100644 --- a/arch/arm/boot/dts/xilinx/zynq-zed-adv7511-ad7768-1-evb.dts +++ b/arch/arm/boot/dts/xilinx/zynq-zed-adv7511-ad7768-1-evb.dts @@ -15,6 +15,8 @@ #include #include +#include + / { vref: regulator-vref { compatible = "regulator-fixed"; @@ -31,6 +33,12 @@ clock-frequency = <16384000>; }; }; + + sync_trigger: triggers { + compatible = "gpio-trigger"; + #trigger-source-cells = <0>; + gpios = <&gpio0 88 GPIO_ACTIVE_LOW>; + }; }; &fpga_axi { @@ -52,7 +60,7 @@ }; axi_spi_engine_0: spi@44a00000 { - compatible = "adi,legacy-axi-spi-engine-1.00.a"; + compatible = "adi,axi-spi-engine-1.00.a"; reg = <0x44a00000 0x1000>; interrupt-parent = <&intc>; interrupts = <0 56 IRQ_TYPE_LEVEL_HIGH>; @@ -60,6 +68,10 @@ clock-names = "s_axi_aclk", "spi_clk"; num-cs = <1>; + trigger-sources = <&ad7768_1 AD7768_TRIGGER_SOURCE_DRDY>; + dmas = <&rx_dma 0>; + dma-names = "offload0-rx"; + #address-cells = <0x1>; #size-cells = <0x0>; @@ -70,13 +82,27 @@ spi-cpol; spi-cpha; vref-supply = <&vref>; - adi,sync-in-gpios = <&gpio0 88 GPIO_ACTIVE_LOW>; + gpio-controller; + interrupts = <93 IRQ_TYPE_EDGE_RISING>; + interrupt-parent = <&gpio0>; + trigger-sources = <&sync_trigger>; reset-gpios = <&gpio0 86 GPIO_ACTIVE_LOW>; clocks = <&ad7768_1_mclk>; clock-names = "mclk"; - dmas = <&rx_dma 0>; - dma-names = "rx"; + #trigger-source-cells = <1>; #io-channel-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + regulators { + vcm_reg: vcm-output { + regulator-name = "ad7768-1-vcm"; + }; + }; + + channel@0 { + reg = <0>; + label = "channel_0"; + }; }; }; }; From 15ad0fa5f9cec2a807cb6a047417ff643e93eb13 Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Fri, 27 Mar 2026 17:33:50 -0300 Subject: [PATCH 33/46] arm: dts: zynq-coraz7s-cn0540: update to support new features update devicetree to support the new spi-engine implementation and regulator provider property. while at it, add channel description. Signed-off-by: Jonathan Santos --- .../boot/dts/xilinx/zynq-coraz7s-cn0540.dts | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/arch/arm/boot/dts/xilinx/zynq-coraz7s-cn0540.dts b/arch/arm/boot/dts/xilinx/zynq-coraz7s-cn0540.dts index d1bdd7698182c0..aee9bbe55d3a7a 100644 --- a/arch/arm/boot/dts/xilinx/zynq-coraz7s-cn0540.dts +++ b/arch/arm/boot/dts/xilinx/zynq-coraz7s-cn0540.dts @@ -17,6 +17,8 @@ #include #include +#include + / { vref: regulator-vref { compatible = "regulator-fixed"; @@ -120,7 +122,7 @@ }; axi_spi_engine_0: spi@44a00000 { - compatible = "adi,legacy-axi-spi-engine-1.00.a"; + compatible = "adi,axi-spi-engine-1.00.a"; reg = <0x44a00000 0x10000>; interrupt-parent = <&intc>; interrupts = <0 56 IRQ_TYPE_LEVEL_HIGH>; @@ -128,6 +130,10 @@ clock-names = "s_axi_aclk", "spi_clk"; num-cs = <1>; + trigger-sources = <&ad7768_1 AD7768_TRIGGER_SOURCE_DRDY>; + dmas = <&rx_dma 0>; + dma-names = "offload0-rx"; + #address-cells = <0x1>; #size-cells = <0x0>; @@ -140,13 +146,27 @@ vref-supply = <&vref>; #gpio-cells = <2>; gpio-controller; + interrupts = <99 IRQ_TYPE_EDGE_RISING>; + interrupt-parent = <&gpio0>; adi,sync-in-gpios = <&gpio0 87 GPIO_ACTIVE_LOW>; reset-gpios = <&gpio0 93 GPIO_ACTIVE_LOW>; clocks = <&ad7768_1_mclk>; clock-names = "mclk"; - dmas = <&rx_dma 0>; - dma-names = "rx"; + #trigger-source-cells = <1>; #io-channel-cells = <1>; + + #address-cells = <1>; + #size-cells = <0>; + regulators { + vcm_reg: vcm-output { + regulator-name = "ad7768-1-vcm"; + }; + }; + + channel@0 { + reg = <0>; + label = "channel_0"; + }; }; }; From da8503a828ebe73fd079ea40b72c5f0766ae5ca8 Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Fri, 27 Mar 2026 17:36:37 -0300 Subject: [PATCH 34/46] arm: dts: socfpga_cyclone5_de10_nano_cn0540: update to support new features update devicetree to support the new spi-engine implementation and regulator provider property. while at it, add channel description. Signed-off-by: Jonathan Santos --- .../socfpga_cyclone5_de10_nano_cn0540.dts | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/arch/arm/boot/dts/intel/socfpga/socfpga_cyclone5_de10_nano_cn0540.dts b/arch/arm/boot/dts/intel/socfpga/socfpga_cyclone5_de10_nano_cn0540.dts index 528027a8b0d8b7..6d9364b7776627 100644 --- a/arch/arm/boot/dts/intel/socfpga/socfpga_cyclone5_de10_nano_cn0540.dts +++ b/arch/arm/boot/dts/intel/socfpga/socfpga_cyclone5_de10_nano_cn0540.dts @@ -15,6 +15,7 @@ #include #include +#include / { vref: regulator-vref { @@ -98,7 +99,7 @@ }; spi@30000 { - compatible = "adi,legacy-axi-spi-engine-1.00.a"; + compatible = "adi,axi-spi-engine-1.00.a"; reg = <0x00030000 0x00010000>; interrupt-parent = <&intc>; interrupts = <0 45 IRQ_TYPE_LEVEL_HIGH>; @@ -106,6 +107,10 @@ clock-names = "s_axi_aclk", "spi_clk"; num-cs = <1>; + trigger-sources = <&ad7768_1 AD7768_TRIGGER_SOURCE_DRDY>; + dmas = <&axi_dmac_0 0>; + dma-names = "offload0-rx"; + #address-cells = <0x1>; #size-cells = <0x0>; @@ -117,14 +122,28 @@ spi-cpha; #gpio-cells = <2>; gpio-controller; + interrupts = <0 46 IRQ_TYPE_EDGE_RISING>; + interrupt-parent = <&intc>; vref-supply = <&vref>; adi,sync-in-gpios = <&gpio_out 1 GPIO_ACTIVE_LOW>; reset-gpios = <&gpio_out 0 GPIO_ACTIVE_LOW>; clocks = <&ad7768_1_mclk>; clock-names = "mclk"; - dmas = <&axi_dmac_0 0>; - dma-names = "rx"; + #trigger-source-cells = <1>; #io-channel-cells = <1>; + + #address-cells = <1>; + #size-cells = <0>; + regulators { + vcm_reg: vcm-output { + regulator-name = "ad7768-1-vcm"; + }; + }; + + channel@0 { + reg = <0>; + label = "channel_0"; + }; }; }; }; From ea29c1d9cc32f3033f66449462335337635ba7be Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Mon, 2 Mar 2026 12:43:03 -0300 Subject: [PATCH 35/46] arm: dts: Add device tree for ADAQ7767-1 on ZedBoard Enables using the ADAQ7767-1 device on ZedBoard with FMC connector. Signed-off-by: Jonathan Santos --- .../zynq-zed-adv7511-adaq7767-1-evb.dts | 107 ++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 arch/arm/boot/dts/xilinx/zynq-zed-adv7511-adaq7767-1-evb.dts diff --git a/arch/arm/boot/dts/xilinx/zynq-zed-adv7511-adaq7767-1-evb.dts b/arch/arm/boot/dts/xilinx/zynq-zed-adv7511-adaq7767-1-evb.dts new file mode 100644 index 00000000000000..9037850c6035f4 --- /dev/null +++ b/arch/arm/boot/dts/xilinx/zynq-zed-adv7511-adaq7767-1-evb.dts @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices AD7768-1 + * https://wiki.analog.com/resources/eval/user-guides/ad7768-1 + * + * hdl_project: + * board_revision: + * + * Copyright (C) 2026 Analog Devices Inc. + */ +/dts-v1/; + +#include "zynq-zed.dtsi" +#include "zynq-zed-adv7511.dtsi" +#include +#include + +#include + +/ { + vref: regulator-vref { + compatible = "regulator-fixed"; + regulator-name = "fixed-supply"; + regulator-min-microvolt = <4096000>; + regulator-max-microvolt = <4096000>; + regulator-always-on; + }; + + clocks { + ad7768_1_mclk: clock@0 { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <16384000>; + }; + }; + + sync_trigger: triggers { + compatible = "gpio-trigger"; + #trigger-source-cells = <0>; + gpios = <&gpio0 88 GPIO_ACTIVE_LOW>; + }; +}; + +&fpga_axi { + rx_dma: rx-dmac@44a30000 { + compatible = "adi,axi-dmac-1.00.a"; + reg = <0x44a30000 0x1000>; + #dma-cells = <1>; + interrupt-parent = <&intc>; + interrupts = <0 57 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clkc 16>; + }; + + spi_clock: spieng-axi-clkgen@44a70000 { + compatible = "adi,axi-clkgen-2.00.a"; + reg = <0x44a70000 0x10000>; + #clock-cells = <0>; + clocks = <&clkc 15>, <&clkc 16>; + clock-names = "s_axi_aclk", "clkin1"; + }; + + axi_spi_engine_0: spi@44a00000 { + compatible = "adi,axi-spi-engine-1.00.a"; + reg = <0x44a00000 0x1000>; + interrupt-parent = <&intc>; + interrupts = <0 56 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clkc 15 &spi_clock>; + + trigger-sources = <&adaq7767_1 AD7768_TRIGGER_SOURCE_DRDY>; + dmas = <&rx_dma 0>; + dma-names = "offload0-rx"; + + clock-names = "s_axi_aclk", "spi_clk"; + num-cs = <1>; + + #address-cells = <0x1>; + #size-cells = <0x0>; + + adaq7767_1: adc@0 { + compatible = "adi,adaq7767-1"; + reg = <0>; + spi-max-frequency = <20000000>; + spi-cpol; + spi-cpha; + vref-supply = <&vref>; + gpio-controller; + interrupts = <93 IRQ_TYPE_EDGE_RISING>; + interrupt-parent = <&gpio0>; + adi,aaf-gain-bp = <10000>; + #trigger-source-cells = <1>; + + reset-gpios = <&gpio0 86 GPIO_ACTIVE_LOW>; + clocks = <&ad7768_1_mclk>; + clock-names = "mclk"; + dmas = <&rx_dma 0>; + dma-names = "rx"; + #io-channel-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + label = "channel_0"; + }; + }; + }; +}; From b6d0bb562dc10ef84a298ceefcdba452695ccbd5 Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Mon, 2 Mar 2026 12:45:12 -0300 Subject: [PATCH 36/46] arm: dts: Add device tree for ADAQ7768-1 on ZedBoard Enables using the ADAQ7768-1 device on ZedBoard with FMC connector. Signed-off-by: Jonathan Santos --- .../zynq-zed-adv7511-adaq7768-1-evb.dts | 110 ++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 arch/arm/boot/dts/xilinx/zynq-zed-adv7511-adaq7768-1-evb.dts diff --git a/arch/arm/boot/dts/xilinx/zynq-zed-adv7511-adaq7768-1-evb.dts b/arch/arm/boot/dts/xilinx/zynq-zed-adv7511-adaq7768-1-evb.dts new file mode 100644 index 00000000000000..6fdd3ef2072304 --- /dev/null +++ b/arch/arm/boot/dts/xilinx/zynq-zed-adv7511-adaq7768-1-evb.dts @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices ADAQ7768-1 + * https://wiki.analog.com/resources/eval/user-guides/ad7768-1 + * + * hdl_project: + * board_revision: + * + * Copyright (C) 2026 Analog Devices Inc. + */ +/dts-v1/; + +#include "zynq-zed.dtsi" +#include "zynq-zed-adv7511.dtsi" +#include +#include + +#include + +/ { + vref: regulator-vref { + compatible = "regulator-fixed"; + regulator-name = "fixed-supply"; + regulator-min-microvolt = <4096000>; + regulator-max-microvolt = <4096000>; + regulator-always-on; + }; + + clocks { + ad7768_1_mclk: clock@0 { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <16384000>; + }; + }; + + sync_trigger: triggers { + compatible = "gpio-trigger"; + #trigger-source-cells = <0>; + gpios = <&gpio0 88 GPIO_ACTIVE_LOW>; + }; +}; + +&fpga_axi { + rx_dma: rx-dmac@44a30000 { + compatible = "adi,axi-dmac-1.00.a"; + reg = <0x44a30000 0x1000>; + #dma-cells = <1>; + interrupt-parent = <&intc>; + interrupts = <0 57 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clkc 16>; + }; + + spi_clock: spieng-axi-clkgen@44a70000 { + compatible = "adi,axi-clkgen-2.00.a"; + reg = <0x44a70000 0x10000>; + #clock-cells = <0>; + clocks = <&clkc 15>, <&clkc 16>; + clock-names = "s_axi_aclk", "clkin1"; + }; + + axi_spi_engine_0: spi@44a00000 { + compatible = "adi,axi-spi-engine-1.00.a"; + reg = <0x44a00000 0x1000>; + interrupt-parent = <&intc>; + interrupts = <0 56 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clkc 15 &spi_clock>; + + trigger-sources = <&adaq7768_1 AD7768_TRIGGER_SOURCE_DRDY>; + dmas = <&rx_dma 0>; + dma-names = "offload0-rx"; + + clock-names = "s_axi_aclk", "spi_clk"; + num-cs = <1>; + + #address-cells = <0x1>; + #size-cells = <0x0>; + + adaq7768_1: adc@0 { + compatible = "adi,adaq7768-1"; + reg = <0>; + spi-max-frequency = <20000000>; + spi-cpol; + spi-cpha; + vref-supply = <&vref>; + gpio-controller; + #gpio-cells = <2>; + pga-gpios = <&adaq7768_1 0 GPIO_ACTIVE_HIGH>, + <&adaq7768_1 1 GPIO_ACTIVE_HIGH>, + <&adaq7768_1 2 GPIO_ACTIVE_HIGH>; + interrupts = <93 IRQ_TYPE_EDGE_RISING>; + interrupt-parent = <&gpio0>; + #trigger-source-cells = <1>; + + reset-gpios = <&gpio0 86 GPIO_ACTIVE_LOW>; + clocks = <&ad7768_1_mclk>; + clock-names = "mclk"; + dmas = <&rx_dma 0>; + dma-names = "rx"; + #io-channel-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + label = "channel_0"; + }; + }; + }; +}; From 495a4c05cdf1e6aa5647ccedbe83ccce25aadfa2 Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Mon, 2 Mar 2026 12:45:37 -0300 Subject: [PATCH 37/46] arm: dts: Add device tree for ADAQ7769-1 on ZedBoard Enables using the ADAQ7769-1 device on ZedBoard with FMC connector. Signed-off-by: Jonathan Santos --- .../zynq-zed-adv7511-adaq7769-1-evb.dts | 109 ++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 arch/arm/boot/dts/xilinx/zynq-zed-adv7511-adaq7769-1-evb.dts diff --git a/arch/arm/boot/dts/xilinx/zynq-zed-adv7511-adaq7769-1-evb.dts b/arch/arm/boot/dts/xilinx/zynq-zed-adv7511-adaq7769-1-evb.dts new file mode 100644 index 00000000000000..07ccbf07090d18 --- /dev/null +++ b/arch/arm/boot/dts/xilinx/zynq-zed-adv7511-adaq7769-1-evb.dts @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices ADAQ7769-1 + * https://wiki.analog.com/resources/eval/user-guides/ad7768-1 + * + * hdl_project: + * board_revision: + * + * Copyright (C) 2026 Analog Devices Inc. + */ +/dts-v1/; + +#include "zynq-zed.dtsi" +#include "zynq-zed-adv7511.dtsi" +#include +#include + +#include + +/ { + vref: regulator-vref { + compatible = "regulator-fixed"; + regulator-name = "fixed-supply"; + regulator-min-microvolt = <4096000>; + regulator-max-microvolt = <4096000>; + regulator-always-on; + }; + + clocks { + ad7768_1_mclk: clock@0 { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <16384000>; + }; + }; + + sync_trigger: triggers { + compatible = "gpio-trigger"; + #trigger-source-cells = <0>; + gpios = <&gpio0 88 GPIO_ACTIVE_LOW>; + }; +}; + +&fpga_axi { + rx_dma: rx-dmac@44a30000 { + compatible = "adi,axi-dmac-1.00.a"; + reg = <0x44a30000 0x1000>; + #dma-cells = <1>; + interrupt-parent = <&intc>; + interrupts = <0 57 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clkc 16>; + }; + + spi_clock: spieng-axi-clkgen@44a70000 { + compatible = "adi,axi-clkgen-2.00.a"; + reg = <0x44a70000 0x10000>; + #clock-cells = <0>; + clocks = <&clkc 15>, <&clkc 16>; + clock-names = "s_axi_aclk", "clkin1"; + }; + + axi_spi_engine_0: spi@44a00000 { + compatible = "adi,axi-spi-engine-1.00.a"; + reg = <0x44a00000 0x1000>; + interrupt-parent = <&intc>; + interrupts = <0 56 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clkc 15 &spi_clock>; + + trigger-sources = <&adaq7769_1 AD7768_TRIGGER_SOURCE_DRDY>; + dmas = <&rx_dma 0>; + dma-names = "offload0-rx"; + + clock-names = "s_axi_aclk", "spi_clk"; + num-cs = <1>; + + #address-cells = <0x1>; + #size-cells = <0x0>; + + adaq7769_1: adc@0 { + compatible = "adi,adaq7769-1"; + reg = <0>; + spi-max-frequency = <20000000>; + spi-cpol; + spi-cpha; + vref-supply = <&vref>; + gpio-controller; + interrupts = <93 IRQ_TYPE_EDGE_RISING>; + interrupt-parent = <&gpio0>; + #gpio-cells = <2>; + pga-gpios = <&adaq7769_1 0 GPIO_ACTIVE_HIGH>, + <&adaq7769_1 1 GPIO_ACTIVE_HIGH>, + <&adaq7769_1 2 GPIO_ACTIVE_HIGH>; + adi,aaf-gain-bp = <10000>; + #trigger-source-cells = <1>; + + reset-gpios = <&gpio0 86 GPIO_ACTIVE_LOW>; + clocks = <&ad7768_1_mclk>; + clock-names = "mclk"; + #io-channel-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + label = "channel_0"; + }; + }; + }; +}; From 34dece1a52fb1cb9248cc65963d10f8d0d4b5813 Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Wed, 14 Jan 2026 06:26:52 -0300 Subject: [PATCH 38/46] iio: adc: ad7768-1: introduce chip info for future multidevice support Add Chip info struct in SPI device to store channel information for each supported part. Signed-off-by: Jonathan Santos Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7768-1.c | 64 ++++++++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 23 deletions(-) diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index f550d29b1aecef..d7c4a3014dd500 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -213,6 +213,12 @@ static const struct iio_scan_type ad7768_scan_type[] = { }, }; +struct ad7768_chip_info { + const char *name; + const struct iio_chan_spec *channel_spec; + int num_channels; +}; + struct ad7768_state { struct spi_device *spi; struct regmap *regmap; @@ -234,6 +240,7 @@ struct ad7768_state { struct gpio_desc *gpio_reset; const char *labels[AD7768_MAX_CHANNELS]; struct gpio_chip gpiochip; + const struct ad7768_chip_info *chip; bool en_spi_sync; /* * DMA (thus cache coherency maintenance) may require the @@ -749,24 +756,28 @@ static const struct iio_chan_spec_ext_info ad7768_ext_info[] = { { } }; +#define AD7768_CHAN(_idx, _msk_avail) \ +{ \ + .type = IIO_VOLTAGE, \ + .info_mask_separate_available = _msk_avail, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .ext_info = ad7768_ext_info, \ + .indexed = 1, \ + .channel = _idx, \ + .scan_index = _idx, \ + .has_ext_scan_type = 1, \ + .ext_scan_type = ad7768_scan_type, \ + .num_ext_scan_type = ARRAY_SIZE(ad7768_scan_type), \ +} + static const struct iio_chan_spec ad7768_channels[] = { - { - .type = IIO_VOLTAGE, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | - BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | - BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), - .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), - .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), - .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), - .ext_info = ad7768_ext_info, - .indexed = 1, - .channel = 0, - .scan_index = 0, - .has_ext_scan_type = 1, - .ext_scan_type = ad7768_scan_type, - .num_ext_scan_type = ARRAY_SIZE(ad7768_scan_type), - }, + AD7768_CHAN(0, 0), }; static int ad7768_read_raw(struct iio_dev *indio_dev, @@ -1322,6 +1333,12 @@ static int ad7768_register_regulators(struct device *dev, struct ad7768_state *s return 0; } +static const struct ad7768_chip_info ad7768_chip_info = { + .name = "ad7768-1", + .channel_spec = ad7768_channels, + .num_channels = ARRAY_SIZE(ad7768_channels), +}; + static int ad7768_probe(struct spi_device *spi) { struct ad7768_state *st; @@ -1348,6 +1365,7 @@ static int ad7768_probe(struct spi_device *spi) return ret; } + st->chip = spi_get_device_match_data(spi); st->spi = spi; st->regmap = devm_regmap_init_spi(spi, &ad7768_regmap_config); @@ -1372,9 +1390,9 @@ static int ad7768_probe(struct spi_device *spi) st->mclk_freq = clk_get_rate(st->mclk); - indio_dev->channels = ad7768_channels; - indio_dev->num_channels = ARRAY_SIZE(ad7768_channels); - indio_dev->name = spi_get_device_id(spi)->name; + indio_dev->channels = st->chip->channel_spec; + indio_dev->num_channels = st->chip->num_channels; + indio_dev->name = st->chip->name; indio_dev->info = &ad7768_info; indio_dev->modes = INDIO_DIRECT_MODE; @@ -1391,7 +1409,7 @@ static int ad7768_probe(struct spi_device *spi) init_completion(&st->completion); - ret = ad7768_set_channel_label(indio_dev, ARRAY_SIZE(ad7768_channels)); + ret = ad7768_set_channel_label(indio_dev, st->chip->num_channels); if (ret) return ret; @@ -1410,13 +1428,13 @@ static int ad7768_probe(struct spi_device *spi) } static const struct spi_device_id ad7768_id_table[] = { - { "ad7768-1", 0 }, + { "ad7768-1", (kernel_ulong_t)&ad7768_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ad7768_id_table); static const struct of_device_id ad7768_of_match[] = { - { .compatible = "adi,ad7768-1" }, + { .compatible = "adi,ad7768-1", .data = &ad7768_chip_info }, { } }; MODULE_DEVICE_TABLE(of, ad7768_of_match); From afaadd84ee6d5fe271552369956545fdf870deaf Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Wed, 14 Jan 2026 06:27:14 -0300 Subject: [PATCH 39/46] iio: adc: ad7768-1: refactor ad7768_write_raw() Squash __ad7768_write_raw() back to ad7768_write_raw() to allow the addition of new attributes without requiring a direct mode claim. Signed-off-by: Jonathan Santos Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7768-1.c | 50 ++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index d7c4a3014dd500..49f894993e81d3 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -743,6 +743,19 @@ static int ad7768_get_filter_type_attr(struct iio_dev *dev, return ad7768_filter_regval_to_type[FIELD_GET(mask, mode)]; } +static int ad7768_update_dec_rate(struct iio_dev *dev, unsigned int dec_rate) +{ + struct ad7768_state *st = iio_priv(dev); + int ret; + + ret = ad7768_configure_dig_fil(dev, st->filter_type, dec_rate); + if (ret) + return ret; + + /* Update sampling frequency */ + return ad7768_set_freq(st, st->samp_freq); +} + static const struct iio_enum ad7768_filter_type_iio_enum = { .items = ad7768_filter_enum, .num_items = ARRAY_SIZE(ad7768_filter_enum), @@ -868,44 +881,33 @@ static int ad7768_read_avail(struct iio_dev *indio_dev, } } -static int __ad7768_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, int val2, long info) +static int ad7768_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long info) { struct ad7768_state *st = iio_priv(indio_dev); int ret; switch (info) { case IIO_CHAN_INFO_SAMP_FREQ: - return ad7768_set_freq(st, val); + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; + ret = ad7768_set_freq(st, val); + iio_device_release_direct(indio_dev); + return ret; case IIO_CHAN_INFO_OVERSAMPLING_RATIO: - ret = ad7768_configure_dig_fil(indio_dev, st->filter_type, val); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; - /* Update sampling frequency */ - return ad7768_set_freq(st, st->samp_freq); + ret = ad7768_update_dec_rate(indio_dev, val); + iio_device_release_direct(indio_dev); + return ret; default: return -EINVAL; } } -static int ad7768_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, int val2, long info) -{ - int ret; - - if (!iio_device_claim_direct(indio_dev)) - return -EBUSY; - - ret = __ad7768_write_raw(indio_dev, chan, val, val2, info); - iio_device_release_direct(indio_dev); - - return ret; -} - static int ad7768_read_label(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, char *label) { From 32d0dbcd5450604985ed797ccba5b293acd1b6ca Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Wed, 14 Jan 2026 06:27:29 -0300 Subject: [PATCH 40/46] iio: adc: ad7768-1: add support for ADAQ776x-1 ADC Family Add support for ADAQ7767/68/69-1 series, which includes PGIA and Anti-aliasing filter (AAF) gains. Unlike the AD7768-1, they do not provide a VCM regulator interface. The PGA gain is configured in run-time through the scale attribute, if supported by the device. PGA is controlled by GPIOs provided in the device tree. The AAF gain is defined by hardware connections and should be specified in the device tree. Signed-off-by: Jonathan Santos Signed-off-by: Jonathan Cameron --- drivers/iio/adc/Kconfig | 1 + drivers/iio/adc/ad7768-1.c | 311 ++++++++++++++++++++++++++++++++++++- 2 files changed, 308 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 8fd50628f43e54..93926a77cc325c 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -377,6 +377,7 @@ config AD7768_1 tristate "Analog Devices AD7768-1 ADC driver" depends on SPI select REGMAP_SPI + select RATIONAL select IIO_BUFFER select IIO_TRIGGER select IIO_TRIGGERED_BUFFER diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index 49f894993e81d3..bb802b8f379b7f 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -6,6 +6,7 @@ */ #include #include +#include #include #include #include @@ -14,8 +15,12 @@ #include #include #include +#include +#include #include #include +#include +#include #include #include #include @@ -107,10 +112,15 @@ #define AD7768_VCM_OFF 0x07 +#define ADAQ776X_GAIN_MAX_NANO (128 * NANO) +#define ADAQ776X_MAX_GAIN_MODES 8 + #define AD7768_TRIGGER_SOURCE_SYNC_IDX 0 #define AD7768_MAX_CHANNELS 1 +#define ADAQ7768_PGA_PINS 3 + enum ad7768_conv_mode { AD7768_CONTINUOUS, AD7768_ONE_SHOT, @@ -153,6 +163,51 @@ enum ad7768_scan_type { AD7768_SCAN_TYPE_HIGH_SPEED, }; +enum { + AD7768_PGA_GAIN_0, + AD7768_PGA_GAIN_1, + AD7768_PGA_GAIN_2, + AD7768_PGA_GAIN_3, + AD7768_PGA_GAIN_4, + AD7768_PGA_GAIN_5, + AD7768_PGA_GAIN_6, + AD7768_PGA_GAIN_7, +}; + +enum { + AD7768_AAF_IN1, + AD7768_AAF_IN2, + AD7768_AAF_IN3, +}; + +/* PGA and AAF gains in V/V */ +static const int adaq7768_gains[] = { + [AD7768_PGA_GAIN_0] = 325, /* 0.325 */ + [AD7768_PGA_GAIN_1] = 650, /* 0.650 */ + [AD7768_PGA_GAIN_2] = 1300, /* 1.300 */ + [AD7768_PGA_GAIN_3] = 2600, /* 2.600 */ + [AD7768_PGA_GAIN_4] = 5200, /* 5.200 */ + [AD7768_PGA_GAIN_5] = 10400, /* 10.400 */ + [AD7768_PGA_GAIN_6] = 20800, /* 20.800 */ +}; + +static const int adaq7769_gains[] = { + [AD7768_PGA_GAIN_0] = 1000, /* 1.000 */ + [AD7768_PGA_GAIN_1] = 2000, /* 2.000 */ + [AD7768_PGA_GAIN_2] = 4000, /* 4.000 */ + [AD7768_PGA_GAIN_3] = 8000, /* 8.000 */ + [AD7768_PGA_GAIN_4] = 16000, /* 16.000 */ + [AD7768_PGA_GAIN_5] = 32000, /* 32.000 */ + [AD7768_PGA_GAIN_6] = 64000, /* 64.000 */ + [AD7768_PGA_GAIN_7] = 128000, /* 128.000 */ +}; + +static const int ad7768_aaf_gains_bp[] = { + [AD7768_AAF_IN1] = 10000, /* 1.000 */ + [AD7768_AAF_IN2] = 3640, /* 0.364 */ + [AD7768_AAF_IN3] = 1430, /* 0.143 */ +}; + /* -3dB cutoff frequency multipliers (relative to ODR) for each filter type. */ static const int ad7768_filter_3db_odr_multiplier[] = { [AD7768_FILTER_SINC5] = 204, /* 0.204 */ @@ -217,6 +272,13 @@ struct ad7768_chip_info { const char *name; const struct iio_chan_spec *channel_spec; int num_channels; + const int *pga_gains; + int num_pga_modes; + int default_pga_mode; + int pgia_mode2pin_offset; + bool has_pga; + bool has_variable_aaf; + bool has_vcm_regulator; }; struct ad7768_state { @@ -234,14 +296,19 @@ struct ad7768_state { unsigned int samp_freq; unsigned int samp_freq_avail[ARRAY_SIZE(ad7768_mclk_div_rates)]; unsigned int samp_freq_avail_len; + unsigned int pga_gain_mode; + unsigned int aaf_gain; + int scale_tbl[ADAQ776X_MAX_GAIN_MODES][2]; struct completion completion; struct iio_trigger *trig; + struct gpio_descs *pga_gpios; struct gpio_desc *gpio_sync_in; struct gpio_desc *gpio_reset; const char *labels[AD7768_MAX_CHANNELS]; struct gpio_chip gpiochip; const struct ad7768_chip_info *chip; bool en_spi_sync; + struct mutex pga_lock; /* protect device internal state (PGA) */ /* * DMA (thus cache coherency maintenance) may require the * transfer buffers to live in their own cache lines. @@ -464,6 +531,42 @@ static int ad7768_reg_access(struct iio_dev *indio_dev, return ret; } +static void ad7768_fill_scale_tbl(struct iio_dev *dev) +{ + struct ad7768_state *st = iio_priv(dev); + const struct iio_scan_type *scan_type; + int val, val2, tmp0, tmp1, i; + struct u32_fract fract; + unsigned long n, d; + u64 tmp2; + + scan_type = iio_get_current_scan_type(dev, &dev->channels[0]); + if (scan_type->sign == 's') + val2 = scan_type->realbits - 1; + else + val2 = scan_type->realbits; + + for (i = 0; i < st->chip->num_pga_modes; i++) { + /* Convert gain to a fraction format */ + fract.numerator = st->chip->pga_gains[i]; + fract.denominator = MILLI; + if (st->chip->has_variable_aaf) { + fract.numerator *= ad7768_aaf_gains_bp[st->aaf_gain]; + fract.denominator *= PERMYRIAD; + } + + rational_best_approximation(fract.numerator, fract.denominator, + INT_MAX, INT_MAX, &n, &d); + + val = mult_frac(st->vref_uv, d, n); + /* Would multiply by NANO here, but value is already in milli */ + tmp2 = ((u64)val * MICRO) >> val2; + tmp0 = div_u64_rem(tmp2, NANO, &tmp1); + st->scale_tbl[i][0] = tmp0; /* Integer part */ + st->scale_tbl[i][1] = abs(tmp1); /* Fractional part */ + } +} + static int ad7768_set_sinc3_dec_rate(struct ad7768_state *st, unsigned int dec_rate) { @@ -565,12 +668,66 @@ static int ad7768_configure_dig_fil(struct iio_dev *dev, st->oversampling_ratio = ad7768_dec_rate_values[dec_rate_idx]; } + /* Update scale table: scale values vary according to the precision */ + ad7768_fill_scale_tbl(dev); + ad7768_fill_samp_freq_tbl(st); /* A sync-in pulse is required after every configuration change */ return ad7768_send_sync_pulse(st); } +static int ad7768_setup_pga(struct device *dev, struct ad7768_state *st) +{ + st->pga_gpios = devm_gpiod_get_array(dev, "pga", GPIOD_OUT_LOW); + if (IS_ERR(st->pga_gpios)) + return dev_err_probe(dev, PTR_ERR(st->pga_gpios), + "Failed to get PGA gpios.\n"); + + if (st->pga_gpios->ndescs != ADAQ7768_PGA_PINS) + return dev_err_probe(dev, -EINVAL, + "Expected %d GPIOs for PGA control.\n", + ADAQ7768_PGA_PINS); + return 0; +} + +static int ad7768_calc_pga_gain(struct ad7768_state *st, int gain_int, + int gain_fract, int precision) +{ + u64 gain_nano; + u32 tmp; + + gain_nano = gain_int * NANO + gain_fract; + gain_nano = clamp(gain_nano, 0, ADAQ776X_GAIN_MAX_NANO); + tmp = DIV_ROUND_CLOSEST_ULL(gain_nano << precision, NANO); + gain_nano = DIV_ROUND_CLOSEST(st->vref_uv, tmp); + if (st->chip->has_variable_aaf) + gain_nano = DIV_ROUND_CLOSEST_ULL(gain_nano * PERMYRIAD, + ad7768_aaf_gains_bp[st->aaf_gain]); + + return find_closest(gain_nano, st->chip->pga_gains, + (int)st->chip->num_pga_modes); +} + +static int ad7768_set_pga_gain(struct ad7768_state *st, + int gain_mode) +{ + int pgia_pins_value = abs(gain_mode - st->chip->pgia_mode2pin_offset); + DECLARE_BITMAP(bitmap, ADAQ7768_PGA_PINS) = { }; + int ret; + + guard(mutex)(&st->pga_lock); + + bitmap_write(bitmap, pgia_pins_value, 0, ADAQ7768_PGA_PINS); + ret = gpiod_multi_set_value_cansleep(st->pga_gpios, bitmap); + if (ret) + return ret; + + st->pga_gain_mode = gain_mode; + + return 0; +} + static int ad7768_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) { struct iio_dev *indio_dev = gpiochip_get_data(chip); @@ -793,6 +950,10 @@ static const struct iio_chan_spec ad7768_channels[] = { AD7768_CHAN(0, 0), }; +static const struct iio_chan_spec adaq776x_channels[] = { + AD7768_CHAN(0, BIT(IIO_CHAN_INFO_SCALE)), +}; + static int ad7768_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long info) @@ -820,7 +981,19 @@ static int ad7768_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - *val = (st->vref_uv * 2) / 1000; + if (st->chip->has_pga) { + guard(mutex)(&st->pga_lock); + + *val = st->scale_tbl[st->pga_gain_mode][0]; + *val2 = st->scale_tbl[st->pga_gain_mode][1]; + return IIO_VAL_INT_PLUS_NANO; + } + + temp = (st->vref_uv * 2) / 1000; + if (st->chip->has_variable_aaf) + temp = (temp * PERMYRIAD) / ad7768_aaf_gains_bp[st->aaf_gain]; + + *val = temp; *val2 = scan_type->realbits; return IIO_VAL_FRACTIONAL_LOG2; @@ -876,18 +1049,39 @@ static int ad7768_read_avail(struct iio_dev *indio_dev, *length = st->samp_freq_avail_len; *type = IIO_VAL_INT; return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_SCALE: + *vals = (int *)st->scale_tbl; + *length = st->chip->num_pga_modes * 2; + *type = IIO_VAL_INT_PLUS_NANO; + return IIO_AVAIL_LIST; default: return -EINVAL; } } +static int ad7768_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_SCALE: + return IIO_VAL_INT_PLUS_NANO; + default: + return IIO_VAL_INT_PLUS_MICRO; + } +} + static int ad7768_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long info) { struct ad7768_state *st = iio_priv(indio_dev); + const struct iio_scan_type *scan_type; int ret; + scan_type = iio_get_current_scan_type(indio_dev, chan); + if (IS_ERR(scan_type)) + return PTR_ERR(scan_type); + switch (info) { case IIO_CHAN_INFO_SAMP_FREQ: if (!iio_device_claim_direct(indio_dev)) @@ -903,6 +1097,21 @@ static int ad7768_write_raw(struct iio_dev *indio_dev, ret = ad7768_update_dec_rate(indio_dev, val); iio_device_release_direct(indio_dev); return ret; + case IIO_CHAN_INFO_SCALE: { + int gain_mode; + + if (!st->chip->has_pga) + return -EOPNOTSUPP; + + if (scan_type->sign == 's') + gain_mode = ad7768_calc_pga_gain(st, val, val2, + scan_type->realbits - 1); + else + gain_mode = ad7768_calc_pga_gain(st, val, val2, + scan_type->realbits); + + return ad7768_set_pga_gain(st, gain_mode); + } default: return -EINVAL; } @@ -929,6 +1138,7 @@ static const struct iio_info ad7768_info = { .read_raw = &ad7768_read_raw, .read_avail = &ad7768_read_avail, .write_raw = &ad7768_write_raw, + .write_raw_get_fmt = &ad7768_write_raw_get_fmt, .read_label = ad7768_read_label, .get_current_scan_type = &ad7768_get_current_scan_type, .debugfs_reg_access = &ad7768_reg_access, @@ -1312,8 +1522,9 @@ static const struct regulator_desc vcm_desc = { .owner = THIS_MODULE, }; -static int ad7768_register_regulators(struct device *dev, struct ad7768_state *st, - struct iio_dev *indio_dev) +static int ad7768_register_vcm_regulator(struct device *dev, + struct ad7768_state *st, + struct iio_dev *indio_dev) { struct regulator_config config = { .dev = dev, @@ -1335,10 +1546,77 @@ static int ad7768_register_regulators(struct device *dev, struct ad7768_state *s return 0; } +static int ad7768_parse_aaf_gain(struct device *dev, struct ad7768_state *st) +{ + u32 val; + int ret; + + ret = device_property_read_u32(dev, "adi,aaf-gain-bp", &val); + if (ret == -EINVAL) { + /* If controllable, use default */ + if (st->chip->has_variable_aaf) + st->aaf_gain = AD7768_AAF_IN1; + return 0; + } + if (ret) + return dev_err_probe(dev, ret, "Failed to get AAF gain value\n"); + + if (!st->chip->has_variable_aaf) + return dev_err_probe(dev, -EOPNOTSUPP, + "AAF gain provided, but not supported for %s\n", st->chip->name); + + switch (val) { + case 10000: + st->aaf_gain = AD7768_AAF_IN1; + break; + case 3640: + st->aaf_gain = AD7768_AAF_IN2; + break; + case 1430: + st->aaf_gain = AD7768_AAF_IN3; + break; + default: + return dev_err_probe(dev, -EINVAL, "Invalid firmware provided AAF gain\n"); + } + + return 0; +} + static const struct ad7768_chip_info ad7768_chip_info = { .name = "ad7768-1", .channel_spec = ad7768_channels, .num_channels = ARRAY_SIZE(ad7768_channels), + .has_vcm_regulator = true, +}; + +static const struct ad7768_chip_info adaq7767_chip_info = { + .name = "adaq7767-1", + .channel_spec = ad7768_channels, + .num_channels = ARRAY_SIZE(ad7768_channels), + .has_variable_aaf = true, +}; + +static const struct ad7768_chip_info adaq7768_chip_info = { + .name = "adaq7768-1", + .channel_spec = adaq776x_channels, + .num_channels = ARRAY_SIZE(adaq776x_channels), + .pga_gains = adaq7768_gains, + .default_pga_mode = AD7768_PGA_GAIN_2, + .num_pga_modes = ARRAY_SIZE(adaq7768_gains), + .pgia_mode2pin_offset = 6, + .has_pga = true, +}; + +static const struct ad7768_chip_info adaq7769_chip_info = { + .name = "adaq7769-1", + .channel_spec = adaq776x_channels, + .num_channels = ARRAY_SIZE(adaq776x_channels), + .pga_gains = adaq7769_gains, + .default_pga_mode = AD7768_PGA_GAIN_0, + .num_pga_modes = ARRAY_SIZE(adaq7769_gains), + .pgia_mode2pin_offset = 0, + .has_pga = true, + .has_variable_aaf = true, }; static int ad7768_probe(struct spi_device *spi) @@ -1399,7 +1677,13 @@ static int ad7768_probe(struct spi_device *spi) indio_dev->modes = INDIO_DIRECT_MODE; /* Register VCM output regulator */ - ret = ad7768_register_regulators(&spi->dev, st, indio_dev); + if (st->chip->has_vcm_regulator) { + ret = ad7768_register_vcm_regulator(&spi->dev, st, indio_dev); + if (ret) + return ret; + } + + ret = ad7768_parse_aaf_gain(&spi->dev, st); if (ret) return ret; @@ -1410,6 +1694,19 @@ static int ad7768_probe(struct spi_device *spi) } init_completion(&st->completion); + ret = devm_mutex_init(&spi->dev, &st->pga_lock); + if (ret) + return ret; + + if (st->chip->has_pga) { + ret = ad7768_setup_pga(&spi->dev, st); + if (ret) + return ret; + + ret = ad7768_set_pga_gain(st, st->chip->default_pga_mode); + if (ret) + return ret; + } ret = ad7768_set_channel_label(indio_dev, st->chip->num_channels); if (ret) @@ -1431,12 +1728,18 @@ static int ad7768_probe(struct spi_device *spi) static const struct spi_device_id ad7768_id_table[] = { { "ad7768-1", (kernel_ulong_t)&ad7768_chip_info }, + { "adaq7767-1", (kernel_ulong_t)&adaq7767_chip_info }, + { "adaq7768-1", (kernel_ulong_t)&adaq7768_chip_info }, + { "adaq7769-1", (kernel_ulong_t)&adaq7769_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ad7768_id_table); static const struct of_device_id ad7768_of_match[] = { { .compatible = "adi,ad7768-1", .data = &ad7768_chip_info }, + { .compatible = "adi,adaq7767-1", .data = &adaq7767_chip_info }, + { .compatible = "adi,adaq7768-1", .data = &adaq7768_chip_info }, + { .compatible = "adi,adaq7769-1", .data = &adaq7769_chip_info }, { } }; MODULE_DEVICE_TABLE(of, ad7768_of_match); From 99b016093597b7190739556f8ff3aee4f0211627 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Wed, 28 Jan 2026 10:55:37 +0100 Subject: [PATCH 41/46] iio: Replace IRQF_ONESHOT with IRQF_NO_THREAD Passing IRQF_ONESHOT ensures that the interrupt source is masked until the secondary (threaded) handler is done. If only a primary handler is used then the flag makes no sense because the interrupt can not fire (again) while its handler is running. The flag also disallows force-threading of the primary handler and the irq-core will warn about this. The intention here was probably not allowing forced-threading for handlers such as iio_trigger_generic_data_rdy_poll() will intends to invoke hard-interrupt handlers. Replace IRQF_ONESHOT with IRQF_NO_THREAD. Reviewed-by: Andy Shevchenko Reviewed-by: Marcus Folkesson Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7768-1.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index bb802b8f379b7f..dde2bc1db0443f 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -1712,9 +1712,8 @@ static int ad7768_probe(struct spi_device *spi) if (ret) return ret; - ret = devm_request_irq(&spi->dev, spi->irq, - &ad7768_interrupt, - IRQF_TRIGGER_RISING | IRQF_ONESHOT, + ret = devm_request_irq(&spi->dev, spi->irq, &ad7768_interrupt, + IRQF_TRIGGER_RISING | IRQF_NO_THREAD, indio_dev->name, indio_dev); if (ret) return ret; From 8464aedea1bb7e6def949c2ee52d3f593cdc2faa Mon Sep 17 00:00:00 2001 From: Ethan Tidmore Date: Sat, 14 Feb 2026 12:46:37 -0600 Subject: [PATCH 42/46] iio: adc: ad7768-1: Fix ERR_PTR dereference in ad7768_fill_scale_tbl The function iio_get_current_scan_type() can return an error pointer, the return value scan_type is not checked for this and immediately dereferenced which can cause a kernel panic. Add check for IS_ERR() and propagate the error back. Fixes: ff085189cb17 ("iio: adc: ad7768-1: add support for ADAQ776x-1 ADC Family") Reported-by: kernel test robot Reported-by: Dan Carpenter Closes: https://lore.kernel.org/r/202602051234.5gArzLyZ-lkp@intel.com/ Signed-off-by: Ethan Tidmore Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7768-1.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index dde2bc1db0443f..1d43da21e4280a 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -531,7 +531,7 @@ static int ad7768_reg_access(struct iio_dev *indio_dev, return ret; } -static void ad7768_fill_scale_tbl(struct iio_dev *dev) +static int ad7768_fill_scale_tbl(struct iio_dev *dev) { struct ad7768_state *st = iio_priv(dev); const struct iio_scan_type *scan_type; @@ -541,6 +541,11 @@ static void ad7768_fill_scale_tbl(struct iio_dev *dev) u64 tmp2; scan_type = iio_get_current_scan_type(dev, &dev->channels[0]); + if (IS_ERR(scan_type)) { + dev_err(&st->spi->dev, "Failed to get scan type.\n"); + return PTR_ERR(scan_type); + } + if (scan_type->sign == 's') val2 = scan_type->realbits - 1; else @@ -565,6 +570,8 @@ static void ad7768_fill_scale_tbl(struct iio_dev *dev) st->scale_tbl[i][0] = tmp0; /* Integer part */ st->scale_tbl[i][1] = abs(tmp1); /* Fractional part */ } + + return 0; } static int ad7768_set_sinc3_dec_rate(struct ad7768_state *st, @@ -669,7 +676,9 @@ static int ad7768_configure_dig_fil(struct iio_dev *dev, } /* Update scale table: scale values vary according to the precision */ - ad7768_fill_scale_tbl(dev); + ret = ad7768_fill_scale_tbl(dev); + if (ret) + return ret; ad7768_fill_samp_freq_tbl(st); From c17fe4256ac5c9229b4ddbdc382bf2b97044e197 Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Mon, 23 Feb 2026 08:59:26 -0300 Subject: [PATCH 43/46] iio: adc: ad7768-1: fix one-shot mode data acquisition According to the datasheet, one-shot mode requires a SYNC_IN pulse to trigger a new sample conversion. In the current implementation, No sync pulse was sent after switching to one-shot mode and reinit_completion() was called before mode switching, creating a race condition where spurious interrupts during mode change could trigger completion prematurely. Fix by sending a sync pulse after configuring one-shot mode and reinit_completion() to ensure it only waits for the actual conversion completion. Fixes: a5f8c7da3dbe ("iio: adc: Add AD7768-1 ADC basic support") Signed-off-by: Jonathan Santos Reviewed-by: David Lechner Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7768-1.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index 1d43da21e4280a..f4cb3dce1d6e3f 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -463,12 +463,17 @@ static int ad7768_scan_direct(struct iio_dev *indio_dev) struct ad7768_state *st = iio_priv(indio_dev); int readval, ret; - reinit_completion(&st->completion); - ret = ad7768_set_mode(st, AD7768_ONE_SHOT); if (ret < 0) return ret; + reinit_completion(&st->completion); + + /* One-shot mode requires a SYNC pulse to generate a new sample */ + ret = ad7768_send_sync_pulse(st); + if (ret) + return ret; + ret = wait_for_completion_timeout(&st->completion, msecs_to_jiffies(1000)); if (!ret) From 835315f3e37a9617e3fde2840811d91d7eb049c8 Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Mon, 23 Feb 2026 08:59:35 -0300 Subject: [PATCH 44/46] iio: adc: ad7768-1: remove switch to one-shot mode wideband low ripple FIR Filter is not available in one-shot mode. In order to make direct reads work for all filter options, remove the switch for one-shot mode and guarantee device is always in continuous conversion mode. Fixes: fb1d3b24ebf5 ("iio: adc: ad7768-1: add filter type and oversampling ratio attributes") Signed-off-by: Jonathan Santos Reviewed-by: David Lechner Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7768-1.c | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index f4cb3dce1d6e3f..758e40528316e2 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -463,17 +463,8 @@ static int ad7768_scan_direct(struct iio_dev *indio_dev) struct ad7768_state *st = iio_priv(indio_dev); int readval, ret; - ret = ad7768_set_mode(st, AD7768_ONE_SHOT); - if (ret < 0) - return ret; - reinit_completion(&st->completion); - /* One-shot mode requires a SYNC pulse to generate a new sample */ - ret = ad7768_send_sync_pulse(st); - if (ret) - return ret; - ret = wait_for_completion_timeout(&st->completion, msecs_to_jiffies(1000)); if (!ret) @@ -492,14 +483,6 @@ static int ad7768_scan_direct(struct iio_dev *indio_dev) if (st->oversampling_ratio == 8) readval >>= 8; - /* - * Any SPI configuration of the AD7768-1 can only be - * performed in continuous conversion mode. - */ - ret = ad7768_set_mode(st, AD7768_CONTINUOUS); - if (ret < 0) - return ret; - return readval; } @@ -1258,6 +1241,10 @@ static int ad7768_setup(struct iio_dev *indio_dev) return ret; } + ret = ad7768_set_mode(st, AD7768_CONTINUOUS); + if (ret) + return ret; + /* For backwards compatibility, try the adi,sync-in-gpios property */ st->gpio_sync_in = devm_gpiod_get_optional(&st->spi->dev, "adi,sync-in", GPIOD_OUT_LOW); From 8e78b224c8a164fd1aa7c6bfa4870a0dff3abce1 Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Mon, 23 Feb 2026 08:59:44 -0300 Subject: [PATCH 45/46] iio: adc: ad7768-1: disable IRQ autoenable The device continuously converts data while powered up, generating interrupts in the background. Configure the IRQ to be enabled and disabled manually as needed to avoid unnecessary CPU load. Signed-off-by: Jonathan Santos Reviewed-by: David Lechner Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7768-1.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index 758e40528316e2..797b176b2ea944 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -464,9 +464,11 @@ static int ad7768_scan_direct(struct iio_dev *indio_dev) int readval, ret; reinit_completion(&st->completion); + enable_irq(st->spi->irq); ret = wait_for_completion_timeout(&st->completion, msecs_to_jiffies(1000)); + disable_irq(st->spi->irq); if (!ret) return -ETIMEDOUT; @@ -1349,8 +1351,22 @@ static const struct iio_buffer_setup_ops ad7768_buffer_ops = { .predisable = &ad7768_buffer_predisable, }; +static int ad7768_set_trigger_state(struct iio_trigger *trig, bool enable) +{ + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); + struct ad7768_state *st = iio_priv(indio_dev); + + if (enable) + enable_irq(st->spi->irq); + else + disable_irq(st->spi->irq); + + return 0; +} + static const struct iio_trigger_ops ad7768_trigger_ops = { .validate_device = iio_trigger_validate_own_device, + .set_trigger_state = ad7768_set_trigger_state, }; static int ad7768_set_channel_label(struct iio_dev *indio_dev, @@ -1714,7 +1730,7 @@ static int ad7768_probe(struct spi_device *spi) return ret; ret = devm_request_irq(&spi->dev, spi->irq, &ad7768_interrupt, - IRQF_TRIGGER_RISING | IRQF_NO_THREAD, + IRQF_TRIGGER_RISING | IRQF_NO_THREAD | IRQF_NO_AUTOEN, indio_dev->name, indio_dev); if (ret) return ret; From 9c8426bd1c2f5cce87597e8c292d408fe2ba7a63 Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Mon, 23 Feb 2026 08:59:53 -0300 Subject: [PATCH 46/46] iio: adc: ad7768-1: add support for SPI offload The AD7768-1 family supports sampling rates up to 1 MSPS, which exceeds the capabilities of conventional triggered buffer operations due to SPI transaction overhead and interrupt latency. Add SPI offload support to enable hardware-accelerated data acquisition that bypasses software SPI transactions using continuous data streaming. Signed-off-by: Jonathan Santos Reviewed-by: David Lechner Signed-off-by: Jonathan Cameron --- drivers/iio/adc/Kconfig | 2 + drivers/iio/adc/ad7768-1.c | 186 ++++++++++++++++++++++++++++++++++++- 2 files changed, 185 insertions(+), 3 deletions(-) diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 93926a77cc325c..6962ab86d61cfc 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -379,8 +379,10 @@ config AD7768_1 select REGMAP_SPI select RATIONAL select IIO_BUFFER + select IIO_BUFFER_DMAENGINE select IIO_TRIGGER select IIO_TRIGGERED_BUFFER + select SPI_OFFLOAD help Say yes here to build support for Analog Devices AD7768-1 SPI simultaneously sampling sigma-delta analog to digital converter (ADC). diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index 797b176b2ea944..39ef970a3e5b46 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -25,12 +25,15 @@ #include #include #include +#include +#include #include #include #include #include #include +#include #include #include #include @@ -161,6 +164,8 @@ enum ad7768_filter_regval { enum ad7768_scan_type { AD7768_SCAN_TYPE_NORMAL, AD7768_SCAN_TYPE_HIGH_SPEED, + AD7768_SCAN_TYPE_OFFLOAD_NORMAL, + AD7768_SCAN_TYPE_OFFLOAD_HIGH_SPEED, }; enum { @@ -266,6 +271,18 @@ static const struct iio_scan_type ad7768_scan_type[] = { .storagebits = 16, .endianness = IIO_BE, }, + [AD7768_SCAN_TYPE_OFFLOAD_NORMAL] = { + .sign = 's', + .realbits = 24, + .storagebits = 32, + .endianness = IIO_CPU, + }, + [AD7768_SCAN_TYPE_OFFLOAD_HIGH_SPEED] = { + .sign = 's', + .realbits = 16, + .storagebits = 32, + .endianness = IIO_CPU, + }, }; struct ad7768_chip_info { @@ -283,6 +300,8 @@ struct ad7768_chip_info { struct ad7768_state { struct spi_device *spi; + struct spi_offload *offload; + struct spi_offload_trigger *offload_trigger; struct regmap *regmap; struct regmap *regmap24; int vref_uv; @@ -306,6 +325,8 @@ struct ad7768_state { struct gpio_desc *gpio_reset; const char *labels[AD7768_MAX_CHANNELS]; struct gpio_chip gpiochip; + struct spi_transfer offload_xfer; + struct spi_message offload_msg; const struct ad7768_chip_info *chip; bool en_spi_sync; struct mutex pga_lock; /* protect device internal state (PGA) */ @@ -1129,6 +1150,10 @@ static int ad7768_get_current_scan_type(const struct iio_dev *indio_dev, { struct ad7768_state *st = iio_priv(indio_dev); + if (st->offload) + return st->oversampling_ratio == 8 ? + AD7768_SCAN_TYPE_OFFLOAD_HIGH_SPEED : AD7768_SCAN_TYPE_OFFLOAD_NORMAL; + return st->oversampling_ratio == 8 ? AD7768_SCAN_TYPE_HIGH_SPEED : AD7768_SCAN_TYPE_NORMAL; } @@ -1351,6 +1376,78 @@ static const struct iio_buffer_setup_ops ad7768_buffer_ops = { .predisable = &ad7768_buffer_predisable, }; +static int ad7768_offload_buffer_postenable(struct iio_dev *indio_dev) +{ + struct ad7768_state *st = iio_priv(indio_dev); + struct spi_offload_trigger_config config = { + .type = SPI_OFFLOAD_TRIGGER_DATA_READY, + }; + const struct iio_scan_type *scan_type; + unsigned int unused; + int ret; + + scan_type = iio_get_current_scan_type(indio_dev, &indio_dev->channels[0]); + if (IS_ERR(scan_type)) + return PTR_ERR(scan_type); + + st->offload_xfer.len = spi_bpw_to_bytes(scan_type->realbits); + st->offload_xfer.bits_per_word = scan_type->realbits; + st->offload_xfer.offload_flags = SPI_OFFLOAD_XFER_RX_STREAM; + + spi_message_init_with_transfers(&st->offload_msg, &st->offload_xfer, 1); + st->offload_msg.offload = st->offload; + + ret = spi_optimize_message(st->spi, &st->offload_msg); + if (ret) { + dev_err(&st->spi->dev, "failed to prepare offload, err: %d\n", ret); + return ret; + } + + /* + * Write a 1 to the LSB of the INTERFACE_FORMAT register to enter + * continuous read mode. Subsequent data reads do not require an + * initial 8-bit write to query the ADC_DATA register. + */ + ret = regmap_write(st->regmap, AD7768_REG_INTERFACE_FORMAT, 0x01); + if (ret) + goto err_unoptimize_message; + + ret = spi_offload_trigger_enable(st->offload, st->offload_trigger, + &config); + if (ret) + goto err_exit_continuous_read_mode; + + return 0; + +err_exit_continuous_read_mode: + regmap_read(st->regmap24, AD7768_REG24_ADC_DATA, &unused); + +err_unoptimize_message: + spi_unoptimize_message(&st->offload_msg); + + return ret; +} + +static int ad7768_offload_buffer_predisable(struct iio_dev *indio_dev) +{ + struct ad7768_state *st = iio_priv(indio_dev); + unsigned int unused; + + spi_offload_trigger_disable(st->offload, st->offload_trigger); + spi_unoptimize_message(&st->offload_msg); + + /* + * To exit continuous read mode, perform a single read of the ADC_DATA + * reg (0x2C), which allows further configuration of the device. + */ + return regmap_read(st->regmap24, AD7768_REG24_ADC_DATA, &unused); +} + +static const struct iio_buffer_setup_ops ad7768_offload_buffer_ops = { + .postenable = ad7768_offload_buffer_postenable, + .predisable = ad7768_offload_buffer_predisable, +}; + static int ad7768_set_trigger_state(struct iio_trigger *trig, bool enable) { struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); @@ -1599,6 +1696,36 @@ static int ad7768_parse_aaf_gain(struct device *dev, struct ad7768_state *st) return 0; } +static bool ad7768_offload_trigger_match(struct spi_offload_trigger *trigger, + enum spi_offload_trigger_type type, + u64 *args, u32 nargs) +{ + if (type != SPI_OFFLOAD_TRIGGER_DATA_READY) + return false; + + /* Up to 2 args are allowed, but only 1 is used */ + if (nargs == 0 || nargs > 2 || args[0] != AD7768_TRIGGER_SOURCE_DRDY) + return false; + + return true; +} + +static int ad7768_offload_trigger_request(struct spi_offload_trigger *trigger, + enum spi_offload_trigger_type type, + u64 *args, u32 nargs) +{ + /* Should already be validated by match, but just in case */ + if (nargs == 0 || nargs > 2) + return -EINVAL; + + return 0; +} + +static const struct spi_offload_trigger_ops ad7768_offload_trigger_ops = { + .match = ad7768_offload_trigger_match, + .request = ad7768_offload_trigger_request, +}; + static const struct ad7768_chip_info ad7768_chip_info = { .name = "ad7768-1", .channel_spec = ad7768_channels, @@ -1636,10 +1763,51 @@ static const struct ad7768_chip_info adaq7769_chip_info = { .has_variable_aaf = true, }; +static const struct spi_offload_config ad7768_spi_offload_config = { + .capability_flags = SPI_OFFLOAD_CAP_TRIGGER | SPI_OFFLOAD_CAP_RX_STREAM_DMA, +}; + +static int ad7768_spi_offload_probe(struct iio_dev *indio_dev, + struct ad7768_state *st) +{ + struct device *dev = &st->spi->dev; + struct spi_offload_trigger_info trigger_info = { + .fwnode = dev_fwnode(dev), + .ops = &ad7768_offload_trigger_ops, + .priv = st, + }; + struct dma_chan *rx_dma; + int ret; + + ret = devm_spi_offload_trigger_register(dev, &trigger_info); + if (ret) + return dev_err_probe(dev, ret, "failed to register offload trigger\n"); + + st->offload_trigger = devm_spi_offload_trigger_get(dev, st->offload, + SPI_OFFLOAD_TRIGGER_DATA_READY); + if (IS_ERR(st->offload_trigger)) + return dev_err_probe(dev, PTR_ERR(st->offload_trigger), + "failed to get offload trigger\n"); + + rx_dma = devm_spi_offload_rx_stream_request_dma_chan(dev, st->offload); + if (IS_ERR(rx_dma)) + return dev_err_probe(dev, PTR_ERR(rx_dma), "failed to get offload RX DMA\n"); + + ret = devm_iio_dmaengine_buffer_setup_with_handle(dev, indio_dev, rx_dma, + IIO_BUFFER_DIRECTION_IN); + if (ret) + return dev_err_probe(dev, ret, "failed to setup offload RX DMA\n"); + + indio_dev->setup_ops = &ad7768_offload_buffer_ops; + + return 0; +} + static int ad7768_probe(struct spi_device *spi) { struct ad7768_state *st; struct iio_dev *indio_dev; + struct device *dev = &spi->dev; int ret; indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); @@ -1735,9 +1903,20 @@ static int ad7768_probe(struct spi_device *spi) if (ret) return ret; - ret = ad7768_triggered_buffer_alloc(indio_dev); - if (ret) - return ret; + st->offload = devm_spi_offload_get(dev, spi, &ad7768_spi_offload_config); + ret = PTR_ERR_OR_ZERO(st->offload); + if (ret == -ENODEV) { + /* If not using SPI offload, fall back to low speed usage */ + ret = ad7768_triggered_buffer_alloc(indio_dev); + if (ret) + return ret; + } else if (ret) { + return dev_err_probe(dev, ret, "failed to get SPI offload\n"); + } else { + ret = ad7768_spi_offload_probe(indio_dev, st); + if (ret) + return ret; + } return devm_iio_device_register(&spi->dev, indio_dev); } @@ -1773,3 +1952,4 @@ module_spi_driver(ad7768_driver); MODULE_AUTHOR("Stefan Popa "); MODULE_DESCRIPTION("Analog Devices AD7768-1 ADC driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_DMAENGINE_BUFFER);