RT-Thread RTOS
An open source embedded real-time operating system
Fixed clock provider

<tt>fixed-clock</tt> platform driver

Implementation: **components/drivers/clk/clk-fixed-rate.c**. Driver name: **clk-fixed-rate**. Overview: Clock framework (CLK).

Registers a constant-frequency, always-on clock with no gate, parent, or rate programming — the leaf most SoC trees hang PLLs from.


Device tree

osc24m: fixed-clock {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <24000000>;
clock-accuracy = <0>; /* optional, ppb */
clock-output-names = "osc24m"; /* optional; becomes cell name */
};

Consumers:

uart0: serial@40000000 {
clocks = <&osc24m>;
/* clock-names optional when only one clock */
};

With **#clock-cells = <0>**, the specifier in **clocks = <&osc24m>** has no extra integers (implicit index 0).


Probe flow

  1. **rt_platform_driver_register** via **INIT_SUBSYS_EXPORT(fixed_clk_drv_register)** — early registration so crystal nodes probe before CCM consumers.
  2. **fixed_clk_probe**: rt_calloc **struct clk_fixed** (embeds **rt_clk_node** + one **rt_clk_fixed_rate**).
  3. **rt_dm_dev_prop_read_u32(dev, "clock-frequency", &val)** — required; probe fails without it.
  4. Optional **clock-accuracy**, **clock-output-names** → **fcell.cell.name**.
  5. Wire **cells[0]**, **fixed_clk_ops** (only **.recalc_rate**).
  6. **rt_clk_register(&cf->parent)** — may run **rt_ofw_clk_set_defaults** if the fixed-clock node has **assigned-clocks*** (unusual on leaf osc).

Data structures

struct clk_fixed {
struct rt_clk_node parent;
struct rt_clk_fixed_rate fcell;
struct rt_clk_cell *cells[1];
};
struct rt_clk_cell cell;
rt_ubase_t fixed_rate;
rt_ubase_t fixed_accuracy;
};
Clock cell - represents a single hardware clock element.
Definition: clk.h:99
Fixed-rate clock descriptor.
Definition: clk.h:130
Clock provider node - represents a hardware clock controller.
Definition: clk.h:64
Member Role
**fixed_rate** Hz from **clock-frequency**
**fixed_accuracy** Optional ppb from DT
**cell.ops->recalc_rate** Returns **fixed_rate**; ignores parent

No **enable/disable/prepare** — enabling is a no-op at ops level; framework refcount still works for consumers.


OFW matching

static const struct rt_ofw_node_id fixed_clk_ofw_ids[] = {
{ .compatible = "fixed-clock" },
{ /* sentinel */ }
};

Linux-compatible binding; same node can be shared across BSP DTS and upstream dt-bindings.


When to use vs SoC CCM

Use **fixed-clock** Use SoC driver (e.g. rockchip,*-cru)
Crystal, RC oscillator, external clock input PLL, mux, divider, gate
Rate fixed at boot DVFS, dynamic reparent
No MMIO (or MMIO not managed here) Large clock controller IP

Consumer example

struct rt_clk *clk = rt_clk_get_by_name(dev, "uart_clk");
/* or index 0 if no clock-names */
rt_err_t err = rt_clk_prepare_enable(clk);
rt_ubase_t hz = rt_clk_get_rate(clk);
struct rt_clk * rt_clk_get_by_name(struct rt_device *dev, const char *name)
Get clock pointer from ofw device node by name.
Definition: clk.c:1892
rt_ubase_t rt_clk_get_rate(struct rt_clk *clk)
Get clock rate.
Definition: clk.c:1183
rt_err_t rt_clk_prepare_enable(struct rt_clk *clk)
Prepare and enable clock.
Definition: clk.c:663
Clock handle - represents a consumer reference to a clock.
Definition: clk.h:144

Fixed clocks rarely need **rt_clk_set_rate** — rate is fixed; **rt_clk_get_rate** reads **recalc_rate**.


Pitfalls

  • Missing clock-frequency — probe fails, phandle resolution returns NULL for consumers.
  • Wrong Hz in DT — all derived PLL math wrong; UART baud, SDIO timing, etc. break silently.
  • Using fixed-clock for gated peripherals — use a gate driver cell instead.
  • Name collisions — **clock-output-names** should be unique enough for **rt_clk_get_by_name** fallback lookup.

See also