2. 时钟节点核心属性:详解 compatible、clocks、clock-names、clock-frequency、assigned-clocks 等关键属性
设备树中时钟节点的核心属性是驱动与硬件时钟控制器之间的契约。正确配置这些属性,是时钟驱动正常工作的前提。本节将逐一拆解 compatible、clocks、clock-names、clock-frequency、assigned-clocks 等关键属性的语义、配置规范及常见错误。
2.1 属性总览与功能分类
时钟节点属性可分为三类:标识属性(匹配驱动)、连接属性(描述时钟树拓扑)、配置属性(设定初始频率与父时钟)。下表列出各属性的核心作用:
| 属性名 | 分类 | 作用 | 是否必需 |
|---|---|---|---|
compatible |
标识 | 匹配时钟控制器驱动 | 是 |
clocks |
连接 | 声明输入时钟源(phandle + 索引) | 视情况 |
clock-names |
连接 | 为 clocks 条目提供语义名称 | 推荐 |
clock-frequency |
配置 | 指定固定频率(通常用于固定时钟) | 视情况 |
assigned-clocks |
配置 | Bootloader 阶段重设时钟频率或父时钟 | 可选 |
assigned-clock-parents |
配置 | 与 assigned-clocks 配合,指定父时钟 | 可选 |
assigned-clock-rates |
配置 | 与 assigned-clocks 配合,指定目标频率 | 可选 |
compatible 和 clocks(如果有输入源)是必须的;对于板级固定频率振荡器,compatible 和 clock-frequency 即可。
2.2 compatible —— 驱动匹配的钥匙
compatible 是设备树中最关键的标识属性。驱动通过 of_match_table 与设备树节点的 compatible 字符串进行匹配。格式为 "厂商,型号",例如:
clk_uart: clock-controller@ff0a0000 {
compatible = "samsung,exynos-uart-clock", "fixed-clock";
// ...
};
匹配优先级:驱动会按 of_match_table 中的顺序依次尝试,设备树中 compatible 的第一个字符串优先级最高。常见错误包括:
- 字符串拼写错误:大小写、连字符、下划线不匹配。
- 缺少 fallback:未包含兼容的通用 compatible,导致旧内核无法匹配。
- 驱动未编译:即使 compatible 正确,驱动未选入内核也会导致匹配失败。
2.3 clocks 与 clock-names —— 构建时钟树拓扑
clocks 属性是一个 phandle + 时钟索引 的列表,描述当前时钟控制器的输入源。每个条目指向一个上游时钟节点。例如:
clk_pll: pll@1000 {
compatible = "vendor,my-pll";
clocks = <&osc 0>, <&clk_ref 1>;
clock-names = "osc", "ref";
};
上述代码表示:
- 第一个输入源是
osc节点的第 0 路输出。 - 第二个输入源是
clk_ref节点的第 1 路输出。 clock-names为每个输入源赋予语义名称,驱动可通过of_clk_get_by_name()按名称获取。
clocks 的顺序必须与 clock-names 一一对应。如果只写 clocks 而不写 clock-names,驱动只能通过索引访问,代码可读性差且容易出错。
2.4 clock-frequency —— 固定频率时钟的声明
对于板级晶振或固定频率振荡器,clock-frequency 直接指定输出频率,单位是 Hz。典型用法:
osc24m: oscillator {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <24000000>;
};
驱动读取该属性后,直接注册一个固定频率时钟。常见问题:
- 频率值写错:例如 24MHz 写成 24000(缺少三个零)。
- 缺少
#clock-cells:固定时钟通常设为 0,表示输出单路时钟。 - 与 assigned-clocks 冲突:如果同时使用
assigned-clocks修改该节点频率,可能导致预期外的覆盖。
2.5 assigned-clocks 系列 —— Bootloader 阶段的时钟重配置
assigned-clocks、assigned-clock-parents、assigned-clock-rates 三个属性配合使用,在 Bootloader(如 U-Boot)或内核早期初始化阶段,对时钟进行重配置。典型场景:
&uart0 {
assigned-clocks = <&clk_uart 0>;
assigned-clock-parents = <&clk_pll 1>;
assigned-clock-rates = <115200>;
};
上述配置表示:将 clk_uart 的第 0 路输出时钟的父时钟设置为 clk_pll 的第 1 路,并将频率设置为 115200 Hz。
使用注意事项:
- 属性位置:通常放在使用该时钟的 消费者节点 中,而非时钟控制器节点。
- 执行时机:在时钟框架初始化完成后、驱动 probe 之前执行。
- 依赖关系:如果父时钟未准备好,配置会延迟或失败。
assigned-clocks 属性,以及 assigned-clock-parents 是否指向了正确的 PLL 输出。
2.6 核心属性关系图
下图展示了时钟节点核心属性之间的逻辑关系与数据流向:
2.7 典型配置示例与对比
以下对比展示一个 固定频率晶振 与一个 可配置 PLL 的节点配置差异:
| 对比项 | 固定晶振 (fixed-clock) | 可配置 PLL |
|---|---|---|
| compatible | "fixed-clock" |
"vendor,my-pll" |
| #clock-cells | <0> |
<1>(多路输出) |
| clocks | 无(自身是根时钟) | <&osc 0> |
| clock-frequency | <24000000> |
无(由 assigned-clocks 配置) |
| assigned-clocks | 通常不写 | 在消费者节点中配置 |
2.8 调试检查清单
当遇到时钟相关驱动 probe 失败或频率异常时,按以下清单逐一排查:
- 检查 compatible 是否匹配:
cat /sys/firmware/devicetree/base/.../compatible与驱动中的of_match_table对比。 - 检查 clocks 是否存在且顺序正确:使用
clk_summary或debugfs查看时钟树连接。 - 检查 clock-names 是否与驱动代码一致:驱动调用
devm_clk_get(dev, "name")时名称必须完全匹配。 - 检查 clock-frequency 单位:确认数值是 Hz,而非 kHz 或 MHz。
- 检查 assigned-clocks 的 phandle 是否有效:确保引用的时钟节点存在且已注册。
- 检查父时钟是否已使能:如果父时钟未使能,子时钟可能无法获取有效频率。
dev_info(dev, "clock rate: %lu\n", clk_get_rate(clk));,对比实际值与预期值是否一致。