4、设备树绑定文档:如何读懂和编写binding文档

设备树绑定文档,说白了就是一份“说明书”。

它告诉内核:某个硬件设备该怎么描述,哪些属性是必须的,哪些是可选的。我刚开始接触设备树时,觉得这玩意儿可有可无。直到有一次,我调试一个I2C触摸屏,死活驱动不起来。查了两天,最后发现是设备树里少写了一个 interrupts 属性。嗯,从那以后,我再也不敢小看binding文档了。

4.1 什么是设备树绑定?

设备树绑定(Device Tree Binding)是一份文档规范。它定义了:

  • 某个硬件设备在设备树中应该有哪些节点
  • 每个节点需要哪些属性
  • 属性的数据类型是什么
  • 属性值的取值范围

你想想看,如果没有这份文档,内核开发者怎么知道某个设备该怎么配置?全靠猜吗?显然不行。

我个人习惯,在写一个新的设备驱动之前,一定会先找到对应的binding文档。哪怕只是扫一眼,也能避免很多低级错误。

4.2 绑定文档的存放位置

在Linux内核源码中,binding文档通常存放在:

Documentation/devicetree/bindings/

这个目录下按设备类型分了子目录,比如:

  • i2c/ — I2C设备
  • gpio/ — GPIO控制器
  • clock/ — 时钟控制器
  • pinctrl/ — 引脚控制
  • display/ — 显示设备
  • sound/ — 音频设备

每个设备类型下,通常是一个 .yaml 文件。现在内核社区已经全面转向YAML格式的绑定文档。老式的纯文本格式(.txt)正在被逐步淘汰。

重要提示:如果你在内核里找不到某个设备的binding文档,那说明这个设备可能还没有被主线支持。这时候你需要自己写一份binding文档,提交给社区。

4.3 如何读懂YAML格式的binding文档

YAML格式的binding文档,结构非常清晰。我来拆解一下:

4.3.1 基本结构

一个典型的YAML binding文档长这样:

# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/i2c/foo,i2c-touch.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: Foo I2C Touchscreen Controller

maintainers:
  - Zhang San <zhangsan@foo.com>

description: |
  This binding describes the Foo I2C touchscreen controller.
  It supports up to 5-point multi-touch.

properties:
  compatible:
    const: foo,i2c-touch

  reg:
    maxItems: 1
    description: I2C address of the device

  interrupts:
    maxItems: 1
    description: Interrupt number for touch events

  touchscreen-size-x:
    $ref: /schemas/types.yaml#/definitions/uint32
    description: Maximum X resolution

  touchscreen-size-y:
    $ref: /schemas/types.yaml#/definitions/uint32
    description: Maximum Y resolution

required:
  - compatible
  - reg
  - interrupts

additionalProperties: false

examples:
  - |
    i2c {
        #address-cells = <1>;
        #size-cells = <0>;

        touchscreen@2a {
            compatible = "foo,i2c-touch";
            reg = <0x2a>;
            interrupt-parent = <&gpio1>;
            interrupts = <5 IRQ_TYPE_EDGE_FALLING>;
            touchscreen-size-x = <1024>;
            touchscreen-size-y = <768>;
        };
    };

4.3.2 关键字段解读

字段 含义 说明
title 设备名称 简洁描述设备是什么
maintainers 维护者列表 出了问题找谁
description 详细描述 设备的功能、特性等
properties 属性定义 每个属性的类型、约束、说明
required 必需属性列表 少了这些属性,设备树就是非法的
examples 示例 一个完整的设备树节点示例

我的小技巧:看binding文档时,先看 required 字段。它告诉你哪些属性是“命根子”,缺一不可。然后看 examples,直接抄作业。最后再细看 properties,理解每个属性的含义。

4.4 如何编写binding文档

写binding文档,其实没那么玄乎。我总结了一套流程:

4.4.1 第一步:确定设备类型和兼容字符串

兼容字符串的格式是:厂商,设备型号。比如:

  • ti,ads1015 — TI的ADS1015 ADC芯片
  • nxp,pca9685 — NXP的PCA9685 PWM控制器
  • microchip,mcp23017 — Microchip的MCP23017 GPIO扩展器

注意:厂商名要小写,设备型号要精确。我曾经见过有人把 ti,ads1015 写成 ti,ads1015-adc,结果驱动匹配不上。这种坑,踩一次就够了。

4.4.2 第二步:列出所有属性

把设备需要的所有属性列出来。分三类:

  1. 标准属性:比如 reginterruptsclocksreset-gpios 等。这些有通用的定义,直接引用即可。
  2. 设备特有属性:比如触摸屏的 touchscreen-size-x、音频编解码器的 micbias-voltage 等。这些需要你自己定义。
  3. 可选属性:比如电源管理相关的 vcc-supplypowerdown-gpios 等。

4.4.3 第三步:确定数据类型

YAML binding中,常见的数据类型有:

类型 YAML表示 说明
32位整数 uint32 单个数值
32位整数数组 uint32-array 多个数值,如 <1 2 3>
字符串 string "foo,i2c-touch"
布尔值 boolean 存在即为true
GPIO句柄 phandle+gpio-specifier <&gpio1 5 GPIO_ACTIVE_LOW>

4.4.4 第四步:写示例

示例很重要。它是binding文档的“活教材”。

我建议:示例要尽量完整。把必需属性和常用可选属性都写进去。这样别人抄作业时,不容易漏掉东西。

4.5 避坑指南

我曾经踩过的坑:

  • 兼容字符串写错:大小写、连字符、下划线,一个都不能错。驱动匹配是精确匹配,错一个字符就匹配不上。
  • 遗漏必需属性:比如I2C设备忘了写 reg,或者中断设备忘了写 interrupts。内核在解析设备树时会报错,但错误信息往往不直观,排查起来很痛苦。
  • 属性类型搞错:比如把 uint32 写成了 string,或者把 phandle 写成了 uint32。驱动在读取属性值时,会得到错误的数据。
  • 忘记更新binding文档:驱动代码改了,但binding文档没同步。别人看文档时,发现和实际代码对不上。这种问题在内核社区review时会被直接打回来。

4.6 知识体系图

下面这张图,帮你理清binding文档的核心逻辑:

设备树绑定文档知识体系 Binding文档 如何读懂 如何编写 避坑指南 YAML结构:title/properties/required 关键字段:compatible/reg/interrupts 示例:直接抄作业 第一步:确定兼容字符串 第二步:列出所有属性 第三步:确定数据类型 第四步:写完整示例 兼容字符串大小写错误 遗漏必需属性 属性类型搞错 文档与代码不同步 核心:读懂 + 编写 + 避坑 = 合格的binding文档

4.7 小结

设备树绑定文档,是设备驱动开发的地基。地基没打好,上面的房子再漂亮也白搭。

我个人习惯,每次提交一个新的设备驱动时,都会把binding文档放在第一位。先写文档,再写代码。这样能逼着自己把设备的所有属性都想清楚,而不是边写代码边拍脑袋。

记住一句话:好的binding文档,能让后来者少掉一半头发。

实用工具推荐:

  • dt-doc-validate — 验证binding文档格式是否正确
  • make dt_binding_check — 内核自带的binding检查工具
  • make dtbs_check — 检查设备树文件是否符合binding规范

嗯,这一章就到这里。binding文档这东西,看多了自然就熟了。下次你拿到一个新设备的datasheet,不妨先试着写一份binding文档,你会发现,很多硬件细节在写文档的过程中就理清楚了。