自学内容网 自学内容网

Linux驱动开发——(一)设备树的基本属性及其应用

目录

一、常见基本属性

1.1 compatible属性

1.2 status属性

1.3 reg属性

1.4 #address-cells属性和#size-cells属性

二、基本属性在设备树的表现

三、基本属性在驱动代码的表现

3.1 驱动代码

3.2 驱动代码中的OF函数

3.2.1 of_find_node_by_path

3.2.2 of_find_property 

3.2.3 of_property_read_string 

3.2.4 of_property_read_u32_array

四、平台实验测试


一、常见基本属性

常见的基本属性有compatible、status、reg、#address-cells#size-cells

1.1 compatible属性

compatible属性的值是一个字符串列表,将设备和驱动绑定起来。compatible属性的值格式如下所示:

"manufacturer,model"

manufacturer:厂商。

model:模块对应的驱动名字。

 比如:

compatible = "fsl,imx6ul-evk-wm8960","fsl,imx-audio-wm8960";

其中”fsl“表示厂商是飞思卡尔,“imx6ul-evk-wm8960”和 “imx-audio-wm8960”表示驱动模块名字。 这个设备首先使用第一个兼容值“imx6ul-evk-wm8960”在Linux内核里面查找,看看能不能找到与之匹配的驱动文件,如果没有找到的话就使用第二个兼容值“imx-audio-wm8960”查。

1.2 status属性

status属性值也是字符串,是和设备状态有关的。

描述
”okay“表明设备是可操作的。
"disabled"表明设备当前是不可操作的,但是在未来可以变为可操作的。
”fail”表明设备不可操作,设备检测到了一系列的错误,而且设备也不大可能变得可操作。
”fail-sss“含义和“fail”相同,后面的 sss部分是检测到的错误内容。
1.3 reg属性

reg属性的值一般是 (address length)对。 reg属性一般用于描述设备地址空间资源信息,一般都是某个外设的寄存器地址范围信息。

1.4 #address-cells属性和#size-cells属性

这两个属性的值都是无符号32位整形, #address-cells和 #size-cells这两个属性可以用在任何拥有子节点的设备中,用于描述子节点的地址信息。

#address-cells属性值决定了子节点reg属性中地址信息所占用的字长(32位),#size-cells属性值决定了子节点reg属性中长度信息所占的字长(32位)。


二、基本属性在设备树的表现

以I.MU6ULL为例,打开设备树dts文件,在根节点“/”下创建一个名为“alphaled”的子节点。

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 */ 
};

第2、3行,属性#address-cells#size-cells都为1,表示reg属性中起始地址占用一个字长
(cell),地址长度也占用一个字长 (cell)。
第4行,属性compatbile设置alphaled节点兼容性为“atkalpha-led”。
第5行,属性status设置状态为“okay”。
第6~10行,属性reg设置了驱动里面所要使用的寄存器物理地址,比如第6行的“ 0X020C406C 0X04”表示 I.MX6ULL的 CCM_CCGR1寄存器,其中寄存器首地址为 0X020C406C,长度为4个字节。

然后重新编译设备树,使用新的设备树启动Linux。


三、基本属性在驱动代码的表现

3.1 驱动代码

驱动入口函数加入以下代码:

/* 获取设备树中的属性数据 */

/* 1、获取设备节点:alphaled */

dtsled.nd = of_find_node_by_path("/alphaled");

if(dtsled.nd == NULL) {

printk("alphaled node nost find!\r\n");

return -EINVAL;

} else {

printk("alphaled node find!\r\n");

}



/* 2、获取compatible属性内容 */

proper = of_find_property(dtsled.nd, "compatible", NULL);

if(proper == NULL) {

printk("compatible property find failed\r\n");

} else {

printk("compatible = %s\r\n", (char*)proper->value);

}



/* 3、获取status属性内容 */

ret = of_property_read_string(dtsled.nd, "status", &str);

if(ret < 0){

printk("status read failed!\r\n");

} else {

printk("status = %s\r\n",str);

}



/* 4、获取reg属性内容 */

ret = of_property_read_u32_array(dtsled.nd, "reg", regdata, 10);

if(ret < 0) {

printk("reg property read failed!\r\n");

} else {

u8 i = 0;

printk("reg data:\r\n");

for(i = 0; i < 10; i++)

printk("%#X ", regdata[i]);

printk("\r\n");

}
3.2 驱动代码中的OF函数
3.2.1 of_find_node_by_path

通过路径来查找指定的节点,函数原型如下:

inline struct device_node *of_find_node_by_path(const char *path)

path:带有全路径的节点名,可使用节点的别名。
返回值: 找到的节点,如果为 NULL表示查找失败。

3.2.2 of_find_property 

用于查找指定的属性compatible,函数原型如下:

property *of_find_property(const struct device_node *np, const char *name, int *lenp)

np:设备节点。
name:属性名字。
lenp:属性值的字节数
返回值: 找到的属性。

3.2.3 of_property_read_string 

用于读取属性中字符串值,函数原型如下:

int of_property_read_string(struct device_node *np, const char *propname, const char **out_string)

np:设备节点。
proname:要读取的属性名字。
out_string:读取到的字符串值。
返回值: 0,读取成功;负值,读取失败。

3.2.4 of_property_read_u32_array

读取属性中u32类型的数组数据,大多数的reg属性都是数组数据,可以使用该函数一次读取出reg属性中的所有数据。这该函数的原型如下:

int of_property_read_u32_array(const struct device_node *np, const char *propname, u32 *out_values, size_t sz)

np:设备节点。

proname: 要读取的属性名字。

out_value:读取到的数组值,分别为 u8、 u16、 u32和 u64。

sz:要读取的数组元素数量。

返回值: 0,读取成功;负值,读取失败,-EINVAL表示属性不存在,-ENODATA表示没有要读取的数据,-EOVERFLOW表示属性值列表太小。


四、平台实验测试

如图:

输出正确,实现成功。


原文地址:https://blog.csdn.net/weixin_61979510/article/details/137845314

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!