这两天在折腾 MCP2515 这个 SPI 转 CAN 芯片的设备树,正好分享一下设备树的阅读方法。

设备树的基本知识:

简而言之,设备树是 Linux 中用于分离驱动配置信息和驱动代码的一个树状文件格式,用于避免在代码中硬编码过多的硬件相关数据。因此,设备树实际上是对应硬件驱动的延伸。比如使用 MCP2515 时,需要在对应的 SPI 总线上启用 MCP2515 的驱动,通过配置设备树可以在不改动 .c 代码的情况下将上述变化告知 Linux。同时,设备树作为一个树形的结构,还可以很方便地表示外设及将外设作为接口的关系,比如 SPI 既是外设,也是与其他接口通信时使用的总线,下面管辖的设备可以是屏幕,也可以是 MCP2515 这样的其他设备。这样,在使用 MCP2515 时,不需要关心 SPI 总线的具体实现,只需要使用通信协议即可。 设备树文件后缀为 .dts,另外可以用#include "xxx.dts"的格式包含 .dtsi 文件,类似 .c 和 .h 的关系。

阅读设备树

设备树中最重要的参数是compatible属性,这是一个或多个字符串,定义对应的驱动。驱动的格式通常为厂商,驱动名,如microchip,mcp2515

找到了 compatible 属性后,可以在 linux 仓库中搜索对应名字的设备树定义或驱动文件,如要阅读microchip,mcp2515相关信息时,全局搜索microchip,mcp2515,可以找到 linux/drivers/net/can/spi/mcp251x.c 和 linux/Documentation/devicetree/bindings/net/can/microchip,mcp251x.txt 这两个文件,分别对应驱动代码和设备树定义。

设备树中的各个选项的文档在 linux/Documentation/devicetree/bindings 中对应的文件,后缀为 .txt/.yaml。当然,真正的定义大部分在该节点或父节点的驱动中,如下面的gpio-controller在 linux/drivers/net/can/spi/mcp251x.c 中定义,而reg属性在 linux/drivers/spi/spi.c 中定义。

以 linux/Documentation/devicetree/bindings/net/can/microchip,mcp251x.txt 为例

* Microchip MCP251X stand-alone CAN controller device tree bindings

Required properties:
 - compatible: Should be one of the following:
   - "microchip,mcp2510" for MCP2510.
   - "microchip,mcp2515" for MCP2515.
   - "microchip,mcp25625" for MCP25625.
 - reg: SPI chip select.
 - clocks: The clock feeding the CAN controller.
 - interrupts: Should contain IRQ line for the CAN controller.

Optional properties:
 - vdd-supply: Regulator that powers the CAN controller.
 - xceiver-supply: Regulator that powers the CAN transceiver.
 - gpio-controller: Indicates this device is a GPIO controller.
 - #gpio-cells: Should be two. The first cell is the pin number and
                the second cell is used to specify the gpio polarity.

Example:
	can0: can@1 {
		compatible = "microchip,mcp2515";
		reg = <1>;
		clocks = <&clk24m>;
		interrupt-parent = <&gpio4>;
		interrupts = <13 IRQ_TYPE_LEVEL_LOW>;
		vdd-supply = <&reg5v0>;
		xceiver-supply = <&reg5v0>;
		gpio-controller;
		#gpio-cells = <2>;
	};

这个文件包括三部分,必要属性、可选属性及示例。 必要属性包括

  • compatible:选择驱动
  • reg:片选,在 spi.c 中of_property_read_u32(nc, "reg", &value)定义
  • clocks:时钟,在 mcp251x.c 中devm_clk_get_optional定义
  • interrupts:中断,在 spi.c 中of_irq_get定义

可选属性包括

  • vdd-supplyxceiver-supply:mcp251x.c 中devm_regulator_get_optional定义
  • gpio-controller:在 mcp251x.c 中device_property_present(&priv->spi->dev, "gpio-controller")定义
  • #gpio-cells:基本属性,在 linux/drivers/of/property.c 中定义

这里的属性只是大致说明,和具体设备树中的属性列表并不一一对应,比如时钟很可能无需在驱动中启停,因此代码中还定义了clock-frequency属性,只用于计算比特率,而中断还需要与interrupt-parent搭配使用。另外代码还给出了一个示例用于了解基本的使用方法。

注:现在 MCP2515 通常只使用 SPI 进行通信,最多结合一个中断引脚避免轮询。实际上 MCP2515 的每个发送和输入缓冲区都有对应的引脚,可以用于直接控制收发,或者也可以复用为 GPIO,拓展 GPIO 接口数量,因此有gpio-controller属性。