Thread (13 messages) 13 messages, 4 authors, 2025-09-07

Re: [PATCH v3 4/4] iio: adc: ad7768-1: add support for ADAQ776x-1 ADC Family

From: Andy Shevchenko <hidden>
Date: 2025-09-05 17:23:40
Also in: linux-iio, lkml

On Fri, Sep 05, 2025 at 06:49:42AM -0300, Jonathan Santos 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 the device tree.
...
+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 u64_fract fract;
+	unsigned long n, d;
+	u64 tmp2;
+
+	scan_type = iio_get_current_scan_type(dev, &dev->channels[0]);
Is it usual patter in IIO? Otherwise it can be written as

	scan_type = iio_get_current_scan_type(dev, dev->channels);
+	if (scan_type->sign == 's')
+		val2 = scan_type->realbits - 1;
+	else
+		val2 = scan_type->realbits;
Wasn't smatch happy about this check?
+	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 *= 10000;
+		}
My question also was: Are these overflow u32? If not, the second patch is not
needed. Otherwise, how is the previous version supposed to work with unsigned
long type (if I am not mistaken) on 32-bit platforms?
+		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 = shift_right((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_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 *  10000,
One space too many.
+						  ad7768_aaf_gains_bp[st->aaf_gain]);
+
+	return find_closest(gain_nano, st->chip->pga_gains,
+			    (int)st->chip->num_pga_modes);
Is casting needed?
+}
...
+	case IIO_CHAN_INFO_SCALE:  {
One space too many.
+		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);
+	}
...
+static int ad7768_parse_aaf_gain(struct device *dev, struct ad7768_state *st)
+{
+	bool aaf_gain_provided;
+	u32 val;
+	int ret;
+	st->aaf_gain = AD7768_AAF_IN1;
+	ret = device_property_read_u32(dev, "adi,aaf-gain-bp", &val);
+	aaf_gain_provided = (ret == 0);
Hmm... It seems rather incorrect check. You should actually return an error
code in case it's provided but can't be read.

I would expect something like

	ret = device_property_read_u32(dev, "adi,aaf-gain-bp", &val);
	if (ret == -EINVAL)
		_gain_provided = false;
	else if (ret)
		return dev_err_probe(...);
	else
		_gain_provided = true;
+	if (!aaf_gain_provided && st->chip->has_variable_aaf) {
+		dev_warn(dev, "AAF gain not specified, using default\n");
+		return 0;
+	}
+
+	if (aaf_gain_provided && !st->chip->has_variable_aaf) {
+		dev_warn(dev, "AAF gain not supported for %s\n", st->chip->name);
+		return 0;
+	}
We can refactor these to have one level indentation less for the switch-case.

	if (aaf_gain_provided && !st->chip->has_variable_aaf) {
		dev_warn(dev, "AAF gain not supported for %s\n", st->chip->name);
		return 0;
	}

	if (!aaf_gain_provided) {
		if (st->chip->has_variable_aaf)
			dev_warn(dev, "AAF gain not specified, using default\n");
		return 0;
	}
+	if (aaf_gain_provided) {
So this one may be dropped.
+		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;
+}
-- 
With Best Regards,
Andy Shevchenko

Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help