Linux Clock Consumer Device Tree-Free Linux Device Drivers Course
Free Linux Kernel Development Course — Common Clock Framework, Lecture 5
Free Linux Kernel Development Course Keywords
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-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_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.
#clock-cells
clock-output-names
clocks
clock-names
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:
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
clocksandclock-names— the driver will silently look up the wrong clock. - Referencing
clock-output-namesstrings instead of the numeric index inside aclocksspecifier. - Forgetting
clk_prepare_enable()and only callingclk_enable()— on some clock providerspreparedoes the operations that may sleep, and skipping it can cause silent failures. - Not handling
-EPROBE_DEFERfromdevm_clk_get()when the provider driver has not registered yet.
Best Practices
- Always use
clock-nameseven 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-namesconsistent with the datasheet naming so debugfs output is easy to cross-reference.
Summary and Key Takeaways
- The consumer node uses
clocksandclock-namesto describe which provider outputs it needs, in the format dictated by the provider’s#clock-cells. clock-output-namesis documentation-only and must never be referenced from a consumer’sclocksproperty.- 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.
