Keywords covered in this lecture
struct clk_fixed_factor
clk_hw_register_fixed_factor
fixed-factor-clock device tree
free linux kernel development course
free linux device drivers course
Some clocks in a system are not truly independent sources at all — they are
just a parent clock multiplied and divided by a fixed ratio, wired in purely to feed a
peripheral the exact frequency it needs. The CCF models this directly as the
linux fixed factor clock type, and it comes with a small but
important quirk in how its set_rate callback behaves that is worth
understanding before you ever write one.
What You Will Learn
- The struct clk_fixed_factor wrapper and its mult/div fields
- Why this clock type can change rate at all despite having no gate or divider hardware
- Why its set_rate callback must be a deliberate no-op returning 0
- Using clk_hw_register_fixed_factor() instead of building the struct by hand
- The fixed-factor-clock DT binding that needs no driver at all
Prerequisites
- Fixed and PWM clock bindings (previous lecture)
- Linux clock flags reference guide (CLK_SET_RATE_PARENT)
- Fixed-rate clock case study (struct clk_fixed_rate, container_of pattern)
The struct clk_fixed_factor Wrapper
A fixed-factor clock’s hardware-specific state is just two small integers: how much
to multiply the parent rate by, and how much to divide it by afterward.
struct clk_fixed_factor {
struct clk_hw hw;
unsigned int mult;
unsigned int div;
};
#define to_clk_fixed_factor(_hw) \
container_of(_hw, struct clk_fixed_factor, hw)
The resulting rate is always parent_rate * mult / div. This clock cannot
gate — there is no enable bit anywhere in this picture, only arithmetic on
whatever rate the parent happens to be running at.
Why set_rate Must Be a Deliberate No-Op
A fixed-factor clock has no way to change its own multiplier or divider at runtime
— those are fixed at registration time. The only way its output rate can change at
all is if the parent’s rate changes, which requires the
CLK_SET_RATE_PARENT flag from an earlier lecture to be set so that any
clk_set_rate() request is forwarded upstream instead of failing.
Here is the subtlety: once CLK_SET_RATE_PARENT is set and the request
succeeds upstream, the CCF still calls this clock’s own set_rate callback
as the final step of applying that rate change. If the callback were left NULL, the CCF
would treat this clock as entirely rate-immutable and refuse the operation outright. The
fix is to provide a callback that does nothing but signal success:
static int clk_factor_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
return 0;
}
This is a deliberate no-op: the actual rate change already happened at the parent, and
this function’s only job is to confirm to the CCF that nothing further needs to happen
locally. recalc_rate and round_rate are still implemented
normally, since the clock does need to report and validate rates — it is only the
act of “setting” a rate locally that has nothing left to do.
The Built-In clk_fixed_factor_ops
You rarely need to write any of this yourself. The framework already ships a complete
ops struct for this exact type:
const struct clk_ops clk_fixed_factor_ops = {
.round_rate = clk_factor_round_rate,
.set_rate = clk_factor_set_rate,
.recalc_rate = clk_factor_recalc_rate,
};
EXPORT_SYMBOL_GPL(clk_fixed_factor_ops);
Its round_rate and recalc_rate implementations already
account for CLK_SET_RATE_PARENT internally, so once you register through
the dedicated helper, you genuinely do not need to think about ops at all:
struct clk_hw *clk_hw_register_fixed_factor(struct device *dev,
const char *name,
const char *parent_name,
unsigned long flags,
unsigned int mult,
unsigned int div);
This allocates a struct clk_fixed_factor internally, wires up
clk_fixed_factor_ops, and registers it in one call — the same
simplification pattern the fixed-rate clock lecture already introduced.
Original Demo: A x2/÷3 Fixed-Factor Clock
/* ep_fixed_factor_demo.c - registers a mult=2, div=3 clock derived from a parent */
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/clk-provider.h>
#include <linux/of.h>
static int ep_fixed_factor_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct clk_hw *hw;
/* output rate = parent_rate * 2 / 3, tracks the parent via CLK_SET_RATE_PARENT */
hw = devm_clk_hw_register_fixed_factor(dev, "ep_derived_clk", "ep_ext_osc",
CLK_SET_RATE_PARENT, 2, 3);
if (IS_ERR(hw))
return PTR_ERR(hw);
return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw);
}
static const struct of_device_id ep_fixed_factor_of_match[] = {
{ .compatible = "ep,clk-fixed-factor-demo" },
{ }
};
MODULE_DEVICE_TABLE(of, ep_fixed_factor_of_match);
static struct platform_driver ep_fixed_factor_driver = {
.probe = ep_fixed_factor_probe,
.driver = {
.name = "ep_clk_fixed_factor_demo",
.of_match_table = ep_fixed_factor_of_match,
},
};
module_platform_driver(ep_fixed_factor_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("EmbeddedPathashala fixed-factor clock case study demo");
Matching device tree node, deriving from the fixed-clock node introduced in the
previous lecture:
ep_derived_ctrl: clock-controller@6000 {
compatible = "ep,clk-fixed-factor-demo";
#clock-cells = <0>;
clocks = <&ep_ext_osc>;
};
Build and Run
make -C /lib/modules/$(uname -r)/build M=$(pwd) modules
sudo insmod ep_fixed_factor_demo.ko
cat /sys/kernel/debug/clk/clk_summary | grep -A1 ep_ext_osc
With an 8 MHz parent, expected clk_summary excerpt (8,000,000 * 2 / 3 ≈ 5,333,333):
ep_ext_osc 1 1 0 8000000 0
ep_derived_clk 1 1 0 5333333 0
The fixed-factor-clock DT-Only Binding
Just like the fixed-clock and pwm-clock types from the previous lecture, a
fixed-factor clock can also be described purely in the device tree with no driver at all
— the CCF core parses clock-mult/clock-div directly:
ep_derived_dtonly: ep_derived_dtonly {
compatible = "fixed-factor-clock";
#clock-cells = <0>;
clock-div = <3>;
clock-mult = <2>;
clocks = <&ep_ext_osc>;
};
The required properties are #clock-cells (always 0),
compatible = "fixed-factor-clock", clock-div,
clock-mult, and clocks pointing at the parent. Choose this
DT-only form whenever the ratio is fixed by board wiring and no software control is ever
needed; reach for the driver-based form from this lecture only when the ratio needs to
be picked or adjusted by code at probe time.
Driver-Based vs DT-Only Fixed-Factor Clocks
| Aspect | devm_clk_hw_register_fixed_factor() | compatible = “fixed-factor-clock” |
|---|---|---|
| Driver code required | Yes, a probe function | None |
| mult/div source | Chosen in C code, can vary by compatible match | Fixed directly in the DT node |
| Best fit | Ratio depends on runtime/compatible-specific logic | Ratio is fixed purely by board wiring |
Common Mistakes
- Leaving set_rate NULL on a custom fixed-factor-style clk_ops, breaking CLK_SET_RATE_PARENT
- Forgetting CLK_SET_RATE_PARENT, so clk_set_rate() calls fail with nowhere to propagate
- Writing a driver for a ratio that never changes and could have used the DT-only binding
- Swapping mult and div, inverting the intended frequency relationship
Best Practices
- Use clk_hw_register_fixed_factor()/devm_ variant instead of building the struct by hand
- Always pair a fixed-factor clock with CLK_SET_RATE_PARENT unless rate propagation is intentionally unwanted
- Prefer the DT-only fixed-factor-clock binding when the ratio never needs code-driven logic
- Double check mult/div direction against the datasheet before wiring up the DT node
Summary and Key Takeaways
- struct clk_fixed_factor holds just mult and div alongside the embedded clk_hw
- set_rate must be a deliberate no-op returning 0 so CLK_SET_RATE_PARENT can do the real work
- clk_hw_register_fixed_factor() wires up clk_fixed_factor_ops for you automatically
- A DT-only fixed-factor-clock binding exists for boards where the ratio never needs code
Frequently Asked Questions
Can a fixed-factor clock gate on and off?
No, it has no enable bit or gating hardware at all — it only computes a
derived rate from its parent.
Why does set_rate need to exist if it does nothing?
Because a NULL set_rate would tell the CCF the clock’s rate can never change at all,
which would block the CLK_SET_RATE_PARENT forwarding mechanism from working.
What happens if I forget CLK_SET_RATE_PARENT?
A clk_set_rate() call against the fixed-factor clock will fail, since there is
nowhere for the request to go without that flag.
Is the DT-only fixed-factor-clock binding as capable as the driver-based version?
For a purely fixed ratio, yes — both end up using the same
clk_fixed_factor_ops underneath; the difference is only whether C code or a DT
property supplies mult/div.
Can mult and div be changed after registration?
No, both are fixed for the lifetime of the registration; only the parent’s rate can
still change, which this clock’s ratio then scales automatically.
Suggested Images For This Lecture
- Diagram: parent rate flowing through mult/div into a fixed-factor clock
- Flow diagram: CLK_SET_RATE_PARENT forwarding into a no-op local set_rate
- Side-by-side diagram: driver-based vs DT-only fixed-factor-clock binding
Continue This Free Linux Kernel Development Course
Next, we move to the gate clock case study and implement a complete gate clk_ops
set from scratch, register by register.
