设备树
2022.5.22
小结:dtc是编译工具.dtb是dtc编译后的结果,dts是最后生成的设备树文件。
需要单独编译一个设备树文件,使用如下指令:
make imx6ull-alientek-emmc.dts
makefile中的文件
设备树语法
dts也有头文件,扩展名为.dtsi头文件,可以将一款soc其他所有的设备提取出来,作为一个通用的.dtsi文件。
dts是以斜杠‘/’开始。
左忠凯草绘设备树
设备树语法
在
设备树举例子:
从根节点/开始描述设备信息,在/根节点外,有&cpu主要的语句是对cpu这个节点进行追加。
设备树节点名称规范:
node-name@unit-address
IMX6ULL参考手册:
I2C4起始地址:
和对应设备树其实地址相同,这个地址是描述I2C外设的起始地址。
再举一个栗子,看uart:
对应相同
&后面的绝对地址都是外设寄存器的起始地址。但是不是绝对的,比如IIC设备。
这里箭头所指的保存的地址是mag3110设备的地址。
如果遇到特殊节点:
引用标签的目的是为了方便的访问节点,就不需要搞这么长的名字了。
比如以后访问iic2这个节点就方便很多了。
2022.5.22 P19
系统启动之后可以在根文件系统看到设备树节点信息。在/proc/device-tree
内核启动的时候,会解析设备树,然后在/proc/device-tree呈现出来。
修改并且编译设备树:
指定编译器编译设备树:
拷贝设备树到nfs下:
P20 2022.5.22
1、aliases
2、chosen节点,主要将bootargs环境变量值传递给linux作为命令行参数。
设备树中的标准属性
1、compatible属性
描述“兼容性”,非常重要的属性。
gpio_spi:reg由spi4来决定的。address-cells 和size-cells 影响的是子节点reg属性而不是本节点。
#address-cells = <1>; //表示地址
#size-cells = <0>; //表示地址大小
表示reg里面只有一个address-cell。
解释说明:
2022.5.23 根节点下compatible属性作用
类型是字符串,根节点下的compatible,内核启动的时候会检查是否支持该平台或者机器。不使用设备树的情况下,根据machine id来判断是否支持此机器。
使用设备树之后,不使用机器ID,而是使用根节点/下的compatible属性。
正是因为 字符串匹配 所以可以启动内核。
和设备树中的内容可以匹配。
of函数
1、驱动如何获取设备树中的信息。在驱动中使用of函数获取设备树属性内容。
2、驱动要获取设备树节点内容,首先要找到节点。
如何使用of函数获取设备信息。
P6.9左忠凯手撕代码
/**
*my first driver
*
*/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#define LED_MAJOR 200 //主设备号
#define LED_NAME "LED" //驱动名称
#define NEWCHRLED_NAME "newchrled"
#define NEWCHRLED_COUNT 1
struct newchrled_dev {
struct cdev cdev;
struct class *class;/*类:为了自动创建节点*/
struct device *device;/*设备:为了自动创建节点*/
dev_t devid; //设备号
int major; //主设备号
int minor; //次设备号
};
struct newchrled_dev newchrled; //led设备
#if 0
backlight {
compatible = "pwm-backlight";
pwms = <&pwm1 0 5000000>;
brightness-levels = <0 4 8 16 32 64 128 255>;
default-brightness-level = <7>;
status = "okay";
};
#endif
static int __init dtsof_init(void)
{
int ret = 0; //
/*1、找到backlight节点,/路径是:/backlight /*/
struct device_node *bl_nd = NULL;/*节点*/
struct property *comppro = NULL;
const char **str = NULL;
u32 def_value = 0;
/*内核动态申请内存*/
u32 *brival;
u32 elemsize = 0;
bl_nd = of_find_node_by_path("/backlight");
if (bl_nd == NULL){ /*失败*/
ret = -EINVAL;
goto fail_findnd;
}
/*2、获取属性*/
comppro = of_find_property(bl_nd,"compatible",NULL);
if (comppro == NULL){ /*失败*/
ret = -EINVAL;
goto fail_findpro;
}else{
printk("compatible = %s",(char*)comppro->value);
}
ret = of_property_read_string(bl_nd,"status",str);
if (ret < 0){
goto fail_rs;
}
/*3、获取数字属性值*/
ret = of_property_read_u32(bl_nd,"default-brightness-level",&def_value);
if (ret<0){
goto fail_read32;
}else{
printk("default-brightness-level = %d \r\n",def_value);
}
/*4、获取数组类型的属性*/
elemsize = of_property_count_elems_of_size(bl_nd,"brightness-levels",sizeof(u32));
if (elemsize<0){
ret = -ENAVAIL;
goto fail_readele;
}else{
printk("brightness-levels = %d \r\n",ret);
}
/*申请内存*/
brival = kmalloc(elemsize * sizeof(u32),GFP_KERNEL);
if(!brival){
ret = -EINVAL;
goto fail_mem;
}
/*获取数组*/
ret = of_property_read_u32_array(bl_nd,"brightness-levels",brival,elemsize);
if (ret<0){
ret = -EINVAL;
goto fail_read32array;
} else {
u8 i = 0;
for (i = 0; i < elemsize; i++){
printk("brightness-levels[%d] = %d \r\n",i,*(brival+i));
}
}
kfree(brival);
return 0;
fail_read32:
fail_findnd:
fail_findpro:
fail_rs:
fail_readele:
fail_mem:
fail_read32array:
return ret;
}
static void __exit dtsof_exit(void)
{
}
//模块加载函数
module_init(dtsof_init);
//模块卸载
module_exit(dtsof_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("qhy");
出了一点小问题,编译的驱动和加载的驱动不匹配,搞了不少时间,外加网络配置也出现一点问题。
设备树下的led驱动
设备节点最好添加到好区分的节点。添加到1级节点。
设备树添加如下信息。
/*qhy 2022.5.24*/
alphaled {
#address-cells = <1>;
#size-cells = <1>;
compatible = "atkalpha-led";
status = "okay";
reg = < 0X020C406C 0X04 /* CCM_CCGR1_BASE */
0X020E0068 0X04 /* SW_MUX_GPIO1_IO03_BASE */
0X020E02F4 0X04 /* SW_PAD_GPIO1_IO03_BASE */
0X0209C000 0X04 /* GPIO1_DR_BASE */
0X0209C004 0X04 >; /* GPIO1_GDIR_BASE */
};
复制设备树到tftp目录下
cp arch/arm/boot/dts/imx6ull-alientek-emmc.dtb /home/alientek/linux/tftp/ -f
P25 左忠凯手撕代码