What is Linux Clock Rate Parent API in Linux Kernel-Free Linux Device Drivers Course

Linux Clock Rate Parent API-Free Linux Device Drivers Course

clk_get_rate, clk_set_rate, clk_round_rate, and switching parents from a consumer driver

The previous lecture covered the first half of the consumer-facing API — grabbing a clock and taking it through the prepare/enable lifecycle. That is enough for a driver that only needs its clock running, without caring about the exact frequency. Many real peripherals care a great deal about the exact frequency: a UART needs to know its input clock rate to compute baud-rate dividers, an I2S controller needs a specific master clock rate for audio sample rates to come out correct, and some peripherals need to switch between two entirely different upstream sources depending on operating mode. This lecture completes the linux clock rate parent api — the functions that read, request, and validate clock rates, and the functions that switch which upstream clock a given line is sourced from — then ties the whole consumer API together with one complete, real-world driver example.

What You Will Learn

clk_get_rate() and CLK_GET_RATE_NOCACHE
clk_round_rate() before clk_set_rate()
why clk_set_rate() can fail
clk_set_parent() / clk_get_parent()
a complete consumer driver walkthrough

Prerequisites

This lecture continues directly from the previous one on grabbing clocks and the prepare/enable lifecycle — make sure that lecture’s clk_get()/devm_clk_get() and clk_prepare_enable() material is comfortable before continuing, since the example driver here builds on exactly that foundation.

Reading the Current Rate

unsigned long clk_get_rate(struct clk *clk);

clk_get_rate() returns 0 if clk is NULL, and otherwise returns the clock’s cached rate — the value the framework already computed and stored, rather than re-reading hardware on every call. If the CLK_GET_RATE_NOCACHE flag was set on that clock by its provider, clk_get_rate() instead triggers a fresh recalc_rate() call to return the true, freshly-measured rate. As a consumer you rarely need to worry about which mode a given clock uses internally; you simply call clk_get_rate() and trust the value it returns.

Requesting a Different Rate

int clk_set_rate(struct clk *clk, unsigned long rate);
long clk_round_rate(struct clk *clk, unsigned long rate);

clk_set_rate() is not guaranteed to give you exactly the rate you ask for — clock hardware is built around fixed dividers and PLL multiplication ratios, so most target frequencies land between two achievable values. clk_round_rate() lets you find out, ahead of time, what rate the clock would actually settle on for a given target, without changing anything:

long rounded_rate = clk_round_rate(clk, target_rate);
if (rounded_rate < 0)
    return rounded_rate;

ret = clk_set_rate(clk, rounded_rate);
if (ret)
    return ret;

Passing clk_round_rate()’s return value straight into clk_set_rate() is the standard pattern — it guarantees the rate you request is one the underlying hardware can actually produce. If a clock’s ops does not implement .round_rate() (or the newer .determine_rate()), the framework falls back to simply returning the parent’s rate, since a clock with no rate-adjustment capability can only ever run at whatever its parent supplies.

Why clk_set_rate() Can Fail

clk_set_rate() Failure Conditions

clk_set_rate(clk, target)
|
+–> is this a fixed-rate source (osc/xref)? –> FAIL, rate is immutable
|
+–> usecount > 1 (multiple active consumers)? –> FAIL, shared clock
|
+–> clock in use by more than one child clock? –> FAIL, shared upstream source
|
+–> none of the above –> proceeds, may adjust rate

Concretely: you cannot change the rate of a clock whose source is a fixed-rate crystal or reference clock, since fixed-rate clocks have no set_rate op at all. You also cannot freely change the rate of a clock that other consumers, or other child clocks in the tree, currently depend on — the framework will reject a rate change that would silently break a sibling’s required frequency unless the CLK_SET_RATE_PARENT propagation flags were explicitly set up for that relationship at registration time.

Switching Parents

int clk_set_parent(struct clk *clk, struct clk *parent);
struct clk *clk_get_parent(struct clk *clk);

clk_set_parent() actually reparents the given clock — this is the consumer-side call that drives the mux clock tree example from the previous lecture: passing in the struct clk for ep_pll3_clk instead of ep_pll2_clk switches ep_out3_clk’s upstream source, and the change is immediately visible in clk_summary. clk_get_parent() simply returns whichever clk the framework currently considers the active parent, useful for logging or for deciding whether a reparent call is even necessary before making it.

Putting It All Together: A Complete Consumer Driver

The following original example ties clk_get(), the prepare/enable lifecycle from the previous lecture, and the rate functions from this one into a single realistic probe function — modeled on the pattern used throughout the kernel’s own serial and audio drivers, but written fresh for this course:

struct ep_uart_port {
    struct clk *clk_per;
    unsigned int uartclk;
};

static int ep_uart_probe(struct platform_device *pdev)
{
    struct ep_uart_port *sport;
    int ret;

    sport = devm_kzalloc(&pdev->dev, sizeof(*sport), GFP_KERNEL);
    if (!sport)
        return -ENOMEM;

    sport->clk_per = devm_clk_get(&pdev->dev, "per");
    if (IS_ERR(sport->clk_per))
        return dev_err_probe(&pdev->dev, PTR_ERR(sport->clk_per),
                              "failed to get per clk\n");

    ret = clk_prepare_enable(sport->clk_per);
    if (ret)
        return ret;

    /* Confirm we can actually hit our target baud-rate clock */
    long rounded = clk_round_rate(sport->clk_per, 48000000);
    if (rounded > 0 && (unsigned long)rounded != clk_get_rate(sport->clk_per)) {
        ret = clk_set_rate(sport->clk_per, rounded);
        if (ret) {
            dev_warn(&pdev->dev,
                      "could not set per clk to %ld, using %lu\n",
                      rounded, clk_get_rate(sport->clk_per));
        }
    }

    sport->uartclk = clk_get_rate(sport->clk_per);
    dev_info(&pdev->dev, "ep_uart running at uartclk=%u Hz\n", sport->uartclk);

    platform_set_drvdata(pdev, sport);
    return 0;
}

static void ep_uart_remove(struct platform_device *pdev)
{
    struct ep_uart_port *sport = platform_get_drvdata(pdev);

    clk_disable_unprepare(sport->clk_per);
}

Build and Test Walkthrough

$ make -C /lib/modules/$(uname -r)/build M=$PWD modules
$ sudo insmod ep_uart.ko
$ dmesg | tail
[   45.112004] ep_uart ep-uart@02020000: ep_uart running at uartclk=48000000 Hz

$ cat /sys/kernel/debug/clk/ep_pll2_clk/clk_rate
48000000

Comparison: Rate Functions at a Glance

Function Purpose Can it fail / sleep?
clk_get_rate() Read the cached (or freshly recalculated) rate Never fails; returns 0 for a NULL clk
clk_round_rate() Preview what rate a target would actually settle on Returns a negative value on error
clk_set_rate() Actually change the clock’s rate May fail (fixed source, shared usecount)
clk_set_parent() Switch which upstream clock feeds this one May fail if the clock is currently enabled and reparenting live is unsupported by the provider

Common Mistakes

  • Calling clk_set_rate() directly with an arbitrary target frequency instead of first passing it through clk_round_rate() — the call may silently produce a rate different from what you asked for, or fail outright.
  • Assuming clk_set_rate() will always succeed on any clock — fixed-rate sources and shared clocks with multiple active consumers are legitimate, expected failure cases, not bugs.
  • Forgetting to re-read clk_get_rate() after a successful clk_set_rate() call and instead caching the originally-requested value, which may differ from what the hardware actually settled on.
  • Calling clk_set_parent() on a clock that is currently enabled when the underlying provider does not support glitch-free live reparenting — always check provider documentation or disable the clock first if uncertain.

Best Practices

  • Always route a target rate through clk_round_rate() before calling clk_set_rate(), and use the rounded value returned.
  • After any successful clk_set_rate(), re-read clk_get_rate() and use that value for downstream calculations (baud-rate dividers, sample-rate configuration) rather than the originally requested target.
  • Treat clk_set_rate() and clk_set_parent() failures as expected, recoverable conditions in a shared-clock system — log them and fall back to the current rate/parent rather than treating them as fatal probe errors.

Summary and Key Takeaways

This completes our tour of the linux clock consumer api: clk_get_rate(), clk_round_rate(), and clk_set_rate() give a consumer driver full, safe control over frequency, while clk_set_parent() and clk_get_parent() let it switch upstream sources entirely — the same mechanism the mux clock tree from an earlier lecture was built to support. Combined with the clk_get()/prepare/enable lifecycle from the previous lecture, a driver now has everything it needs to correctly acquire, configure, and release any clock exposed by a provider, regardless of whether that provider is a simple fixed-rate oscillator or a multi-stage composite clock deep in an SoC’s clock tree. This closes out the Common Clock Framework chapter of this free linux kernel development course — from the five core CCF structs all the way through provider drivers, device tree modeling, and now the full consumer API.

FAQ

Why should I call clk_round_rate() before clk_set_rate()?

Because clock hardware can rarely produce an arbitrary target frequency exactly; clk_round_rate() tells you the actual achievable rate ahead of time so clk_set_rate() does not silently deviate from what you expect.

Can clk_set_rate() fail even with a valid target rate?

Yes — common causes include the clock deriving from a fixed-rate source, or the clock being shared by multiple active consumers or child clocks whose required rates would be disrupted.

What happens if a clock’s ops does not implement round_rate or determine_rate?

The framework falls back to returning the parent clock’s rate, since a clock with no rate-adjustment capability can only run at whatever rate its parent supplies.

Is clk_get_rate() guaranteed to reflect the true hardware rate?

Normally it returns a cached value; it only triggers a fresh recalc_rate() measurement if the provider set the CLK_GET_RATE_NOCACHE flag.

Can I switch a clock’s parent while it is enabled?

It depends on the provider — some hardware supports glitch-free live reparenting and some does not; check the provider’s documentation or disable the clock first if you are unsure.

Does clk_set_parent() work on any clock, or only muxes?

Only clocks whose ops implement .set_parent() (typically mux-type clocks) support reparenting; calling it on a clock without that capability returns an error.

What is the recommended header for consumer-side rate and parent functions?

The same <linux/clk.h> used for clk_get(), clk_prepare(), and clk_enable() — the entire consumer API lives in one header.

Keep Building Real Kernel Skills

This lecture is part of EmbeddedPathashala’s free linux device drivers course covering the Common Clock Framework end to end.

 

Leave a Reply

Your email address will not be published. Required fields are marked *