MCP251x设备树阅读
这两天在折腾 MCP2515 这个 SPI 转 CAN 芯片的设备树,正好分享一下设备树的阅读方法。
设备树的基本知识:
- https://github.com/mykhani/device-tree-guide
- https://docs.kernel.org/devicetree/usage-model.html
- https://www.devicetree.org/
- https://cloud.tencent.com/developer/article/2008640
简而言之,设备树是 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 = <®5v0>;
xceiver-supply = <®5v0>;
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-supply
和xceiver-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
属性。