1.问:设备树是什么东东?
答:它是一个文件,这个文件描述的是设备的信息
2.问:为什么要引入设备树?
答:因为设备的信息是针对于特定平台的,如果我们在Linux内核中包含太多设备信息,
则Linux内核移植性就会变差。引入设备树之后,设备的信息的描述不在是以代码的形式存在于
Linux内核源代码中,这种做法实际上是将设备的信息,从Linux 内核中独立出来,
单独描述(用设备树语法规则来描述设备的信息)。
3.问:设备的信息是以设备树的形式呈现,那么Linux操作系统是如何识别设备的呢?
答:Linux内核在启动的时候,要求把设备树文件传递给它。它拿到设备树之后,会解析设备树文件,
从而识别设备信息。
3.x Linux 内核platform总线上设备与驱动的匹配规则
<1>设备树中的compatible属性与驱动中指定的of_match_table中的compatible进行匹配
如果没有匹配成功:
<2>如果驱动中有id_table,则拿id_table中记录的名字与设备的名字匹配
如果驱动中没有id_table,则拿驱动的名字与设备的名字匹配
节点名称@reg属性的第一个地址值{
#address-cells = <1>;
#size-cells = <1>; //规定它的子节点reg属性写法
compatible = “名字”;//和驱动匹配 (必须)
reg = <寄存器的起始地址 地址的长度>;
---------------------------------------------------------------------------------------------------
设备名-gpios = <&gpio控制器的标签名 管脚编号 标志>; //gpio信息 (驱动需要操作GPIO输出高低电平)
---------------------------------------------------------------------------------------------------
interrupt-parent = <&中断控制器的标签名>;//gpio gic combiner(exynos4412)
interrupts = <1个或多个uint32的数字描述中断的信息>;// #interrupt-cells
interrupt-names = “名称”;
----------------------------------------------------------------------------------------------------
clocks = <&clock 时钟信号的ID>; clk_get , clk_enable ,clk_disable
clock-names = “名字”;
----------------------------------------------------------------------------------------------------
pinctrl-0 = <&描述gpio管脚功能的标签 &描述gpio管脚功能的标签>;//系统自动帮助我们设定为指定的功能模式
pinctrl-1 = <&描述gpio管脚功能的标签 &描述gpio管脚功能的标签>;
pinctrl-names = “default”,“other(随便)”;(第一个名字对应pinctrl-0,第二个对应pinctrl-1)
struct pinctrl * devm_pinctrl_get_select(struct device *dev, const char *name);
-----------------------------------------------------------------------------------------------------
自己定义的属性 = "值";
-----------------------------------------------------------------------------------------------------
status = "状态";//okay , disabled
};
*--------------------------------------------------------------------------------------------------------------
*属性(描述设备的信息)是最简单的键-值对,它的值可以为空或者是一个有效的数据,基本的数据类型如下
*(1)属性后面的值可以是一个字符串,如:
- a string-propery = “a string”
*(2)属性后面的值可以是多个32位的无符号整数,用尖括号限定
- cell-propery = <0xbeef 123 0xabcd1234>
*(3)属性后面的值可以多个二进制数据,用方括号限定
- binary-propery = [0x01 0x23 0x45 0x67]
- 注意:写的时候用十六进制来表示二进制
*(4)属性后面的值可以是多个不同形式的数据组合在一起,他们之间用逗号隔开
- mixed-propery = “a string”,[0x01 0x23 0x45 0x67],<0x12345678>
*(5)属性后面的值可以多个字符传,他们之间用逗号隔开
- string-list = “red fish”,“blue fish”;
*---------------------------------------------------------------------------------------------------------------
注意:
属性名可以任意,但是赋值的时候需要遵从设备树的语法原则,
通用的属性内核是自动解析的,自己的属性需要使用内核提供的设备树函数接口(linux/of.h)自己解析
必须知道的知识:
<1>这个节点Linux内核最终会对它进行解析,解析完成之后是一个结构体:
struct device_node 这个结构体中包含的就是这个节点的所有信息
(struct platform_device 它有记录)
<2>Linux内核在解析这个节点的时候,会根据节点的状态,判定是否添加到platform bus总线上。
如果是添加到platform bus总线上,就会构建一个platform_device结构体,并且会去匹配驱动
此时reg属性就会解析成IORESOURCE_MEM platform_get_resource
此时interrupts属性就会解析成IORESOURCE_IRQ
练习:
(1)描述LED2这个设备
led2@11000C40{
compatible = “fs4412-led”;
reg = <0x11000C40 8>;
------------------------------------------------
pin = <7>;
level = <1>;
mode = <1>;
------------------------------------------------
status = “okay”;
};
如果一个模块包括多个.c文件(如file1.c,file2.c),则应该以如下方式编写Makefile:
obj-m = modulename.o
modulename-objs := file1.o file2.o
(2)描述KEY2这个设备(描述中断信息)
key2{
compatible = “fs4412-key”;
interrupt-parent = <&gpx1>;
interrupts = <1 8>;
intrrupt-names = “key-interrupt”;
};
(3)描述ADC这个设备 (reg ,interrupt , clock)
adc@126C0000{
compatible = “exynos4412-adc”;
reg = <0x126C0000 0x20>;
interrupt-parent = <&combiner>;
interrupts = <10 3>;
intrrupt-names = “adc-interrupt”;
clocks = <&clock 326>;
clock-names = “adc-clock”;
status = “okay”
};