Keywords covered in this lecture
CLK_IGNORE_UNUSED
CLK_IS_CRITICAL
clk_hw init flags
free linux kernel development course
free linux device drivers course
Two clocks can implement the exact same clk_ops callbacks and still behave very
differently once registered, because of one field we have not looked at yet:
clk_hw->init.flags. These linux clock flags are
framework-level hints, defined in include/linux/clk-provider.h and
OR’d together, that change how the CCF itself behaves around rate changes,
re-parenting, and unused-clock cleanup — independent of anything your own
callbacks do.
What You Will Learn
- Where clk_hw.init.flags lives and how flags are combined
- What each CLK_* flag actually changes in framework behavior
- Why CLK_SET_RATE_PARENT needs to be used with care
- Which flag keeps a boot-critical clock from ever being gated
- A flag that is now obsolete, and two newer ones added since this book was written
Prerequisites
- Mandatory clk_ops by clock type (previous lecture)
- CCF clk_ops callback reference guide
- Basic bitfield/BIT() macro familiarity
Where Clock Flags Live
Every clock’s struct clk_init_data has a flags field, set
once at registration time and never changed afterward. Unlike clk_ops, which tells the
CCF what your hardware can do, these flags tell the CCF how to behave around
that hardware — whether a rate change must be gated first, whether an unused clock
should be left alone, and so on. Multiple flags are combined with a bitwise OR.
Clock Flags Reference
CLK_SET_RATE_GATE
The clock must be gated (disabled) across any rate change. With this flag set, if the
clock has already been prepared, a clk_set_rate() call will fail outright
— this exists to protect against rate glitches reaching a running consumer.
CLK_SET_PARENT_GATE
The clock must be gated (disabled) across any re-parenting operation, for the same
glitch-protection reason as CLK_SET_RATE_GATE, but applied to parent switches instead of
rate changes.
CLK_SET_RATE_PARENT
This is the most involved flag, and the one you already saw used for parent chaining
in an earlier lecture. It has two separate effects:
- If .round_rate is missing, a clk_round_rate() request is forwarded up to the parent instead of just returning the cached rate
- Any clk_set_rate() request is forwarded upstream, letting a parent rate change stand in for a rate change the clock itself cannot perform
This flag is typically set on gate and mux clocks that have no rate-changing ability
of their own, and the book’s own advice still holds today: use it with care, since it
means a seemingly local rate change can ripple up and affect every other clock sharing
that same parent.
CLK_IGNORE_UNUSED
Tells the CCF to skip this specific clock during its late-boot “disable unused
clocks” pass. This is the per-clock equivalent of the clk_ignore_unused boot
parameter, and is mainly a bring-up and debug aid for clocks a bootloader leaves running
that no driver has claimed yet — it is not meant for normal production use.
CLK_GET_RATE_NOCACHE
Forces the CCF to recompute the clock’s rate every time instead of trusting its
cached value. This matters on hardware where the rate can change outside the kernel’s
knowledge — for example, a piece of firmware or another core adjusting a PLL
behind the kernel’s back.
CLK_SET_RATE_NO_REPARENT
Prevents the CCF from switching a mux clock’s parent as a side effect of trying to
satisfy a requested rate. Without this flag, a rate request that no current parent can
satisfy exactly might cause an automatic re-parent; this flag disables that behavior.
CLK_GET_ACCURACY_NOCACHE
The accuracy equivalent of CLK_GET_RATE_NOCACHE: it forces accuracy to be
recalculated on every query instead of using a cached parts-per-billion value.
CLK_RECALC_NEW_RATES
Tells the CCF to recalculate this clock’s rate whenever it receives a rate-change
notification, rather than assuming the rate is still whatever was last cached.
CLK_SET_RATE_UNGATE
Marks a clock that must actually be running (ungated) in order for a rate change to
be applied at all — some hardware simply cannot latch a new divider or PLL setting
while the clock signal is stopped.
CLK_IS_CRITICAL
Marks a clock that must never be gated, under any circumstances, even if the CCF
believes no consumer currently holds it. This is reserved for clocks whose loss would
crash the system outright, such as a clock feeding the CPU or system bus itself.
A flag that no longer exists, and two that are new
CLK_IS_BASIC, which older references may still list, has been removed and is no
longer used in current kernels — do not rely on it in new drivers. Since this
book’s era, mainline has also added CLK_OPS_PARENT_ENABLE (forces the
parent clock to be enabled during gate/ungate, set_rate, and re-parent operations)
and CLK_DUTY_CYCLE_PARENT (forwards duty-cycle queries to the parent
clock), verified against current kernel source.
Gated Means Disabled, Ungated Means Enabled
It is easy to trip over the terminology here: a gated clock is a
disabled clock, and an ungated clock is an enabled one. Several of the
flags above talk about gating specifically around rate changes and re-parenting, and
reading “gate” as “disable” makes every one of them much easier to reason about.
Original Demo: Applying CLK_IS_CRITICAL and CLK_SET_RATE_PARENT
Here is a short original example showing both flags at work: a bus clock that must
never be gated, and a gate clock beneath it that forwards any rate change request to
that same bus clock.
/* ep_flagged_clk_tree.c - demonstrating CLK_IS_CRITICAL and CLK_SET_RATE_PARENT */
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/spinlock.h>
struct ep_flagged_data {
void __iomem *base;
spinlock_t lock;
struct clk_hw *bus_hw;
struct clk_hw *periph_hw;
};
static int ep_flagged_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct ep_flagged_data *data;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
spin_lock_init(&data->lock);
data->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(data->base))
return PTR_ERR(data->base);
/* the shared bus clock must never be gated, even if unused */
data->bus_hw = devm_clk_hw_register_fixed_rate(dev, "ep_bus_clk", NULL,
CLK_IS_CRITICAL, 100000000);
if (IS_ERR(data->bus_hw))
return PTR_ERR(data->bus_hw);
/* a peripheral gate that forwards rate requests up to ep_bus_clk */
data->periph_hw = devm_clk_hw_register_gate(dev, "ep_periph_clk", "ep_bus_clk",
CLK_SET_RATE_PARENT,
data->base, 0, 0, &data->lock);
if (IS_ERR(data->periph_hw))
return PTR_ERR(data->periph_hw);
return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, data->periph_hw);
}
static const struct of_device_id ep_flagged_of_match[] = {
{ .compatible = "ep,clk-flags-demo" },
{ }
};
MODULE_DEVICE_TABLE(of, ep_flagged_of_match);
static struct platform_driver ep_flagged_driver = {
.probe = ep_flagged_probe,
.driver = {
.name = "ep_clk_flags_demo",
.of_match_table = ep_flagged_of_match,
},
};
module_platform_driver(ep_flagged_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("EmbeddedPathashala clock flags demo");
Because ep_bus_clk carries CLK_IS_CRITICAL, the late-boot
unused-clock cleanup pass will never disable it, even though nothing directly consumes
it in this demo. Because ep_periph_clk carries
CLK_SET_RATE_PARENT, any clk_set_rate() call against it is
forwarded to ep_bus_clk instead of failing outright.
Clock Flags at a Glance
| Flag | Affects |
|---|---|
| CLK_SET_RATE_GATE | Forces gating across rate changes |
| CLK_SET_PARENT_GATE | Forces gating across re-parenting |
| CLK_SET_RATE_PARENT | Forwards round_rate/set_rate to the parent |
| CLK_IGNORE_UNUSED | Skips this clock during unused-clock cleanup |
| CLK_GET_RATE_NOCACHE | Recomputes rate on every query |
| CLK_SET_RATE_NO_REPARENT | Blocks automatic re-parenting on rate change |
| CLK_GET_ACCURACY_NOCACHE | Recomputes accuracy on every query |
| CLK_RECALC_NEW_RATES | Recalculates rate on notification |
| CLK_SET_RATE_UNGATE | Requires the clock to be running to set rate |
| CLK_IS_CRITICAL | Never gates this clock, ever |
| CLK_OPS_PARENT_ENABLE | Requires parent enabled during gate/rate/reparent ops |
| CLK_DUTY_CYCLE_PARENT | Forwards duty-cycle queries to the parent |
Common Mistakes
- Relying on CLK_IS_BASIC, which no longer exists in current kernels
- Setting CLK_SET_RATE_PARENT without understanding it can change sibling clocks’ rates too
- Using CLK_IGNORE_UNUSED as a permanent fix instead of a bring-up debug aid
- Marking a non-essential clock CLK_IS_CRITICAL, wasting power for no real benefit
Best Practices
- Reserve CLK_IS_CRITICAL for clocks whose loss would crash the system
- Document why CLK_SET_RATE_PARENT is set whenever you use it
- Treat CLK_IGNORE_UNUSED as temporary bring-up scaffolding, not a permanent flag
- Combine flags with a plain bitwise OR and keep the combination readable
Summary and Key Takeaways
- Flags live in clk_init_data.flags and change framework behavior, not hardware capability
- CLK_SET_RATE_PARENT and CLK_IS_CRITICAL are the two flags worth the most care
- CLK_IS_BASIC is obsolete; CLK_OPS_PARENT_ENABLE and CLK_DUTY_CYCLE_PARENT are newer additions
- “Gated” always means disabled, and “ungated” always means enabled
Frequently Asked Questions
Can I combine multiple clock flags?
Yes, they are simple bit values meant to be combined with a bitwise OR in
clk_init_data.flags.
Is CLK_IS_BASIC safe to use in a new driver?
No, it is no longer used by current kernels and should not appear in new driver
code.
Does CLK_IGNORE_UNUSED replace proper clock claiming?
No, it is meant as a bring-up and debug aid for clocks left on by a bootloader, not
a substitute for a driver correctly calling clk_get()/clk_prepare_enable().
What is the risk of CLK_SET_RATE_PARENT?
A rate change on the clock carrying this flag can propagate up and change the
parent’s rate, which may also affect every sibling clock sharing that same parent.
When would I use CLK_GET_RATE_NOCACHE?
When hardware or firmware outside the kernel’s control can change a clock’s rate,
so the cached value the CCF would otherwise trust could go stale.
Suggested Images For This Lecture
- Diagram: clk_ops vs init.flags responsibility split
- Diagram: CLK_SET_RATE_PARENT forwarding a rate request upstream
- Table graphic: all current CLK_* flags at a glance
Continue This Free Linux Kernel Development Course
Next, we start our first full clock-type case study: the fixed-rate clock, its
struct clk_fixed_rate wrapper, and how to register one from scratch.
