lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <20260116192916.436d24c9@jic23-huawei>
Date: Fri, 16 Jan 2026 19:29:16 +0000
From: Jonathan Cameron <jic23@...nel.org>
To: Rodrigo Alencar via B4 Relay
 <devnull+rodrigo.alencar.analog.com@...nel.org>
Cc: rodrigo.alencar@...log.com, linux-kernel@...r.kernel.org,
 linux-iio@...r.kernel.org, devicetree@...r.kernel.org,
 linux-doc@...r.kernel.org, David Lechner <dlechner@...libre.com>, Andy
 Shevchenko <andy@...nel.org>, Lars-Peter Clausen <lars@...afoo.de>, Michael
 Hennerich <Michael.Hennerich@...log.com>, Rob Herring <robh@...nel.org>,
 Krzysztof Kozlowski <krzk+dt@...nel.org>, Conor Dooley
 <conor+dt@...nel.org>, Jonathan Corbet <corbet@....net>
Subject: Re: [PATCH v4 3/7] iio: frequency: adf41513: driver implementation

On Fri, 16 Jan 2026 14:32:22 +0000
Rodrigo Alencar via B4 Relay <devnull+rodrigo.alencar.analog.com@...nel.org> wrote:

> From: Rodrigo Alencar <rodrigo.alencar@...log.com>
> 
> The driver is based on existing PLL drivers in the IIO subsystem and
> implements the following key features:
> 
> - Integer-N and fractional-N (fixed/variable modulus) synthesis modes
> - High-resolution frequency calculations using microhertz (µHz) precision
>   to handle sub-Hz resolution across multi-GHz frequency ranges
> - IIO debugfs interface for direct register access
> - FW property parsing from devicetree including charge pump settings,
>   reference path configuration and muxout options
> - Power management support with suspend/resume callbacks
> - Lock detect GPIO monitoring
> 
> The driver uses 64-bit microhertz values throughout PLL calculations to
> maintain precision when working with frequencies that exceed 32-bit Hz
> representation while requiring fractional Hz resolution.
> 
> Signed-off-by: Rodrigo Alencar <rodrigo.alencar@...log.com>
Hi Rodrigo,

A couple of additional comments for this version.

Thanks,

Jonathan

> diff --git a/drivers/iio/frequency/adf41513.c b/drivers/iio/frequency/adf41513.c
> new file mode 100644
> index 000000000000..9068c427d8e9
> --- /dev/null
> +++ b/drivers/iio/frequency/adf41513.c



> +
> +static int adf41513_write_raw(struct iio_dev *indio_dev,
> +			      struct iio_chan_spec const *chan,
> +			      int val, int val2, long info)
> +{
> +	struct adf41513_state *st = iio_priv(indio_dev);
> +	u64 phase_urad;
> +	u16 phase_val;
> +
> +	guard(mutex)(&st->lock);
> +
> +	switch (info) {
> +	case IIO_CHAN_INFO_PHASE:
> +		phase_urad = (u64)val * MICRO + val2;
> +		if (val < 0 || val2 < 0 || phase_urad >= ADF41513_MAX_PHASE_MICRORAD)

Check val and val2 before setting phase_urad.  Whilst it's not a bug it
is a lot less readable to perform checks on inputs after you've already used
them to compute something.
		if (val < 0 || val2 < 0)
			return -EINVAL;

		phase_urad = ...
		if (phase_urad >= ...)
			return -EINVAL;

> +			return -EINVAL;
> +
> +		phase_val = DIV_U64_ROUND_CLOSEST(phase_urad << 12,
> +						  ADF41513_MAX_PHASE_MICRORAD);
> +		phase_val = min(phase_val, ADF41513_MAX_PHASE_VAL);
> +		st->regs[ADF41513_REG2] |= ADF41513_REG2_PHASE_ADJ_MSK;
> +		FIELD_MODIFY(ADF41513_REG2_PHASE_VAL_MSK,
> +			     &st->regs[ADF41513_REG2], phase_val);
> +		return adf41513_sync_config(st, ADF41513_SYNC_REG0);
> +	default:
> +		return -EINVAL;
> +	}
> +}

> +
> +static int adf41513_parse_fw(struct adf41513_state *st)
> +{
> +	struct device *dev = &st->spi->dev;
> +	int ret;
> +	u32 tmp, cp_resistance, cp_current;
> +
> +	/* power-up frequency */
> +	st->data.power_up_frequency_hz = ADF41510_MAX_RF_FREQ_HZ;
> +	ret = device_property_read_u32(dev, "adi,power-up-frequency-mhz", &tmp);
> +	if (!ret) {
Can easily do the same as below here  No precision issue given definition of
the _MAX_RF_FREQ_HZ value includes a larger power 10 multiplier.
	
	tmp = ADF41510_MAX_RF_FREQ_HZ / HZ_PER_MHZ;
	device_property_read_u32(dev, "adi,power-up-frequency-mhz", &tmp;
	st->data.power_up_frequency_hz = (u64)tmp * HZ_PER_MHZ;
	if (st...

or use a local u64 for a temporary you only assign to power_up_frequency_hz
after checks. That would be more consistent with the code that follows.

> +		st->data.power_up_frequency_hz = (u64)tmp * HZ_PER_MHZ;
> +		if (st->data.power_up_frequency_hz < ADF41513_MIN_RF_FREQ_HZ ||
> +		    st->data.power_up_frequency_hz > ADF41513_MAX_RF_FREQ_HZ)
> +			return dev_err_probe(dev, -ERANGE,
> +					     "power-up frequency %llu Hz out of range\n",
> +					     st->data.power_up_frequency_hz);
> +	}
> +
> +	tmp = ADF41513_MIN_R_CNT;
> +	device_property_read_u32(dev, "adi,reference-div-factor", &tmp);
> +	if (tmp < ADF41513_MIN_R_CNT || tmp > ADF41513_MAX_R_CNT)
> +		return dev_err_probe(dev, -ERANGE,
> +				     "invalid reference div factor %u\n", tmp);
> +	st->data.ref_div_factor = tmp;
> +
> +	st->data.ref_doubler_en = device_property_read_bool(dev, "adi,reference-doubler-enable");
> +	st->data.ref_div2_en = device_property_read_bool(dev, "adi,reference-div2-enable");
> +
> +	cp_resistance = ADF41513_DEFAULT_R_SET;
> +	device_property_read_u32(dev, "adi,charge-pump-resistor-ohms", &cp_resistance);
> +	if (cp_resistance < ADF41513_MIN_R_SET || cp_resistance > ADF41513_MAX_R_SET)
> +		return dev_err_probe(dev, -ERANGE, "R_SET %u Ohms out of range\n", cp_resistance);
> +
> +	st->data.charge_pump_voltage_mv = ADF41513_DEFAULT_CP_VOLTAGE_mV;

This leaves some odd corner cases.
If DT defines cp_resistance but not cp_current then we ignore the cp_resitance.
If you want to insist it is either both or nothing, that needs enforcing in the dt-binding.
I think I slightly prefer this option..

Alternative is define a default current such that the maths works to give the DEFAULT_CP_VOLTAGE_mV
if both properties use defaults and use that here + document in the dt-binding as the default
for this property.   That may mean if only one property is set we reject the pair and fail
to probe.  You have comment about valid combinations in the dt-binding so that's fine.
 
> +	ret = device_property_read_u32(dev, "adi,charge-pump-current-microamp", &cp_current);
> +	if (!ret) {
> +		tmp = DIV_ROUND_CLOSEST(cp_current * cp_resistance, MILLI); /* convert to mV */
> +		if (tmp < ADF41513_MIN_CP_VOLTAGE_mV || tmp > ADF41513_MAX_CP_VOLTAGE_mV)
> +			return dev_err_probe(dev, -ERANGE, "I_CP %u uA (%u Ohms) out of range\n",
> +					     cp_current, cp_resistance);
> +		st->data.charge_pump_voltage_mv = tmp;
> +	}
> +
> +	st->data.phase_detector_polarity =
> +		device_property_read_bool(dev, "adi,phase-detector-polarity-positive-enable");
> +
> +	st->data.logic_lvl_1v8_en = device_property_read_bool(dev, "adi,logic-level-1v8-enable");
> +
> +	tmp = ADF41513_LD_COUNT_MIN;
> +	device_property_read_u32(dev, "adi,lock-detector-count", &tmp);
> +	if (tmp < ADF41513_LD_COUNT_FAST_MIN || tmp > ADF41513_LD_COUNT_MAX ||
> +	    !is_power_of_2(tmp))
> +		return dev_err_probe(dev, -ERANGE,
> +				     "invalid lock detect count: %u\n", tmp);
> +	st->data.lock_detect_count = tmp;
> +
> +	st->data.freq_resolution_uhz = MICROHZ_PER_HZ;
> +
> +	return 0;
> +}


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ