From: Jonathan Cameron <jic23@kernel.org>
To: Rodrigo Alencar via B4 Relay
<devnull+rodrigo.alencar.analog.com@kernel.org>
Cc: rodrigo.alencar@analog.com, linux-kernel@vger.kernel.org,
linux-iio@vger.kernel.org, devicetree@vger.kernel.org,
linux-doc@vger.kernel.org, David Lechner <dlechner@baylibre.com>,
Andy Shevchenko <andy@kernel.org>,
Lars-Peter Clausen <lars@metafoo.de>,
Michael Hennerich <Michael.Hennerich@analog.com>,
Rob Herring <robh@kernel.org>,
Krzysztof Kozlowski <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>,
Jonathan Corbet <corbet@lwn.net>
Subject: Re: [PATCH v4 3/7] iio: frequency: adf41513: driver implementation
Date: Fri, 16 Jan 2026 19:29:16 +0000 [thread overview]
Message-ID: <20260116192916.436d24c9@jic23-huawei> (raw)
In-Reply-To: <20260116-adf41513-iio-driver-v4-3-dbb7d6782217@analog.com>
On Fri, 16 Jan 2026 14:32:22 +0000
Rodrigo Alencar via B4 Relay <devnull+rodrigo.alencar.analog.com@kernel.org> wrote:
> From: Rodrigo Alencar <rodrigo.alencar@analog.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@analog.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;
> +}
next prev parent reply other threads:[~2026-01-16 19:29 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-01-16 14:32 [PATCH v4 0/7] ADF41513/ADF41510 PLL frequency synthesizers Rodrigo Alencar via B4 Relay
2026-01-16 14:32 ` [PATCH v4 1/7] dt-bindings: iio: frequency: add adf41513 Rodrigo Alencar via B4 Relay
2026-01-16 14:35 ` Krzysztof Kozlowski
2026-01-16 14:32 ` [PATCH v4 2/7] units: Add HZ_PER_GHZ definition Rodrigo Alencar via B4 Relay
2026-01-16 15:26 ` Andy Shevchenko
2026-01-16 19:01 ` Jonathan Cameron
2026-01-16 14:32 ` [PATCH v4 3/7] iio: frequency: adf41513: driver implementation Rodrigo Alencar via B4 Relay
2026-01-16 19:29 ` Jonathan Cameron [this message]
2026-01-19 13:10 ` Rodrigo Alencar
2026-01-19 7:31 ` Andy Shevchenko
2026-01-19 11:21 ` Rodrigo Alencar
2026-01-19 13:42 ` Andy Shevchenko
2026-01-19 16:37 ` Rodrigo Alencar
2026-01-19 17:07 ` Andy Shevchenko
2026-01-20 10:43 ` Rodrigo Alencar
2026-01-20 11:24 ` Andy Shevchenko
2026-01-20 13:07 ` Rodrigo Alencar
2026-01-20 13:38 ` Andy Shevchenko
2026-01-21 9:41 ` Rodrigo Alencar
2026-01-21 9:52 ` Andy Shevchenko
2026-01-21 14:21 ` Nuno Sá
2026-01-22 19:33 ` Jonathan Cameron
2026-01-16 14:32 ` [PATCH v4 4/7] iio: frequency: adf41513: handle LE synchronization feature Rodrigo Alencar via B4 Relay
2026-01-16 14:32 ` [PATCH v4 5/7] iio: frequency: adf41513: features on frequency change Rodrigo Alencar via B4 Relay
2026-01-16 15:36 ` Andy Shevchenko
2026-01-16 14:32 ` [PATCH v4 6/7] docs: iio: add documentation for adf41513 driver Rodrigo Alencar via B4 Relay
2026-01-16 14:32 ` [PATCH v4 7/7] Documentation: ABI: testing: add common ABI file for iio/frequency Rodrigo Alencar via B4 Relay
2026-01-16 15:28 ` Andy Shevchenko
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260116192916.436d24c9@jic23-huawei \
--to=jic23@kernel.org \
--cc=Michael.Hennerich@analog.com \
--cc=andy@kernel.org \
--cc=conor+dt@kernel.org \
--cc=corbet@lwn.net \
--cc=devicetree@vger.kernel.org \
--cc=devnull+rodrigo.alencar.analog.com@kernel.org \
--cc=dlechner@baylibre.com \
--cc=krzk+dt@kernel.org \
--cc=lars@metafoo.de \
--cc=linux-doc@vger.kernel.org \
--cc=linux-iio@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=robh@kernel.org \
--cc=rodrigo.alencar@analog.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox