* [PATCH v2 4/4] iio: adc: ad7768-1: add support for ADAQ776x-1 ADC Family
@ 2025-08-24 4:10 Jonathan Santos
2025-08-24 19:43 ` Andy Shevchenko
2025-08-25 14:44 ` Jonathan Cameron
0 siblings, 2 replies; 7+ messages in thread
From: Jonathan Santos @ 2025-08-24 4:10 UTC (permalink / raw)
To: linux-kernel, linux-iio, devicetree
Cc: Jonathan Santos, Michael.Hennerich, lars, jic23, dlechner,
nuno.sa, andy, robh, krzk+dt, conor+dt, marcelo.schmitt1
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 enabled and controlled by the GPIO
controller (GPIOs 0, 1 and 2) provided by the device with the SPI
interface.
The AAF gain is defined by hardware connections and should be specified
in device tree.
Signed-off-by: Jonathan Santos <Jonathan.Santos@analog.com>
---
v2 Changes:
* Added more details to the commit message.
* Some devices does not provide VCM regulator, so a new field in
the chip info struct was added to indicate this.
* Added 'select RATIONAL' to Kconfig. Kernel test robot pointed out
compilation error due to undefined reference to
rational_best_approximation().
* Added lock to protect PGA value access.
* precision in the PGA calculation is now dependent of the channel sign
(signed or unsigned).
* went back to the original scale computation: (st->vref_uv * 2) / 2^n
instead of st->vref_uv / 2^(n-1).
* rewrote AAF gain check and replaced error returns with warnings. I the
AAF gain is not provided, a default value is used.
* Addressed other minor suggestions.
---
drivers/iio/adc/Kconfig | 1 +
drivers/iio/adc/ad7768-1.c | 288 ++++++++++++++++++++++++++++++++++++-
2 files changed, 286 insertions(+), 3 deletions(-)
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 6de2abad0197..7c5fe3954514 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -374,6 +374,7 @@ config AD7768_1
depends on SPI
select REGULATOR
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 51562367a9d4..61d93dbfc4c6 100644
--- a/drivers/iio/adc/ad7768-1.c
+++ b/drivers/iio/adc/ad7768-1.c
@@ -6,6 +6,7 @@
*/
#include <linux/array_size.h>
#include <linux/bitfield.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/delay.h>
@@ -14,8 +15,11 @@
#include <linux/gpio/driver.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
+#include <linux/limits.h>
#include <linux/minmax.h>
#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/rational.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/regulator/driver.h>
@@ -98,15 +102,21 @@
/* AD7768_REG_GPIO_CONTROL */
#define AD7768_GPIO_UNIVERSAL_EN BIT(7)
#define AD7768_GPIO_CONTROL_MSK GENMASK(3, 0)
+#define AD7768_GPIO_PGIA_EN (AD7768_GPIO_UNIVERSAL_EN | GENMASK(2, 0))
/* AD7768_REG_GPIO_WRITE */
#define AD7768_GPIO_WRITE_MSK GENMASK(3, 0)
+#define AD7768_GPIO_WRITE(x) FIELD_PREP(AD7768_GPIO_WRITE_MSK, x)
/* AD7768_REG_GPIO_READ */
#define AD7768_GPIO_READ_MSK GENMASK(3, 0)
+#define AD7768_GPIO_READ(x) FIELD_PREP(AD7768_GPIO_READ_MSK, x)
#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
@@ -153,6 +163,52 @@ 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,
+ AD7768_MAX_PGA_GAIN,
+};
+
+enum {
+ AD7768_AAF_IN1,
+ AD7768_AAF_IN2,
+ AD7768_AAF_IN3,
+};
+
+/* PGA and AAF gains in V/V */
+static const int adaq7768_gains[7] = {
+ [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[8] = {
+ [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[3] = {
+ [AD7768_AAF_IN1] = 1000, /* 1.000 */
+ [AD7768_AAF_IN2] = 364, /* 0.364 */
+ [AD7768_AAF_IN3] = 143 /* 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 */
@@ -218,6 +274,13 @@ struct ad7768_chip_info {
const unsigned long *available_masks;
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 {
@@ -235,6 +298,9 @@ struct ad7768_state {
unsigned int samp_freq;
unsigned int samp_freq_avail[ARRAY_SIZE(ad7768_mclk_div_rates)];
unsigned int samp_freq_avail_len;
+ int pga_gain_mode;
+ int aaf_gain;
+ int scale_tbl[ADAQ776X_MAX_GAIN_MODES][2];
struct completion completion;
struct iio_trigger *trig;
struct gpio_desc *gpio_sync_in;
@@ -243,6 +309,7 @@ struct ad7768_state {
struct gpio_chip gpiochip;
const struct ad7768_chip_info *chip;
bool en_spi_sync;
+ struct mutex pga_lock; /* protect PGA value access */
/*
* DMA (thus cache coherency maintenance) may require the
* transfer buffers to live in their own cache lines.
@@ -465,6 +532,41 @@ 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;
+ unsigned long denominator, numerator;
+ 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 */
+ numerator = st->chip->pga_gains[i];
+ denominator = MILLI;
+ if (st->chip->has_variable_aaf) {
+ numerator *= ad7768_aaf_gains[st->aaf_gain];
+ denominator *= MILLI;
+ }
+
+ rational_best_approximation(numerator, denominator, INT_MAX, INT_MAX,
+ &numerator, &denominator);
+
+ val = mult_frac(st->vref_uv, denominator, numerator);
+ /* Would multiply by NANO here, but value is already in milli */
+ tmp2 = shift_right((u64)val * MICRO, val2);
+ tmp0 = (int)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)
{
@@ -566,12 +668,67 @@ 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_calc_pga_gain(struct ad7768_state *st, int gain_int,
+ int gain_fract, int precision)
+{
+ u64 gain_nano;
+ int gain_idx;
+ 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)
+ /* remove the AAF gain from the overall gain */
+ gain_nano = DIV_ROUND_CLOSEST_ULL(gain_nano * MILLI,
+ ad7768_aaf_gains[st->aaf_gain]);
+ tmp = st->chip->num_pga_modes;
+ gain_idx = find_closest(gain_nano, st->chip->pga_gains, tmp);
+
+ return gain_idx;
+}
+
+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);
+ int check_val;
+ int ret;
+
+ guard(mutex)(&st->pga_lock);
+ /* Check GPIO control register */
+ ret = regmap_read(st->regmap, AD7768_REG_GPIO_CONTROL, &check_val);
+ if (ret < 0)
+ return ret;
+
+ if ((check_val & AD7768_GPIO_PGIA_EN) != AD7768_GPIO_PGIA_EN) {
+ /* Enable PGIA GPIOs and set them as output */
+ ret = regmap_write(st->regmap, AD7768_REG_GPIO_CONTROL, AD7768_GPIO_PGIA_EN);
+ if (ret)
+ return ret;
+ }
+
+ /* Write the respective gain values to GPIOs 0, 1, 2 */
+ ret = regmap_write(st->regmap, AD7768_REG_GPIO_WRITE,
+ AD7768_GPIO_WRITE(pgia_pins_value));
+ 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);
@@ -781,6 +938,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)
@@ -808,7 +969,18 @@ static int ad7768_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
+ 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;
+ }
+
*val = (st->vref_uv * 2) / 1000;
+ if (st->chip->has_variable_aaf)
+ *val = (*val * MILLI) / ad7768_aaf_gains[st->aaf_gain];
+
*val2 = scan_type->realbits;
return IIO_VAL_FRACTIONAL_LOG2;
@@ -864,18 +1036,42 @@ 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;
+ }
+
+ return -EINVAL;
+}
+
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 gain_mode;
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:
return ad7768_set_freq(st, val);
@@ -887,6 +1083,18 @@ static int __ad7768_write_raw(struct iio_dev *indio_dev,
/* Update sampling frequency */
return ad7768_set_freq(st, st->samp_freq);
+ case IIO_CHAN_INFO_SCALE:
+ 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;
}
@@ -928,6 +1136,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,
@@ -1344,12 +1553,47 @@ static const struct ad7768_chip_info ad7768_chip_info = {
.channel_spec = ad7768_channels,
.num_channels = ARRAY_SIZE(ad7768_channels),
.available_masks = ad7768_channel_masks,
+ .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),
+ .available_masks = ad7768_channel_masks,
+ .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),
+ .available_masks = ad7768_channel_masks,
+ .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),
+ .available_masks = ad7768_channel_masks,
+ .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)
{
struct ad7768_state *st;
struct iio_dev *indio_dev;
+ u32 val;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
@@ -1409,9 +1653,37 @@ 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 (ret)
- return ret;
+ if (st->chip->has_vcm_regulator) {
+ ret = ad7768_register_regulators(&spi->dev, st, indio_dev);
+ if (ret)
+ return ret;
+ }
+
+ st->aaf_gain = AD7768_AAF_IN1;
+ ret = device_property_read_u32(&spi->dev, "adi,gain-milli", &val);
+ if (ret && st->chip->has_variable_aaf)
+ dev_warn(&spi->dev, "AAF gain not specified, using default\n");
+
+ if (!ret && !st->chip->has_variable_aaf)
+ dev_warn(&spi->dev, "AAF gain not supported for %s\n", st->chip->name);
+
+ if (!ret) {
+ /* If provided, validate and set the gain */
+ switch (val) {
+ case 1000:
+ st->aaf_gain = AD7768_AAF_IN1;
+ break;
+ case 364:
+ st->aaf_gain = AD7768_AAF_IN2;
+ break;
+ case 143:
+ st->aaf_gain = AD7768_AAF_IN3;
+ break;
+ default:
+ return dev_err_probe(&spi->dev, -EINVAL,
+ "Invalid firmware provided AAF gain\n");
+ }
+ }
ret = ad7768_setup(indio_dev);
if (ret < 0) {
@@ -1420,6 +1692,10 @@ static int ad7768_probe(struct spi_device *spi)
}
init_completion(&st->completion);
+ mutex_init(&st->pga_lock);
+
+ if (st->chip->has_pga)
+ ad7768_set_pga_gain(st, st->chip->default_pga_mode);
ret = ad7768_set_channel_label(indio_dev, st->chip->num_channels);
if (ret)
@@ -1441,12 +1717,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);
--
2.34.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v2 4/4] iio: adc: ad7768-1: add support for ADAQ776x-1 ADC Family
2025-08-24 4:10 [PATCH v2 4/4] iio: adc: ad7768-1: add support for ADAQ776x-1 ADC Family Jonathan Santos
@ 2025-08-24 19:43 ` Andy Shevchenko
2025-08-29 19:11 ` Jonathan Santos
2025-08-25 14:44 ` Jonathan Cameron
1 sibling, 1 reply; 7+ messages in thread
From: Andy Shevchenko @ 2025-08-24 19:43 UTC (permalink / raw)
To: Jonathan Santos
Cc: linux-kernel, linux-iio, devicetree, Michael.Hennerich, lars,
jic23, dlechner, nuno.sa, andy, robh, krzk+dt, conor+dt,
marcelo.schmitt1
On Sun, Aug 24, 2025 at 7:10 AM Jonathan Santos
<Jonathan.Santos@analog.com> wrote:
>
> 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 enabled and controlled by the GPIO
> controller (GPIOs 0, 1 and 2) provided by the device with the SPI
> interface.
>
> The AAF gain is defined by hardware connections and should be specified
> in device tree.
the device
...
> +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,
> + AD7768_MAX_PGA_GAIN,
No trailing comma for the terminator line and I haven't noticed if
it's even being used in the code...
> +};
...
> +/* PGA and AAF gains in V/V */
> +static const int adaq7768_gains[7] = {
The 7 is redundant. Leave it for the compiler.
> + [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 */
Please, leave a trailing comma.
> +};
> +
> +static const int adaq7769_gains[8] = {
8 is redundant.
> + [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 */
Please, leave a trailing comma.
> +};
> +static const int ad7768_aaf_gains[3] = {
3 is redundant,
> + [AD7768_AAF_IN1] = 1000, /* 1.000 */
> + [AD7768_AAF_IN2] = 364, /* 0.364 */
> + [AD7768_AAF_IN3] = 143 /* 0.143 */
Please, leave a trailing comma.
> +};
...
> static const int ad7768_filter_3db_odr_multiplier[] = {
> [AD7768_FILTER_SINC5] = 204, /* 0.204 */
> const unsigned long *available_masks;
> 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;
> };
Same comments as per below.
...
> struct ad7768_state {
> unsigned int samp_freq;
> unsigned int samp_freq_avail[ARRAY_SIZE(ad7768_mclk_div_rates)];
> unsigned int samp_freq_avail_len;
> + int pga_gain_mode;
> + int aaf_gain;
> + int scale_tbl[ADAQ776X_MAX_GAIN_MODES][2];
Why all signed?
> struct completion completion;
> struct iio_trigger *trig;
> struct gpio_desc *gpio_sync_in;
> struct gpio_chip gpiochip;
> const struct ad7768_chip_info *chip;
> bool en_spi_sync;
> + struct mutex pga_lock; /* protect PGA value access */
> }
Have you run `pahole`? Does it suggest a better layout?
...
> +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;
> + unsigned long denominator, numerator;
struct u32_fract fract;
> + 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 */
> + numerator = st->chip->pga_gains[i];
> + denominator = MILLI;
> + if (st->chip->has_variable_aaf) {
> + numerator *= ad7768_aaf_gains[st->aaf_gain];
> + denominator *= MILLI;
> + }
> +
> + rational_best_approximation(numerator, denominator, INT_MAX, INT_MAX,
> + &numerator, &denominator);
> +
> + val = mult_frac(st->vref_uv, denominator, numerator);
> + /* Would multiply by NANO here, but value is already in milli */
> + tmp2 = shift_right((u64)val * MICRO, val2);
> + tmp0 = (int)div_u64_rem(tmp2, NANO, &tmp1);
Why casting here?
> + st->scale_tbl[i][0] = tmp0; /* Integer part */
> + st->scale_tbl[i][1] = abs(tmp1); /* Fractional part */
> + }
> +}
...
> +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);
> + int check_val;
> + int ret;
> +
> + guard(mutex)(&st->pga_lock);
+ Blank line.
> + /* Check GPIO control register */
> + ret = regmap_read(st->regmap, AD7768_REG_GPIO_CONTROL, &check_val);
> + if (ret < 0)
Here and elsewhere when it makes sense, drop redundant ' < 0' pieces.
It's even inconsistent in the same patch with how you check other
regmap returned calls.
> + return ret;
> + return 0;
> +}
...
> case IIO_CHAN_INFO_SCALE:
> + 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;
> + }
> +
> *val = (st->vref_uv * 2) / 1000;
> + if (st->chip->has_variable_aaf)
> + *val = (*val * MILLI) / ad7768_aaf_gains[st->aaf_gain];
This is unreadable. Just use a temporary variable for all calculations
and when it's done, assign *val to it.
> *val2 = scan_type->realbits;
>
> return IIO_VAL_FRACTIONAL_LOG2;
...
> +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;
> + }
> +
> + return -EINVAL;
What's the point in this return, please?
> +}
...
> static const struct ad7768_chip_info ad7768_chip_info = {
> .channel_spec = ad7768_channels,
> .num_channels = ARRAY_SIZE(ad7768_channels),
> .available_masks = ad7768_channel_masks,
> + .has_vcm_regulator = true
Missing trailing comma. Also same in the below. I believe I have
pointed that out in v1.
> +};
> +
> +static const struct ad7768_chip_info adaq7767_chip_info = {
> + .name = "adaq7767-1",
> + .channel_spec = ad7768_channels,
> + .num_channels = ARRAY_SIZE(ad7768_channels),
> + .available_masks = ad7768_channel_masks,
> + .has_variable_aaf = true
> +};
> +static const struct ad7768_chip_info adaq7769_chip_info = {
> + .name = "adaq7769-1",
> + .channel_spec = adaq776x_channels,
> + .num_channels = ARRAY_SIZE(adaq776x_channels),
> + .available_masks = ad7768_channel_masks,
> + .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
> };
...
> init_completion(&st->completion);
> + mutex_init(&st->pga_lock);
Perhaps devm_mutex_init()?
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 4/4] iio: adc: ad7768-1: add support for ADAQ776x-1 ADC Family
2025-08-24 4:10 [PATCH v2 4/4] iio: adc: ad7768-1: add support for ADAQ776x-1 ADC Family Jonathan Santos
2025-08-24 19:43 ` Andy Shevchenko
@ 2025-08-25 14:44 ` Jonathan Cameron
2025-08-27 2:57 ` Jonathan Santos
1 sibling, 1 reply; 7+ messages in thread
From: Jonathan Cameron @ 2025-08-25 14:44 UTC (permalink / raw)
To: Jonathan Santos
Cc: linux-kernel, linux-iio, devicetree, Michael.Hennerich, lars,
dlechner, nuno.sa, andy, robh, krzk+dt, conor+dt,
marcelo.schmitt1
On Sun, 24 Aug 2025 01:10:13 -0300
Jonathan Santos <Jonathan.Santos@analog.com> wrote:
> 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 enabled and controlled by the GPIO
> controller (GPIOs 0, 1 and 2) provided by the device with the SPI
> interface.
>
> The AAF gain is defined by hardware connections and should be specified
> in device tree.
>
> Signed-off-by: Jonathan Santos <Jonathan.Santos@analog.com>
Hi Jonathan
Various minor comments inline.
Thanks,
Jonathan
> diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c
> index 51562367a9d4..61d93dbfc4c6 100644
> --- a/drivers/iio/adc/ad7768-1.c
> +++ b/drivers/iio/adc/ad7768-1.c
>
> struct ad7768_state {
> @@ -235,6 +298,9 @@ struct ad7768_state {
> unsigned int samp_freq;
> unsigned int samp_freq_avail[ARRAY_SIZE(ad7768_mclk_div_rates)];
> unsigned int samp_freq_avail_len;
> + int pga_gain_mode;
> + int aaf_gain;
> + int scale_tbl[ADAQ776X_MAX_GAIN_MODES][2];
> struct completion completion;
> struct iio_trigger *trig;
> struct gpio_desc *gpio_sync_in;
> @@ -243,6 +309,7 @@ struct ad7768_state {
> struct gpio_chip gpiochip;
> const struct ad7768_chip_info *chip;
> bool en_spi_sync;
> + struct mutex pga_lock; /* protect PGA value access */
why? What is special about that value? Is it only state in device?
If so I'd go with
/* protect device internal state (PGA) */
> +static int ad7768_calc_pga_gain(struct ad7768_state *st, int gain_int,
> + int gain_fract, int precision)
> +{
> + u64 gain_nano;
> + int gain_idx;
> + 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)
> + /* remove the AAF gain from the overall gain */
> + gain_nano = DIV_ROUND_CLOSEST_ULL(gain_nano * MILLI,
> + ad7768_aaf_gains[st->aaf_gain]);
> + tmp = st->chip->num_pga_modes;
> + gain_idx = find_closest(gain_nano, st->chip->pga_gains, tmp);
put tmp inline. It's not adding anything by having it in the local variable
where it's not so obvious it is the number of the previous parameter.
> +
> + return gain_idx;
> +}
> +
> +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);
> + int check_val;
> + int ret;
> +
> + guard(mutex)(&st->pga_lock);
> + /* Check GPIO control register */
The code is pretty much saying what that comment does. Drop the comment.
> + ret = regmap_read(st->regmap, AD7768_REG_GPIO_CONTROL, &check_val);
> + if (ret < 0)
> + return ret;
> +
> + if ((check_val & AD7768_GPIO_PGIA_EN) != AD7768_GPIO_PGIA_EN) {
> + /* Enable PGIA GPIOs and set them as output */
> + ret = regmap_write(st->regmap, AD7768_REG_GPIO_CONTROL, AD7768_GPIO_PGIA_EN);
Why check it? Just write it and rely on regcache making that only happen once
if at all. If you need to be careful about double writing - add a comment.
> + if (ret)
> + return ret;
> + }
> +
> + /* Write the respective gain values to GPIOs 0, 1, 2 */
> + ret = regmap_write(st->regmap, AD7768_REG_GPIO_WRITE,
> + AD7768_GPIO_WRITE(pgia_pins_value));
> + if (ret)
> + return ret;
> +
> + st->pga_gain_mode = gain_mode;
> +
> + return 0;
> +}
> 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 gain_mode;
> int ret;
Might as well combine ret and gain_mode on one line.
or pus gain_mode down into a more local scope so it's not defined here
at all.
>
> + 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:
> return ad7768_set_freq(st, val);
> @@ -887,6 +1083,18 @@ static int __ad7768_write_raw(struct iio_dev *indio_dev,
>
> /* Update sampling frequency */
> return ad7768_set_freq(st, st->samp_freq);
> + case IIO_CHAN_INFO_SCALE:
> + 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);
> static int ad7768_probe(struct spi_device *spi)
> {
> struct ad7768_state *st;
> struct iio_dev *indio_dev;
> + u32 val;
> int ret;
>
> indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
> @@ -1409,9 +1653,37 @@ 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 (ret)
> - return ret;
> + if (st->chip->has_vcm_regulator) {
> + ret = ad7768_register_regulators(&spi->dev, st, indio_dev);
> + if (ret)
> + return ret;
> + }
> +
> + st->aaf_gain = AD7768_AAF_IN1;
> + ret = device_property_read_u32(&spi->dev, "adi,gain-milli", &val);
> + if (ret && st->chip->has_variable_aaf)
> + dev_warn(&spi->dev, "AAF gain not specified, using default\n");
> +
> + if (!ret && !st->chip->has_variable_aaf)
> + dev_warn(&spi->dev, "AAF gain not supported for %s\n", st->chip->name);
I'm confused. If you hit this warn, you then go ahead and set it anyway. How does that
work?
> +
> + if (!ret) {
use a local bool for ret here with a suitable name. Carrying on using ret is
fragile against later code changes where someone doesn't realise it is still in use.
> + /* If provided, validate and set the gain */
> + switch (val) {
> + case 1000:
> + st->aaf_gain = AD7768_AAF_IN1;
> + break;
> + case 364:
> + st->aaf_gain = AD7768_AAF_IN2;
> + break;
> + case 143:
> + st->aaf_gain = AD7768_AAF_IN3;
> + break;
> + default:
> + return dev_err_probe(&spi->dev, -EINVAL,
> + "Invalid firmware provided AAF gain\n");
> + }
> + }
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 4/4] iio: adc: ad7768-1: add support for ADAQ776x-1 ADC Family
2025-08-25 14:44 ` Jonathan Cameron
@ 2025-08-27 2:57 ` Jonathan Santos
2025-08-31 12:30 ` Jonathan Cameron
0 siblings, 1 reply; 7+ messages in thread
From: Jonathan Santos @ 2025-08-27 2:57 UTC (permalink / raw)
To: Jonathan Cameron
Cc: Jonathan Santos, linux-kernel, linux-iio, devicetree,
Michael.Hennerich, lars, dlechner, nuno.sa, andy, robh, krzk+dt,
conor+dt, marcelo.schmitt1
On 08/25, Jonathan Cameron wrote:
> On Sun, 24 Aug 2025 01:10:13 -0300
> Jonathan Santos <Jonathan.Santos@analog.com> wrote:
>
> > 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 enabled and controlled by the GPIO
> > controller (GPIOs 0, 1 and 2) provided by the device with the SPI
> > interface.
> >
> > The AAF gain is defined by hardware connections and should be specified
> > in device tree.
> >
> > Signed-off-by: Jonathan Santos <Jonathan.Santos@analog.com>
> Hi Jonathan
>
> Various minor comments inline.
>
> Thanks,
>
> Jonathan
>
...
> > /* Register VCM output regulator */
> > - ret = ad7768_register_regulators(&spi->dev, st, indio_dev);
> > - if (ret)
> > - return ret;
> > + if (st->chip->has_vcm_regulator) {
> > + ret = ad7768_register_regulators(&spi->dev, st, indio_dev);
> > + if (ret)
> > + return ret;
> > + }
> > +
> > + st->aaf_gain = AD7768_AAF_IN1;
> > + ret = device_property_read_u32(&spi->dev, "adi,gain-milli", &val);
> > + if (ret && st->chip->has_variable_aaf)
> > + dev_warn(&spi->dev, "AAF gain not specified, using default\n");
> > +
> > + if (!ret && !st->chip->has_variable_aaf)
> > + dev_warn(&spi->dev, "AAF gain not supported for %s\n", st->chip->name);
>
> I'm confused. If you hit this warn, you then go ahead and set it anyway. How does that
> work?
>
I would be setting a variable that will not be used, so no functional impact.
I could add another condition to avoid assigning it, or do you believe it
is better to return error like before?
> > +
> > + if (!ret) {
> use a local bool for ret here with a suitable name. Carrying on using ret is
> fragile against later code changes where someone doesn't realise it is still in use.
>
Maybe it is better to handle this in a helper function and apply the
suggestion.
> > + /* If provided, validate and set the gain */
> > + switch (val) {
> > + case 1000:
> > + st->aaf_gain = AD7768_AAF_IN1;
> > + break;
> > + case 364:
> > + st->aaf_gain = AD7768_AAF_IN2;
> > + break;
> > + case 143:
> > + st->aaf_gain = AD7768_AAF_IN3;
> > + break;
> > + default:
> > + return dev_err_probe(&spi->dev, -EINVAL,
> > + "Invalid firmware provided AAF gain\n");
> > + }
> > + }
Regards,
Jonathan S.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 4/4] iio: adc: ad7768-1: add support for ADAQ776x-1 ADC Family
2025-08-24 19:43 ` Andy Shevchenko
@ 2025-08-29 19:11 ` Jonathan Santos
2025-08-30 4:54 ` Andy Shevchenko
0 siblings, 1 reply; 7+ messages in thread
From: Jonathan Santos @ 2025-08-29 19:11 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Jonathan Santos, linux-kernel, linux-iio, devicetree,
Michael.Hennerich, lars, jic23, dlechner, nuno.sa, andy, robh,
krzk+dt, conor+dt, marcelo.schmitt1
On 08/24, Andy Shevchenko wrote:
> On Sun, Aug 24, 2025 at 7:10 AM Jonathan Santos
> <Jonathan.Santos@analog.com> wrote:
> >
> > 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 enabled and controlled by the GPIO
> > controller (GPIOs 0, 1 and 2) provided by the device with the SPI
> > interface.
> >
> > The AAF gain is defined by hardware connections and should be specified
> > in device tree.
>
> the device
>
> ...
>
...
> > struct completion completion;
> > struct iio_trigger *trig;
> > struct gpio_desc *gpio_sync_in;
>
> > struct gpio_chip gpiochip;
> > const struct ad7768_chip_info *chip;
> > bool en_spi_sync;
> > + struct mutex pga_lock; /* protect PGA value access */
>
> > }
>
> Have you run `pahole`? Does it suggest a better layout?
>
> ...
>
yes, I have run with the reorganaize option, tried a few combinations, but couldn't found a better arrengement.
> > +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;
>
> > + unsigned long denominator, numerator;
>
> struct u32_fract fract;
>
Problem is that rational_best_approximation requires a unsigned long. I
could do:
rational_best_approximation(fract.numerator, fract.denominator,
INT_MAX, INT_MAX,
(unsigned long *)&fract.numerator,
(unsigned long *)&fract.denominator);
But I don't know if this is the best practice.
One way around this would be to represent the gains in fractions instead
of 1000x, example:
static const int ad7768_gains_frac[][2] = {
...
[AD7768_PGA_GAIN_3] = { 13, 5 }, /* 2.600 */
...
};
then we could drop the rational approximation.
> > + 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 */
> > + numerator = st->chip->pga_gains[i];
> > + denominator = MILLI;
> > + if (st->chip->has_variable_aaf) {
> > + numerator *= ad7768_aaf_gains[st->aaf_gain];
> > + denominator *= MILLI;
> > + }
> > +
> > + rational_best_approximation(numerator, denominator, INT_MAX, INT_MAX,
> > + &numerator, &denominator);
> > +
> > + val = mult_frac(st->vref_uv, denominator, numerator);
> > + /* Would multiply by NANO here, but value is already in milli */
> > + tmp2 = shift_right((u64)val * MICRO, val2);
...
> > init_completion(&st->completion);
> > + mutex_init(&st->pga_lock);
>
> Perhaps devm_mutex_init()?
>
sure!
> --
> With Best Regards,
> Andy Shevchenko
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 4/4] iio: adc: ad7768-1: add support for ADAQ776x-1 ADC Family
2025-08-29 19:11 ` Jonathan Santos
@ 2025-08-30 4:54 ` Andy Shevchenko
0 siblings, 0 replies; 7+ messages in thread
From: Andy Shevchenko @ 2025-08-30 4:54 UTC (permalink / raw)
To: CAHp75VcGG_h+wpo7hHL=ERYqbrvvAaufwPAYBsEbRn3dB8-dfA
Cc: Jonathan Santos, linux-kernel, linux-iio, devicetree,
Michael.Hennerich, lars, jic23, dlechner, nuno.sa, andy, robh,
krzk+dt, conor+dt, marcelo.schmitt1
On Fri, Aug 29, 2025 at 10:11 PM Jonathan Santos <jonath4nns@gmail.com> wrote:
> On 08/24, Andy Shevchenko wrote:
> > On Sun, Aug 24, 2025 at 7:10 AM Jonathan Santos
...
> > > + unsigned long denominator, numerator;
> >
> > struct u32_fract fract;
>
> Problem is that rational_best_approximation requires a unsigned long. I
> could do:
>
> rational_best_approximation(fract.numerator, fract.denominator,
> INT_MAX, INT_MAX,
> (unsigned long *)&fract.numerator,
> (unsigned long *)&fract.denominator);
No, this is not good. And it will overflow. See below for a better alternative.
> But I don't know if this is the best practice.
The best practice is to add a patch to extend that to cover unsigned
long and long
https://elixir.bootlin.com/linux/v6.17-rc3/source/include/linux/math.h#L122
It's just a couple of lines which I review and acknowledge
immediately. (Just make them a precursor patch)
BUT, looking at the code, I don't see that people use the same
variables for input and output (otherwise it's also considered not the
best practice, for example, in the cases when input can be made a
const).
That said, the patching math.h is optional, either way, make sure your
input and output are different variables.
> One way around this would be to represent the gains in fractions instead of 1000x, example:
> then we could drop the rational approximation.
I like the use of rational best approximation. I think it gives a
really nice algo for simplifying fractions.
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 4/4] iio: adc: ad7768-1: add support for ADAQ776x-1 ADC Family
2025-08-27 2:57 ` Jonathan Santos
@ 2025-08-31 12:30 ` Jonathan Cameron
0 siblings, 0 replies; 7+ messages in thread
From: Jonathan Cameron @ 2025-08-31 12:30 UTC (permalink / raw)
To: Jonathan Santos
Cc: 20250825154450.75eedc9b, Jonathan Santos, linux-kernel, linux-iio,
devicetree, Michael.Hennerich, lars, dlechner, nuno.sa, andy,
robh, krzk+dt, conor+dt, marcelo.schmitt1
On Tue, 26 Aug 2025 23:57:44 -0300
Jonathan Santos <jonath4nns@gmail.com> wrote:
> On 08/25, Jonathan Cameron wrote:
> > On Sun, 24 Aug 2025 01:10:13 -0300
> > Jonathan Santos <Jonathan.Santos@analog.com> wrote:
> >
> > > 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 enabled and controlled by the GPIO
> > > controller (GPIOs 0, 1 and 2) provided by the device with the SPI
> > > interface.
> > >
> > > The AAF gain is defined by hardware connections and should be specified
> > > in device tree.
> > >
> > > Signed-off-by: Jonathan Santos <Jonathan.Santos@analog.com>
> > Hi Jonathan
> >
> > Various minor comments inline.
> >
> > Thanks,
> >
> > Jonathan
> >
> ...
> > > /* Register VCM output regulator */
> > > - ret = ad7768_register_regulators(&spi->dev, st, indio_dev);
> > > - if (ret)
> > > - return ret;
> > > + if (st->chip->has_vcm_regulator) {
> > > + ret = ad7768_register_regulators(&spi->dev, st, indio_dev);
> > > + if (ret)
> > > + return ret;
> > > + }
> > > +
> > > + st->aaf_gain = AD7768_AAF_IN1;
> > > + ret = device_property_read_u32(&spi->dev, "adi,gain-milli", &val);
> > > + if (ret && st->chip->has_variable_aaf)
> > > + dev_warn(&spi->dev, "AAF gain not specified, using default\n");
> > > +
> > > + if (!ret && !st->chip->has_variable_aaf)
> > > + dev_warn(&spi->dev, "AAF gain not supported for %s\n", st->chip->name);
> >
> > I'm confused. If you hit this warn, you then go ahead and set it anyway. How does that
> > work?
> >
>
> I would be setting a variable that will not be used, so no functional impact.
> I could add another condition to avoid assigning it, or do you believe it
> is better to return error like before?
Just don't set it to avoid confusion. Alternative would be a comment that says that
it won't be used, which is probably more complex than the code.
>
> > > +
> > > + if (!ret) {
> > use a local bool for ret here with a suitable name. Carrying on using ret is
> > fragile against later code changes where someone doesn't realise it is still in use.
> >
>
> Maybe it is better to handle this in a helper function and apply the
> suggestion.
If that works, sounds good!
J
>
> > > + /* If provided, validate and set the gain */
> > > + switch (val) {
> > > + case 1000:
> > > + st->aaf_gain = AD7768_AAF_IN1;
> > > + break;
> > > + case 364:
> > > + st->aaf_gain = AD7768_AAF_IN2;
> > > + break;
> > > + case 143:
> > > + st->aaf_gain = AD7768_AAF_IN3;
> > > + break;
> > > + default:
> > > + return dev_err_probe(&spi->dev, -EINVAL,
> > > + "Invalid firmware provided AAF gain\n");
> > > + }
> > > + }
>
> Regards,
> Jonathan S.
>
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2025-08-31 12:30 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-24 4:10 [PATCH v2 4/4] iio: adc: ad7768-1: add support for ADAQ776x-1 ADC Family Jonathan Santos
2025-08-24 19:43 ` Andy Shevchenko
2025-08-29 19:11 ` Jonathan Santos
2025-08-30 4:54 ` Andy Shevchenko
2025-08-25 14:44 ` Jonathan Cameron
2025-08-27 2:57 ` Jonathan Santos
2025-08-31 12:30 ` Jonathan Cameron
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).