1、dts:device tree source 设备树源码
硬件的相应信息都会写在.dts为后缀的文件中,每一款硬件可以单独写一xxxx.dts,一般在Linux源码中存在大量的dts文件,对于arm架构可以在arch/arm/boot/dts找到相应的dts,一个dts文件对应一个ARM的machie。
2、dtsi:类似于dts。是dts的头文件,dts中的配置会覆盖dtsi中的配置。非必要的我们一般不去改这个,这是一种板子的通用文件。dts就是细分一种板子的几个版本这种。
3、dtc是编译dts的工具,可以在Ubuntu系统上通过指令apt-get install device-tree-compiler安装dtc工具,不过在内核源码scripts/dtc路径下已经包含了dtc工具。直接用就可以。
4、dtb(Device Tree Blob),dts经过dtc编译之后会得到dtb文件,dtb通过Bootloader引导程序加载到内核。所以Bootloader需要支持设备树才行;Kernel也需要加入设备树的支持;
dts一般放在,kernel/arh/arm*/boot/dts/xxxx/里面(xxx是你自己板子的牌子那种,比如瑞芯微就是rockchip),在这里面有很多的dts文件和dtsi文件。我们需要找到自己对应的板子的dts和dtsi文件。
找到过后我们就能看到很多源码。
我们打开一个看看
/*第一个pdm_mic_array,是他的别名,第二个pdm-mic-array是他的真名,有时真名比较长,所以会采用别名方便调用
*比如:vcc_camera: vcc-camera-regulator {}
*/
pdm_mic_array: pdm-mic-array {
/*状态,打开或者关闭*/
status = "disabled";
/*属性,可以理解设备注册的名字,需要和驱动注册的名字对应*/
compatible = "simple-audio-card";
/*也是他的属性,瑞芯微的,设备名字是pdm-mic-array*/
simple-audio-card,name = "rockchip,pdm-mic-array";
/*这两个都是声卡连接cpu的编解码器*/
simple-audio-card,cpu {
sound-dai = <&pdm>;
};
simple-audio-card,codec {
sound-dai = <&pdmics>;
};
};
还有这样的
/*子节点名称*/
wd_tpl5010 {
compatible = "wd-tpl5010";
/*这个好像都是default,应该是pinctrl子系统里面的东西*/
pinctrl-names = "default";
/*用pinctrl子系统去控制这个gpiod的模式(类似于浮空、上拉、下拉这种)*/
pinctrl-0 = <&gpio4_b6>;
/*配置gpio的状态*/
tpl-wake = <&gpio0 RK_PA5 GPIO_ACTIVE_LOW>;
tpl-done = <&gpio3 RK_PC5 GPIO_ACTIVE_HIGH>;
};
在dts文件的上端,一般会有一个这个代码,这不是注释,这是dts的版本那种
/dts-v1/;
/ 表示这是根节点,仔细看看源码,根结点都是顶行写的,而根节点的下面的节点会用一个TAB来表示,同样的下面的节点也会继续TAB,这样用tab就可以看出各个节点的关系了。
/{
child1{
child2{
child3{
.......
};
};
};
};
zwave_ctl {
/* qls_cnt_zwave 这个就是你去匹配对应驱动代码的*/
compatible = "Pine,qls_cnt_zwave";
gpios = <&gpio3 RK_PB6 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&gpio3_b6>;
};
用sourceinsight的可以直接搜索
我用的vim,因为ubuntu用sourceinsight很难受
drivers/misc/tab07_rk68_qls_cnt_zware.c:33:struct qls_cnt_zwave_drvdata {
drivers/misc/tab07_rk68_qls_cnt_zware.c:39:static const struct of_device_id qls_cnt_zwave_match[] = {
drivers/misc/tab07_rk68_qls_cnt_zware.c:40: { .compatible = "Pine,qls_cnt_zwave", .data = NULL},
drivers/misc/tab07_rk68_qls_cnt_zware.c:43:MODULE_DEVICE_TABLE(of, qls_cnt_zwave_match);
..........
我们马上就在驱动里面找到相关代码,打开他(你打开的不一定正确,所以有时需要多次打开)
果然我们就在里面找到了对应的代码
static struct platform_driver pine_qls_cnt_zwave_driver = {
/*驱动的注册,注销、名字*/
.probe = qls_cnt_zwave_probe,
.remove = qls_cnt_zwave_remove,
.driver = {
.name = "qls_cnt_zwave",
.owner = THIS_MODULE,
/*匹配函数,去匹配设备和驱动的代码*/
.of_match_table = qls_cnt_zwave_match,
#ifdef CONFIG_PM
.pm = &qls_cnt_zwave_pm_ops,
#endif
同样的方法,我们可以找到相关的驱动和dts的关系。
阅读驱动的代码建议从下往上看,因为驱动的代码重要的东西都是放在下面的。
可以想象一条总线上有两个链表,一个是设备链表,一个是驱动链表。每一个节点就是自己的设备或者驱动的名字,match函数就是遍历链表,然后把两个链表的节点名字用来作比对,如果对上了,那么就证明我们的设备是有驱动的,如果没有对上,那么就证明我们的设备是没有驱动的,取要去写驱动。
每一个设备都有一个驱动,不然设备没法工作,但是不是每一驱动都有设备。设备可以少,但是驱动不能少。
在dts里面我们会看到这样的一种代码
&dfi {
status = "disabled";
........
};
这种一个取地址符加上一个名字这种,这是追加说明,是因为dts不止用在一个开发板上,那么对应的驱动或者总线就会有不同的需求,有的要,有的不要,为了不去找之前是什么状态,我们直接追加一个我们需要的属性就好,可以追加状态开或者关,也可以追加子节点,类似下面的代码。
&i2c0 {
status = "okay";
vdd_cpu: tcs4525@1c {
compatible = "tcs,tcs452x";
reg = <0x1c>;
vin-supply = <&vcc5v0_sys>;
regulator-compatible = "fan53555-reg";
regulator-name = "vdd_cpu";
regulator-min-microvolt = <712500>;
regulator-max-microvolt = <1390000>;
regulator-init-microvolt = <900000>;
regulator-ramp-delay = <2300>;
fcs,suspend-voltage-selector = <1>;
regulator-boot-on;
regulator-always-on;
regulator-state-mem {
regulator-off-in-suspend;
};
};
rk809: pmic@20 {
compatible = "rockchip,rk809";
reg = <0x20>;
interrupt-parent = <&gpio0>;
interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
....
...
};
};