Skip to content

hmc7044: add dynamic PLL2 rate selection via CCF#3283

Open
vai-tomme wants to merge 11 commits into
analogdevicesinc:mainfrom
vai-tomme:upstream/hmc7044
Open

hmc7044: add dynamic PLL2 rate selection via CCF#3283
vai-tomme wants to merge 11 commits into
analogdevicesinc:mainfrom
vai-tomme:upstream/hmc7044

Conversation

@vai-tomme

@vai-tomme vai-tomme commented Apr 27, 2026

Copy link
Copy Markdown
Contributor

PR Description

This series extends the HMC7044 driver to expose PLL2 as a CCF clock and support dynamic PLL2 rate selection. When a requested output frequency cannot be satisfied by an integer divider alone, the driver searches for a PLL2 rate that best approximates the target. Per-channel deviation budgets can be specified to protect other outputs from excessive frequency error when PLL2 is retuned.

Tested on zcu102 with modifications on top of main branch. Noting that curiously jesd204 link does not come up successfully with main branch, but situation is same with or without these changes applied.

Signed-off-by: Tomas Melin tomas.melin@vaisala.com

PR Type

  • Bug fix (a change that fixes an issue)
  • New feature (a change that adds new functionality)
  • Breaking change (a change that affects other repos or cause CIs to fail)

PR Checklist

  • I have conducted a self-review of my own code changes
  • I have compiled my changes, including the documentation
  • I have tested the changes on the relevant hardware
  • I have updated the documentation outside this repo accordingly
  • I have provided links for the relevant upstream lore

@vai-tomme

vai-tomme commented May 4, 2026

Copy link
Copy Markdown
Contributor Author
  • split dt binding commit to separate patch

@vai-tomme vai-tomme force-pushed the upstream/hmc7044 branch from c153c5b to 30964aa Compare May 4, 2026 14:26

@nunojsa nunojsa left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks again for contributing. Some remarks from me

Comment thread drivers/iio/frequency/hmc7044.c
Comment thread drivers/iio/frequency/hmc7044.c Outdated
unsigned long r2_max;

vcxo_freq = vcxo_freq / 1000;
pll2_freq = pll2_freq / 1000;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will we gain something from DIV_ROUND_CLOSEST()?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thin that wouldn't gain anything here. The frequencies are exact kHz multiples so it would give the same result.

Comment thread drivers/iio/frequency/hmc7044.c Outdated
Comment thread drivers/iio/frequency/hmc7044.c

/* don't propagate rate change to parent*/
if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT))
return oldrate;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm I get the don't propagate the parent rate thing but why do we return oldrate? is it because if we can't change the parent than we can assume no new rate will work? Maybe I'm missing something

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's because shortly before, based on the requested rate, we have calculcated what the rate will be with the current PLL2 frequency. As we are not changing that, oldrate is what we can achieve.

struct hmc7044_chan_spec {
unsigned int num;
bool disable;
bool mute;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm don't really like this kind of "write 0" to disable. If that isn't an allowed value we should just error out instead of doing this kind of stuff, Both CCF and IIO have explicit things to disable channels or clocks

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see them as separate actions. Until now, also 0 has been supported through sysfs, but if used it would fail on reading back the value. And there is no enable/disable knob for each channel so setting to 0 is effectively what it does.

Comment thread drivers/iio/frequency/hmc7044.c Outdated
Comment thread drivers/iio/frequency/hmc7044.c Outdated
div = hmc7044_calc_out_div(pll2_candidate, current_rate);
candidate_rate = DIV_ROUND_CLOSEST(pll2_candidate, div);
deviation_ppm = abs(current_rate - candidate_rate) *
1000000 / current_rate;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would also put it in the same line unless we pass the 101 col limit

@analogdevicesinc analogdevicesinc deleted a comment from github-actions Bot May 7, 2026
@nunojsa nunojsa added llm review Request a review from a LLM Reviewer and removed llm review Request a review from a LLM Reviewer labels May 7, 2026
@github-actions

github-actions Bot commented May 7, 2026

Copy link
Copy Markdown
Contributor

LLM review

This series adds PLL2 clock framework integration to the HMC7044 jitter attenuator driver, enabling dynamic PLL2 rate changes, channel muting via zero-rate, and per-channel deviation guards (adi,max-deviation-ppm / adi,set-rate-parent).

run: 25484988610

84a63553 - register pll2 clock

Clock name collision: hmc7044_pll2_register() registers the PLL2 clock with the hardcoded name "hmc7044_pll2":

// drivers/iio/frequency/hmc7044.c:1101
init.name = "hmc7044_pll2";

The Linux clock framework requires globally unique clock names. When two HMC7044 instances are present (common in multi-chip systems), devm_clk_register() on the second device returns -EEXIST and the driver fails to probe. All 14 output clocks correctly use per-device names from the clock-output-names DT property; the same approach is needed here. Compare with adf4382.c and adf4350.c which use devm_kasprintf(&dev, GFP_KERNEL, "%s-clk", dev_name(dev)).

CI warnings

No checkpatch warnings were found. Clean build confirmed with gcc_arm cross-compiler (W=1 extra warnings enabled).

Verification data

The HMC7044 datasheet was fetched from the doctools docling mirror (hmc7044.md) and used to verify: VCO frequency range (2400–3200 MHz guaranteed coverage), N2 feedback divider range (8–65535), R2 reference divider range (1–4095) — all consistent with the driver's HMC7044_RECOMM_VCO_MIN/MAX, HMC7044_N2_MIN/MAX, and HMC7044_R2_MAX constants.

Suggested patches

Apply the suggested patches with:

cd path/to/repository
export GITHUB_TOKEN=ghp_***
apply-patches --repo=analogdevicesinc/linux 25484988610
Install instructions

The following one-liner installs the script if not present already:

grep "/apply-patches.sh" ~/.bashrc ||  { curl "https://raw.githubusercontent.com/analogdevicesinc/doctools/refs/heads/main/ci/scripts/apply-patches.sh"    -o ~/.local/bin/apply-patches.sh &&  echo "source ~/.local/bin/apply-patches.sh" >> ~/.bashrc ; source ~/.bashrc ; }

More information at AI Usage.

@nunojsa

nunojsa commented May 7, 2026

Copy link
Copy Markdown
Collaborator

AI complain seems valid

@vai-tomme

vai-tomme commented May 12, 2026

Copy link
Copy Markdown
Contributor Author

AI complain seems valid

  • It does, I will check it out

@vai-tomme

Copy link
Copy Markdown
Contributor Author

AI complain seems valid

* [x]   It does, I will check it out

Updated in latest push.

@vai-tomme

vai-tomme commented May 18, 2026

Copy link
Copy Markdown
Contributor Author
  • check if needs rebase

Register pll2 as parent in the case device is hmc7044. This will
enable control and propagation of clock changes to sibling channels
and parent clock within the device. Support clock framework
operations for the added pll2 clock.

Signed-off-by: Tomas Melin <tomas.melin@vaisala.com>
vai-tomme added 2 commits May 19, 2026 05:24
Make the pll2 setting calculations a separate function. Calculating
appropriate settings and achievable frequencies as a separate request
is needed when controlling the clock via the clock framework.

Signed-off-by: Tomas Melin <tomas.melin@vaisala.com>
Add new set-rate-parent property.

Signed-off-by: Tomas Melin <tomas.melin@vaisala.com>
vai-tomme added 8 commits May 19, 2026 05:24
Add a new property to make channel rate setting possible
to propagate to parent. The escalation happens when a frequency
that is not directly achievable is requested. Since not all
requested frequencies are necessarily achievable by all channels
at once, this feature allows to describe which channels should
be prioritized. Channels that lack this property will work as before.
That is, only operate within the range of divider settings available,
and with constant parent frequency rate.

Signed-off-by: Tomas Melin <tomas.melin@vaisala.com>
Implementation for both determine_rate and round_rate operations
are typically not required. In this case supporting both is not
needed and also would require extending current implementations to
both support parent rate setting. To avoid any conflicts with
this, drop determine rate in favor of the round rate implementation.

Signed-off-by: Tomas Melin <tomas.melin@vaisala.com>
Split functionality to register clocks separately in preparation
to support pll2 clock operations dynamically.

Signed-off-by: Tomas Melin <tomas.melin@vaisala.com>
Round rate operation will be called to determine whether a requested
frequency can be fulfilled. Here we add support to also calculate
a suitable new parent rate for the case where parent rate propagation
has been set for the specific clock being changed.

Signed-off-by: Tomas Melin <tomas.melin@vaisala.com>
Relay writes to common clock framework when channel frequency settings
are altered via sysfs interface. This allows to escalate frequency changes
to parent clocks and do other sanity checks to the frequency being
requested, in a common fashion.

Signed-off-by: Tomas Melin <tomas.melin@vaisala.com>
When requesting zero as output frequency for a specific channel,
set the channel register to disabled. Also add the support codes for
avoiding division by zero. Setting a frequency different than zero
re-enables the channels with other settings restored.

Signed-off-by: Tomas Melin <tomas.melin@vaisala.com>
Add the adi,max-deviation-ppm property. When set on a channel, any
PLL2 rate change requested by a CLK_SET_RATE_PARENT channel is
rejected if it would shift this channel's output frequency by more
than the specified number of parts per million from its current rate.

Signed-off-by: Tomas Melin <tomas.melin@vaisala.com>
Account for maximum allowed deviations when setting frequency.

Logic works accordingly:
If set-rate-parent is enabled for a specific channel, a new
parent pll2 rate will be looked for when the frequency does not match
an allowed divider.
If the parent clock rate changes, this implies that the accuracy of
other channels might change. Therefore, check all other channel's allowed
deviations.
If a potential parent rate that fulfills the requested rate for the
channel does not meet deviation requirements of the other channels,
skip it and go to next candidate. This check applies to all channels that
are not currently disabled.
If any of the channel deviation requirements fail, the requested frequency
will be rejected.

Signed-off-by: Tomas Melin <tomas.melin@vaisala.com>
@vai-tomme

Copy link
Copy Markdown
Contributor Author
  • check if needs rebase

Rebased on current main branch

@nunojsa nunojsa left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice series. Not much to say. I'll trigger another AI review on this one.

Comment thread drivers/iio/frequency/hmc7044.c
ret = hmc7044_pll2_recalc_rate(&pll2, hmc->vcxo_freq, hmc->pll2_freq,
hmc->sync_through_pll2_force_r2_eq_1);
if (ret == 0)
return -EINVAL;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel that this patch could have been squashed in the patch adding the pll2 clock. Adding the helper in same patchset as adding the feature looks weird to me

struct clk *clk;
unsigned long flags;

flags = CLK_GET_RATE_NOCACHE;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The above also adds changes in behavior. Any special reason for it? If so, It could be stated in the commit message.

struct hmc7044_chan_spec {
unsigned int num;
bool disable;
bool mute;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still don't agree with this write 0 to frequency to disable tbh. We do have interfaces to disable a channel. As for the frequency value 0, we can just reject it.

@nunojsa nunojsa added llm review Request a review from a LLM Reviewer and removed llm review Request a review from a LLM Reviewer labels Jun 8, 2026
@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

LLM review

This series adds PLL2 clock registration in the CCF, CLK_SET_RATE_PARENT propagation for HMC7044 output channels, zero-frequency mute support, and per-channel adi,max-deviation-ppm tolerance checking.

run: 27166678064

8e22b0f08ac2 - iio: frequency: hmc7044: use clk framework for rate changes

Wrong divider when CLK_SET_RATE_PARENT is active:

hmc7044_clk_set_rate computes the channel output divider using hmc->pll2_freq (line 1050), but at the time the channel's set_rate callback is called, hmc->pll2_freq holds the requested PLL2 rate set by the parent's set_rate callback — not the hardware-achievable rate. The CLK framework passes the actual achievable parent rate in the parent_rate argument, which is what was returned by hmc7044_clk_round_rate in *parent_rate. Using the wrong rate produces an incorrect divider value when the rational approximation causes the PLL2 to settle at a frequency different from what was requested.

// drivers/iio/frequency/hmc7044.c:1050
- ch->divider = hmc7044_calc_out_div(hmc->pll2_freq, rate);
+ ch->divider = hmc7044_calc_out_div(parent_rate, rate);

6285c51a2a90 - iio: frequency: hmc7044: support channel frequency deviation setting

32-bit integer overflow in deviation_ppm computation:

deviation_ppm = abs(current_rate - candidate_rate) * 1000000 / current_rate (lines 904 and 985) overflows on 32-bit ARM whenever the frequency difference exceeds ~4 295 Hz, because * 1000000 is computed in unsigned long (32 bits on ARM) before the division. This silently produces a wrong ppm value, meaning the adi,max-deviation-ppm guard may accept PLL2 changes it should have rejected.

// hmc7044_verify_deviation (line 896, 904)
- unsigned int deviation_ppm;
+ u64 deviation_ppm;
  ...
- deviation_ppm = abs(current_rate - candidate_rate) * 1000000 / current_rate;
+ deviation_ppm = (u64)abs_diff(current_rate, candidate_rate) * 1000000;
+ do_div(deviation_ppm, current_rate);
  dev_dbg(...,
-     "... deviation %u ppm\n", ...);
+     "... deviation %llu ppm\n", ...);

// hmc7044_clk_round_rate (line 925, 952, 958, 985)
- unsigned long min_dev;
+ u64 min_dev;
- min_dev = hmc->channels[out->address].max_deviation_ppm;
+ min_dev = (u64)hmc->channels[out->address].max_deviation_ppm;
- unsigned long deviation_ppm;
+ u64 deviation_ppm;
- deviation_ppm = abs(rate - newrate) * 1000000 / rate;
+ deviation_ppm = (u64)abs_diff(rate, newrate) * 1000000;
+ do_div(deviation_ppm, rate);

Verification data

  • The datasheet hmc7044.md was fetched from https://raw.githubusercontent.com/analogdevicesinc/doctools/refs/heads/docling/media/en/technical-documentation/data-sheets/hmc7044.md and used to verify register addresses (0x00C8+0xA*ch for channel control, 0x00C9/0xCA for divider LSB/MSB) against the driver macros — all match.
  • Compiled for gcc_arm (32-bit) using the CI build.sh helpers; both the original code and the fixup patches build without errors or warnings.
  • checkpatch.pl reports zero errors and zero warnings for all 11 series commits.

Suggested patches

Apply the suggested patches with:

cd path/to/repository
export GITHUB_TOKEN=ghp_***
apply-patches --repo=analogdevicesinc/linux 27166678064
Install instructions

The following one-liner installs the script if not present already:

curl -fSsL "https://raw.githubusercontent.com/analogdevicesinc/doctools/refs/heads/main/ci/scripts/apply-patches.sh" \
     -o ~/.local/bin/apply-patches.sh && \
  grep -q "/apply-patches.sh" ~/.bashrc || echo "source ~/.local/bin/apply-patches.sh" >> $_ ; . $_

More information at AI Usage.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

llm review Request a review from a LLM Reviewer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants