What is Linux Clock Consumer Device Tree in Linux Kernel

Linux Clock Consumer Device Tree-Free Linux Device Drivers Course

Free Linux Kernel Development Course — Common Clock Framework, Lecture 5

📘 Chapter 4: Common Clock Framework
⏱ 18 min read
🐧 Kernel 6.x Verified

Free Linux Kernel Development Course Keywords

linux clock consumer device tree
free linux device drivers course
free embedded systems course
free linux development course
clocks clock-names property

If you have been following this free Linux kernel development course, you already know how a clock provider registers itself with the Common Clock Framework (CCF). But a provider is useless on its own — somewhere, a consumer device has to ask for that clock by name. In this lecture on the linux clock consumer device tree binding, we look at exactly how a consumer node describes which clock line it needs, using the clocks and clock-names properties, and how the provider’s #clock-cells and clock-output-names properties shape that description.

What You Will Learn

#clock-cells from the consumer’s point of view
clock-output-names property
clocks and clock-names bindings
Single-cell vs multi-cell clock specifiers
devm_clk_get() driver-side lookup
Original ep_clk_consumer_demo driver

Prerequisites

Before this lecture, you should be comfortable with the earlier parts of this free Linux device drivers course:

clk_hw, clk_ops, clk_init_data basics
clk_hw_register() provider registration
of_clk_add_hw_provider() DT exposure
Basic device tree node syntax

Why the Consumer Side of the Binding Matters

A clock provider node only declares that clock lines exist. It is the consumer node that decides which of those lines it actually uses, and it does this entirely inside the device tree — no driver code has to hardcode a clock name. This keeps drivers portable across boards: the same UART driver can run on two different SoCs even if one board wires the UART to a fixed 24 MHz crystal and another wires it to a PLL output, because the binding lives in the DT, not in the driver.

Provider → Consumer Relationship
Provider Node
#clock-cells
clock-output-names
Consumer Node
clocks
clock-names
Driver
devm_clk_get()

The #clock-cells Property, Seen from the Consumer

We introduced #clock-cells back in Lecture 4 when we exposed a provider with of_clk_add_hw_provider(). From the consumer’s perspective, this single number decides how many extra values must follow the provider’s phandle inside the clocks property:

#clock-cells value Meaning for the consumer Specifier example
0 Provider has a single output; only the phandle is needed clocks = <&clk54>;
1 Provider has multiple outputs; one index cell selects which output clocks = <&osc 0>, <&osc 1>;
>1 Rare; provider needs multiple argument cells to identify an output Driver-defined, e.g. bank + index

Notice that the consumer never has to know why the number is what it is — it just follows the provider’s declared cell count. This is exactly the same phandle-with-arguments pattern used by #gpio-cells, #interrupt-cells, and #dma-cells elsewhere in the kernel.

clock-output-names: Naming Lines for Humans, Not Drivers

The optional clock-output-names property on the provider node lists human-readable names for each output line, purely for documentation, debugfs, and clock-tree tooling. A provider exposing two outputs might look like this:

osc: oscillator@0 {
    compatible = "ep,dual-osc";
    #clock-cells = <1>;
    clock-output-names = "ckout1", "ckout2";
};

Important: a consumer node must never reference "ckout1" or "ckout2" directly. These strings show up in /sys/kernel/debug/clk/clk_summary for human readability, but the actual wiring is always done through the numeric index in the clocks specifier — &osc 0 for ckout1, &osc 1 for ckout2.

Writing the Consumer Node: clocks and clock-names

On the consumer side, two properties work as a pair:

clocks — list of phandle + specifier-cell entries, one per clock the device needs
clock-names — matching list of strings the driver uses to request each clock by name
ep_uart0: serial@fe001000 {
    compatible = "ep,uart-lite";
    reg = <0xfe001000 0x100>;
    clocks = <&osc 0>, <&osc 1>;
    clock-names = "baud", "register";
};

The order inside clocks and clock-names must match position-for-position. The driver will later call something like devm_clk_get(dev, "baud") and the kernel resolves that string against this array to find the correct entry.

How the Driver Requests a Named Clock

Once the DT binding is in place, driver code never touches phandles directly. It calls one of the managed clock-lookup helpers:

struct clk *baud_clk = devm_clk_get(&pdev->dev, "baud");
if (IS_ERR(baud_clk))
    return PTR_ERR(baud_clk);

clk_prepare_enable(baud_clk);

devm_clk_get() is the modern, devres-managed entry point. Internally it still walks through of_clk_get_by_name() and eventually reaches the phandle-parsing machinery — we cover that internal walk in full detail in the next lecture, since it deserves a dedicated explanation of of_parse_phandle_with_args().

Original Demo: ep_clk_consumer_demo

Let’s build a small, original platform driver that consumes a fixed clock exposed by a provider, purely to see the consumer binding working end to end.

Device Tree Overlay

/* Provider: 48 MHz fixed clock */
ep_fixedclk: ep-fixed-clock {
    compatible = "fixed-clock";
    #clock-cells = <0>;
    clock-frequency = <48000000>;
    clock-output-names = "ep_osc48";
};

/* Consumer: our demo platform device */
ep_clkconsumer: ep-clk-consumer {
    compatible = "ep,clk-consumer-demo";
    clocks = <&ep_fixedclk>;
    clock-names = "core";
};

Driver Code

#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/of.h>

struct ep_clk_consumer_data {
    struct clk *core_clk;
};

static int ep_clk_consumer_probe(struct platform_device *pdev)
{
    struct ep_clk_consumer_data *data;
    unsigned long rate;
    int ret;

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

    data->core_clk = devm_clk_get(&pdev->dev, "core");
    if (IS_ERR(data->core_clk)) {
        dev_err(&pdev->dev, "failed to get core clock\n");
        return PTR_ERR(data->core_clk);
    }

    ret = clk_prepare_enable(data->core_clk);
    if (ret) {
        dev_err(&pdev->dev, "failed to enable core clock\n");
        return ret;
    }

    rate = clk_get_rate(data->core_clk);
    dev_info(&pdev->dev, "ep_clk_consumer_demo: core clock running at %lu Hz\n", rate);

    platform_set_drvdata(pdev, data);
    return 0;
}

static void ep_clk_consumer_remove(struct platform_device *pdev)
{
    struct ep_clk_consumer_data *data = platform_get_drvdata(pdev);

    clk_disable_unprepare(data->core_clk);
}

static const struct of_device_id ep_clk_consumer_of_match[] = {
    { .compatible = "ep,clk-consumer-demo" },
    {}
};
MODULE_DEVICE_TABLE(of, ep_clk_consumer_of_match);

static struct platform_driver ep_clk_consumer_driver = {
    .probe  = ep_clk_consumer_probe,
    .remove = ep_clk_consumer_remove,
    .driver = {
        .name = "ep_clk_consumer_demo",
        .of_match_table = ep_clk_consumer_of_match,
    },
};
module_platform_driver(ep_clk_consumer_driver);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("EmbeddedPathashala clock consumer demo driver");

Build and Run

make -C /lib/modules/$(uname -r)/build M=$PWD modules
sudo insmod ep_clk_consumer_demo.ko
dmesg | tail -5

Expected dmesg Output

[ 102.334112] ep_clk_consumer_demo: core clock running at 48000000 Hz

You can also confirm the same rate independently via debugfs:

cat /sys/kernel/debug/clk/ep_osc48/clk_rate
48000000

Common Mistakes

  • Mismatching the order of entries between clocks and clock-names — the driver will silently look up the wrong clock.
  • Referencing clock-output-names strings instead of the numeric index inside a clocks specifier.
  • Forgetting clk_prepare_enable() and only calling clk_enable() — on some clock providers prepare does the operations that may sleep, and skipping it can cause silent failures.
  • Not handling -EPROBE_DEFER from devm_clk_get() when the provider driver has not registered yet.

Best Practices

  • Always use clock-names even when a device has only one clock — it keeps the binding self-documenting and future-proof.
  • Prefer the devm_* managed clock APIs so cleanup happens automatically on driver removal or probe failure.
  • Keep clock-output-names consistent with the datasheet naming so debugfs output is easy to cross-reference.

Summary and Key Takeaways

  • The consumer node uses clocks and clock-names to describe which provider outputs it needs, in the format dictated by the provider’s #clock-cells.
  • clock-output-names is documentation-only and must never be referenced from a consumer’s clocks property.
  • Driver code stays hardware-agnostic by calling devm_clk_get(dev, "name") instead of hardcoding any DT detail.
  • The internal lookup path — of_clk_get_by_name()__of_clk_get()of_parse_phandle_with_args() — is covered in full in the next lecture.

Conclusion

Understanding the linux clock consumer device tree binding closes the loop between a provider’s declared outputs and the driver code that actually uses them. With clocks, clock-names, and #clock-cells in place, your driver can request any clock by a stable name regardless of which SoC or board it runs on. In the next lecture in this free Linux kernel development course, we go one level deeper and study the generic of_parse_phandle_with_args() API that makes this lookup possible — not just for clocks, but for GPIOs, DMA channels, and any other phandle-based binding in the kernel.

Frequently Asked Questions

What happens if clock-names is missing from a consumer node?

The driver can still request clocks by index using clk_get(dev, NULL) style lookups relying on position, but this is discouraged. Named lookup via clock-names is far more robust against DT changes.

Can one consumer node use clocks from more than one provider?

Yes. Each entry in the clocks property can reference a different provider phandle, as long as each entry supplies the correct number of specifier cells for that provider’s #clock-cells.

Is clock-output-names mandatory?

No, it is optional but recommended. It only affects human-readable names shown in debugfs and tooling, never the actual binding logic.

What is the difference between clk_get() and devm_clk_get()?

devm_clk_get() ties the clock reference to the device’s lifecycle, so it is released automatically on driver removal or probe failure, avoiding manual cleanup bugs.

Why did my devm_clk_get() call return -EPROBE_DEFER?

This means the clock provider driver referenced by the phandle has not registered its clock yet. The kernel will retry your probe automatically once the provider is available.

Can #clock-cells be greater than 1?

It is technically supported by the phandle-with-args machinery, but almost no real clock provider needs more than one specifier cell in practice.

Do I need CONFIG_COMMON_CLK enabled to use these bindings?

Yes, as covered in Lecture 1 of this chapter, the Common Clock Framework and its device tree bindings require CONFIG_COMMON_CLK to be enabled in your kernel configuration.

Continue This Free Linux Kernel Development Course

Next up: the internal phandle-parsing API that powers every clock, GPIO, and DMA lookup in the kernel.

 

Leave a Reply

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