What is Mandatory clk_ops By Clock Type in Linux Kernel

Mandatory clk_ops By Clock Type-Free Linux Device Drivers Course
Free Linux Kernel Development Course · Common Clock Framework · Kernel 6.x
Chapter 4 · Lecture 13
Reading Time: 13 min
Level: Intermediate

Keywords covered in this lecture

mandatory clk_ops clock type
linux multiplexer clock driver
clk_hw get_parent set_parent
clk_ops checklist
free linux kernel development course
free embedded systems course

The previous lecture covered every callback in struct clk_ops one by one, but left
an important practical question unanswered: for the clock you are actually writing,
which of those callbacks are you required to implement? This lecture answers that
with a single reference table covering mandatory clk_ops by clock type
— gate clocks, rate-changing clocks, single-parent clocks, multiplexer clocks, and
root clocks — so you know exactly what your driver owes the framework before you
start writing it.

What You Will Learn

  • Which clk_ops callbacks are mandatory for a gate-capable clock
  • Which callbacks a rate-changing clock must supply
  • Why single-parent and root clocks must not implement set_parent/get_parent
  • Why multiplexer clocks are the one case where set_parent/get_parent are required
  • Using this table as a pre-flight checklist before writing a new clock driver

Prerequisites

  • CCF clk_ops callback reference guide (previous lecture)
  • CCF base clock types overview

Mandatory clk_ops Callbacks By Clock Type

The table below groups clocks by hardware capability rather than by base type name,
since that is really what determines which callbacks the CCF expects from you. A
“root” clock here means a clock with no parent at all, such as an external oscillator.

Callback Gate Change Rate Single Parent Multiplexer Root
prepare / unprepare optional optional optional optional optional
enable / disable / is_enabled required
recalc_rate required
round_rate / determine_rate one required
set_rate required
set_parent must not implement required must not implement
get_parent must not implement required must not implement
recalc_accuracy optional optional optional optional optional
init optional optional optional optional optional

“one required” on the round_rate/determine_rate row means exactly
one of the two should be implemented, never both — see the previous lecture for
why determine_rate is the preferred choice in new drivers.

Reading the Table Column by Column

Gate

Any clock capable of being turned on or off must implement
enable/disable (or prepare/unprepare
for sleepable buses, per the previous lecture), plus is_enabled if you want
the CCF to query real hardware state instead of relying on its own internal counter.

Change Rate

Any clock that can change its output frequency must implement
recalc_rate so the CCF knows the current rate, exactly one of
round_rate/determine_rate so a requested rate can be validated,
and set_rate to actually apply it.

Single Parent and Root

A clock with exactly one possible parent, and a root clock with no parent at all,
must never implement set_parent or get_parent. There is
nothing to select between, so providing these callbacks would be meaningless and
could confuse the framework about how many parents the clock actually has.

Multiplexer

This is the one column where set_parent and get_parent
flip from forbidden to mandatory. A multiplexer clock, by definition, has two or more
possible parents, and the CCF needs both a way to change the active parent and a way to
ask the hardware which parent is currently selected.

Using the Table as a Pre-Flight Checklist

Here is an original, minimal example applying just the “Gate” column of the table
— a clock that can only turn on and off, with nothing else implemented, matching
exactly what the table says is required and nothing more:

/* ep_gate_only_clk.c - implements only what the Gate column requires */
#include <linux/clk-provider.h>
#include <linux/io.h>

struct ep_gate_only_hw {
    struct clk_hw hw;
    void __iomem *reg;
    u32 enable_mask;
};

static inline struct ep_gate_only_hw *to_ep_gate_only(struct clk_hw *hw)
{
    return container_of(hw, struct ep_gate_only_hw, hw);
}

static int ep_gate_only_enable(struct clk_hw *hw)
{
    struct ep_gate_only_hw *eclk = to_ep_gate_only(hw);
    u32 val = readl(eclk->reg);

    writel(val | eclk->enable_mask, eclk->reg);
    return 0;
}

static void ep_gate_only_disable(struct clk_hw *hw)
{
    struct ep_gate_only_hw *eclk = to_ep_gate_only(hw);
    u32 val = readl(eclk->reg);

    writel(val & ~eclk->enable_mask, eclk->reg);
}

static int ep_gate_only_is_enabled(struct clk_hw *hw)
{
    struct ep_gate_only_hw *eclk = to_ep_gate_only(hw);

    return !!(readl(eclk->reg) & eclk->enable_mask);
}

static const struct clk_ops ep_gate_only_ops = {
    .enable     = ep_gate_only_enable,
    .disable    = ep_gate_only_disable,
    .is_enabled = ep_gate_only_is_enabled,
    /* no recalc_rate, no set_parent/get_parent - this clock only gates */
};

Notice that recalc_rate, set_rate, set_parent,
and get_parent are all absent, exactly as the “Gate” column of the table
says they should be for a clock that only ever turns on and off.

Common Mistakes

  • Implementing get_parent on a clock that genuinely has only one parent
  • Providing set_rate without recalc_rate, leaving the CCF unable to report the current rate
  • Implementing set_parent without get_parent (or vice versa) on a mux clock
  • Adding enable/disable to a pure divider or mux clock that cannot gate at all

Best Practices

  • Check this table before writing a single line of a new clock driver
  • Implement set_parent and get_parent as a pair, never just one
  • Keep gate logic and rate-change logic in separate callbacks even on a composite clock
  • Re-verify the table whenever you add a new capability to an existing clock driver

Summary and Key Takeaways

  • Gate-capable clocks require enable/disable (or prepare/unprepare)
  • Rate-changing clocks require recalc_rate, one of round_rate/determine_rate, and set_rate
  • Single-parent and root clocks must never implement set_parent/get_parent
  • Multiplexer clocks are the only case where set_parent/get_parent are mandatory

Frequently Asked Questions

What counts as a “root” clock?

A clock with no parent at all, such as an external crystal oscillator feeding the
rest of the clock tree.

Can a clock be both a gate and a multiplexer?

Yes, by implementing both the Gate column’s callbacks and the Multiplexer column’s
callbacks together, or more simply by using a composite clock as covered earlier in
this chapter.

What happens if I implement get_parent on a single-parent clock?

It is technically harmless if it always returns the same index, but it adds
unnecessary code and can mislead future maintainers into thinking the clock has more
than one parent.

Is recalc_accuracy ever mandatory?

No, it stays optional across every clock type in this table; omit it unless your
driver has meaningful accuracy information to report.

Do I need is_enabled if I already implement enable/disable?

It is optional; without it, the CCF tracks enable state through its own internal
counter instead of querying the hardware directly.

Suggested Images For This Lecture

  • Table graphic: mandatory clk_ops callbacks by clock type
  • Diagram: single-parent/root vs multiplexer set_parent/get_parent rule
  • Checklist graphic: gate-only clock driver requirements

Continue This Free Linux Kernel Development Course

Next, we implement a complete gate clock driver from scratch, callback by callback,
and register it against real device tree data.

Leave a Reply

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