一、设备树基础
1、什么是设备树
描述设备树的文件叫做DTS文件,DTS文件采用树形结构描述板级设备(开发板上的设备信息)。
在以前的linux内核中,ARM架构没有采用设备树,在内核源码中有大量的arch/arm/mach-xxx和arch/arm/plat-xxx文件夹,这些文件夹里的文件就是对应平台下的板级信息。
如果不使用设备树来描述板级设备信息,则这些信息的.h和.c文件就要被编译进linux内核,这会造成内核有太多冗余。
2、DTS、DTB和DTC
设备树源文件扩展名为.dts,编译后的二进制文件扩展名为.dtb,编译工具为DTC工具。编译.dts文件时,进入内核源码根目录,使用make dtbs来进行编译。
设置linux内核编译时编译哪个SOC的设备树文件,修改arch/arm/boot/dts/Makefile的内容,找到自己使用的SOC,然后添加自己开发板的.dtb文件。在编译时对应的.dts文件就会被编译成二进制的.dtb文件。
二、设备树语法
1、设备树头文件
设备树支持头文件,头文件扩展名为xxx.dtsi、xxx.h 和 xxx.dts。
一般.dtsi文件用于描述SOC的内部外设信息,比如CPU架构、主频、外设寄存器地址范围(如UART、I2C等)。一般开发板使用哪颗SOC,就对调用对应的.dtsi文件。
2、设备节点
设备树是采用树形结构来 描述板子上的设备信息的文件,每个设备都是一个节点,叫做设备节点,每个节点都通过一些属性信息来描述节点信息。设备树模板:
/ {
//根节点
aliases {
//一级子节点aliases
can0 = &flexcan1;
};
cpus {
//一级子节点cpus
#address-cells = <1>;
#size-cells = <0>;
cpu0: cpu@0 {
//二级子节点
compatible = "arm,cortex-a7";
device_type = "cpu";
reg = <0>;
};
};
intc: interrupt-controller@00a01000 {
//一级子节点interrupt-controller
compatible = "arm,cortex-a7-gic";
#interrupt-cells = <3>;
interrupt-controller;
reg = <0x00a01000 0x1000>,
<0x00a02000 0x100>;
};
};
第1行 “/” 是根节点,每个设备树文件只有一个根节点,包含的.dtsi里面也有一个根节点,这些根节点的内容会合并成一个根节点,如果合并的节点都对同一个属性赋值,则新的值会覆盖旧的值。
第2、6、17行是一级子节点的名字,设备树中节点命名格式为:node-name@unit-address ,其中“node-name”是节点名字,第17行节点名字前可以有一个标签 lable: ,使用 &lable 可以访问节点,向节点内添加属性信息。“@unit-address” 一般表示设备的地址或寄存器首地址。如果节点没有可以不要。
第10行是二级子节点。
3、标准属性
节点内都是属性,不同设备需要的属性不同,用户也可以自定义属性,有一些属性是标准属性,linux下的很多外设驱动都会使用这些标准属性。
- compatible
compatible属性叫做“兼容性”属性,它的值是一个字符串列表,作用是将设备和驱动绑定起来,compatible格式如下:
compatible = "manufacturer,model";
其中 manufacturer 表示厂商,modle 一般是模块对应的驱动名字。比如imx6ull-alientek-emmc.dts中的sound节点是音频设备节点,sound节点的compatible属性如下:
compatible = "fsl,imx6ul-evk-wm8960","fsl,imx-audio-wm8960";
属性值有两个,其中==“fsl”表示厂商是飞思卡尔,“imx6ul-evk-wm8960”==表示驱动模块名字。sound首先使用第一个兼容值在linux内核里面查找,如果没有找到匹配驱动文件,就使用第二个兼容值进行查找。
一般驱动文件都会有一个OF匹配表,此OF匹配表保存着一些compatible值,如果compatible的属性值和OF匹配表中的任何一个值,就表示设备可以使用这个驱动。比如imx-wm8960.c中有如下内容:
static const struct of_device_id imx_wm8960_dt_ids[] = {
{
.compatible = "fsl,imx-audio-wm8960", }, //匹配值
{
/* sentinel */ }
};
MODULE_DEVICE_TABLE(of, imx_wm8960_dt_ids);
tatic struct platform_driver imx_wm8960_driver = {
.driver = {
.name = "imx-wm8960",
.pm = &snd_soc_pm_ops,
.of_match_table = imx_wm8960_dt_ids, //设置匹配表
},
.probe = imx_wm8960_probe,
.remove = imx_wm8960_remove,
};
第1行 imx_wm8960_dt_ids 就是驱动文件的匹配表,匹配值为 “fsl,imx-audio-wm8960” ,如果节点中 compatible 的值与之相匹配,则节点会使用此驱动文件。
第11行设置驱动使用的匹配表。
- model
model属性一般描述设备模块信息,比如模块名字:
model = "wm8960-audio";
-
status
status属性用来描述设备状态,状态可选如下:
值 描述 “okay” 表明设备是可操作的。 “disable” 表明设备当前是不可操作的,但在未来可变为可操作,比如热拔插以后。具体含义要看设备的绑定文件。 “fail” 表明表明设备不可操作,设备检测到了一系列的错误,而且设备也不大可能变得可操作。 “fail-sss” 含义和“fail”相同,后面的 sss部分是检测到的错误内容。 -
#address-cells 和 #size-cells
这两个属性值都是无符号32位整形,作用在当前节点的子节点,用于描述子节点的地址信息。
#address-cells 属性值决定了子节点 reg 属性中地址信息所占用的字长(32位),#size-cells 属性值决定了子节点 reg 属性中长度信息所占的字长(32位)。reg属性一般都是和地址有关,格式如下:
reg = <address1 length1 address2 length2 address3 length3…………>;
其中 address 表示起始地址,length 表示地址范围。#address-cells 和 #size-cells 使用示例如下:
aips3: aips-bus@02200000 {
compatible = "fsl,aips-bus"<