3. 设备树绑定文档:内核Documentation/devicetree/bindings目录结构、如何阅读绑定文档、编写自定义绑定
设备树绑定文档(Device Tree Binding Document)是内核官方定义的“硬件描述规范说明书”。它规定了某个IP或设备在设备树中应该怎么写、有哪些属性、哪些是必须的、哪些是可选的。对于驱动开发者来说,绑定文档就是设备树与驱动之间的“契约”。
核心认知: 绑定文档不是代码,但它决定了驱动能否正确解析设备树。没有绑定文档的驱动,在主线内核中几乎不可能被接受。
3.1 内核绑定文档目录结构
内核源码树中的 Documentation/devicetree/bindings/ 目录按照设备类型和厂商进行组织。其结构清晰,便于开发者快速定位。
目录结构遵循以下规则:
- 顶层目录:按设备类型分类,如
arm/、clock/、gpio/、i2c/、spi/、net/、sound/、display/等。 - 厂商子目录:在类型目录下,通常有
vendor/子目录,存放具体厂商的绑定文件。 - 文件格式:新内核(5.x+)统一使用
.yaml格式(基于 json-schema 的 YAML 绑定)。旧内核可能还有.txt格式的纯文本绑定。
| 目录路径 | 内容说明 | 典型文件 |
|---|---|---|
bindings/arm/ |
ARM 架构相关设备(CPU、GIC、定时器等) | arm,gic.yaml |
bindings/clock/ |
时钟控制器、固定时钟、PLL 等 | fixed-clock.yaml |
bindings/gpio/ |
GPIO 控制器、GPIO 按键等 | gpio-controller.yaml |
bindings/i2c/ |
I2C 控制器及 I2C 从设备 | i2c-gpio.yaml |
bindings/spi/ |
SPI 控制器及 SPI 从设备 | spi-controller.yaml |
bindings/net/ |
以太网 MAC/PHY、无线网卡等 | microchip,enc28j60.yaml |
bindings/sound/ |
音频编解码器、DAI 链路等 | simple-audio-card.yaml |
bindings/trivial-devices.yaml |
简单设备(无需独立绑定文件)的汇总 | (单文件) |
3.2 如何阅读绑定文档
以 Documentation/devicetree/bindings/gpio/gpio-controller.yaml 为例,展示如何解析一个标准的 YAML 绑定文件。
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/gpio/gpio-controller.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: GPIO Controller
maintainers:
- Linus Walleij <linus.walleij@linaro.org>
description: |
This binding describes a generic GPIO controller.
Each GPIO controller must have a "gpio-controller" property.
properties:
compatible:
description: Compatible string for the GPIO controller.
items:
- enum:
- brcm,bcm2835-gpio
- nvidia,tegra20-gpio
- ti,omap4-gpio
reg:
description: Address and length of the register map.
maxItems: 1
gpio-controller:
description: Boolean property indicating this node is a GPIO controller.
type: boolean
"#gpio-cells":
description: Number of cells in a GPIO specifier.
enum: [1, 2]
default: 2
required:
- compatible
- reg
- gpio-controller
- "#gpio-cells"
additionalProperties: false
examples:
- |
gpio@50000000 {
compatible = "brcm,bcm2835-gpio";
reg = <0x50000000 0x1000>;
gpio-controller;
#gpio-cells = <2>;
};
阅读绑定文档的关键步骤:
- 查看 title 和 description:了解该绑定描述的是什么设备。
- 检查 compatible 列表:确认你的设备是否在支持的兼容字符串列表中。
- 分析 properties 段:区分哪些是
required(必须)属性,哪些是optional(可选)属性。 - 理解属性类型:
boolean(布尔)、uint32(32位整数)、string(字符串)、phandle(句柄)等。 - 参考 examples 段:示例代码展示了完整的设备树节点写法,是最直接的参考。
阅读技巧: 绑定文档中的
required 列表是“最低要求”。如果你的设备树节点缺少任何一个 required 属性,内核在解析时会报错,驱动 probe 会失败。
3.3 编写自定义绑定
当你需要为新的硬件设备编写驱动时,必须同时编写对应的绑定文档。以下是编写自定义绑定的标准流程和规范。
3.3.1 绑定文件模板
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/misc/my-custom-device.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: My Custom Device
maintainers:
- Your Name <your.email@example.com>
description: |
This binding describes a custom device that does XYZ.
It uses MMIO registers and generates interrupts.
properties:
compatible:
description: Compatible string for the device.
items:
- const: vendor,my-custom-device
reg:
description: Register map base address and size.
maxItems: 1
interrupts:
description: Interrupt number for the device.
maxItems: 1
clock-names:
description: Names of the clocks.
items:
- const: bus
- const: core
clocks:
description: Phandles to the clocks.
minItems: 2
maxItems: 2
vendor-specific-prop:
description: A vendor-specific property (example).
$ref: /schemas/types.yaml#/definitions/uint32
default: 0x100
required:
- compatible
- reg
- interrupts
additionalProperties: false
examples:
- |
my-device@40000000 {
compatible = "vendor,my-custom-device";
reg = <0x40000000 0x1000>;
interrupts = <0 42 4>;
clocks = <&clkc 15>, <&clkc 16>;
clock-names = "bus", "core";
vendor-specific-prop = <0x200>;
};
3.3.2 编写步骤
| 步骤 | 操作 | 说明 |
|---|---|---|
| 1 | 确定 compatible 字符串 | 格式为 vendor,device,如 ti,am335x-uart。vendor 必须是内核认可的厂商前缀。 |
| 2 | 列出所有属性 | 包括 reg、interrupts、clocks、resets、DMA 等标准属性,以及厂商自定义属性。 |
| 3 | 标记 required 和 optional | 驱动 probe 必须依赖的属性放在 required 中;可选功能放在 optional 中。 |
| 4 | 编写 examples | 提供一个完整的、可编译通过的设备树节点示例。 |
| 5 | 使用 dt_binding_check 验证 | 运行 make dt_binding_check DT_SCHEMA_FILES=my-custom-device.yaml 检查语法。 |
3.3.3 验证绑定文件
内核提供了专门的工具来验证绑定文件的正确性:
# 验证单个绑定文件
make dt_binding_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/misc/my-custom-device.yaml
# 验证所有绑定文件(耗时较长)
make dt_binding_check
# 验证设备树源文件是否匹配绑定
make dtbs_check DT_SCHEMA_FILES=my-custom-device.yaml
常见错误:
- compatible 字符串未在绑定文档中列出,导致 dtbs_check 报错。
- required 属性遗漏,驱动 probe 时返回 -ENODEV。
- 属性类型错误(如把 uint32 写成了 string),导致解析失败。
- YAML 缩进错误(必须使用空格,不能使用 Tab)。
3.3.4 绑定文档与驱动的对应关系
3.3.5 绑定文档编写规范总结
- 命名规范:文件名使用
vendor,device.yaml格式,如ti,am335x-uart.yaml。 - 兼容性:如果设备有多个版本,使用
enum列出所有兼容字符串。 - 属性复用:尽量复用内核已有的属性定义(如
reg、interrupts),避免重复发明轮子。 - 文档完整性:每个属性都要有
description,说明其作用和取值范围。 - 示例有效性:examples 中的代码必须能通过
dtbs_check验证。
实战建议: 在编写自定义绑定之前,先在内核源码中搜索类似设备的绑定文件作为参考。例如,编写 SPI 设备绑定时,参考
bindings/spi/ 目录下的现有文件。复制一份并修改,比从零开始更高效且不易出错。