1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
@page page_device_clk_fixed Fixed clock provider
# `fixed-clock` platform driver
Implementation: **`components/drivers/clk/clk-fixed-rate.c`**. Driver name: **`clk-fixed-rate`**. Overview: @ref page_device_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
```dts
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:
```dts
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
```c
struct clk_fixed {
struct rt_clk_node parent;
struct rt_clk_fixed_rate fcell;
struct rt_clk_cell *cells[1];
};
struct rt_clk_fixed_rate {
struct rt_clk_cell cell;
rt_ubase_t fixed_rate;
rt_ubase_t fixed_accuracy;
};
```
| 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
```c
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
```c
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);
```
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
- @ref page_device_clk
- `components/drivers/clk/clk-fixed-rate.c`
- `components/drivers/include/drivers/clk.h`
|