设备树设备和平台设备的关系
平台总线会将name相同的device和driver进行匹配,执行driver中的probe
设备树描述的节点会生成对应的设备树device,我这里理解为设备树也向平台总线注册了device,可以在/sys/devices/platform/目录下看到
driver也可以通过平台总线和设备树中的节点设备进行匹配,执行probe,获取设备树中节点的参数,然后执行各种操作。
相当于之前的device的驱动代码部分由设备树来代替。
以设备树-平台总线方式注册驱动、获取设备树参数
思路步骤:
- 设备树中添加需要的节点,烧录进板卡
- 在设备中确认相关节点存在,确认compatible属性(在板卡命令行可以查看)
- 编写driver驱动代码
- 初始化platform_driver结构体:注意driver结构体成员中的of_match_table属性,因为依靠这个名字来和compatible匹配
- 编写platform_driver结构体中的probe函数
- 注册平台driver:使用platform_driver_register函数
- 在probe函数里使用of相关函数获取节点的参数
设备树中添加的节点:
taxue_leds:taxue_leds {
compatible = "taxue_leds";
gpios1 = <&gpl2 0 GPIO_ACTIVE_HIGH>;
gpios2 = <&gpk1 1 GPIO_ACTIVE_HIGH>;
status = "disabled";
};
&taxue_leds {
status = "okay";
};
查看板卡上的节点是否存在
cat /sys/devices/platform/taxue_leds/of_node/compatible
taxue_leds
driver代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/platform_device.h>
#include <linux/ioport.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#define DEVICE_NAME "taxue_leds"
struct device_node *led_node=NULL;
//probe函数,进入probe说明匹配到device
int drProbe(struct platform_device *dev){
int ret;
struct property *pro;
unsigned int gpioval[3];
printk("probe here\n");
led_node = of_find_node_by_path("/taxue_leds"); //从设备树路径获取节点
//或者
//led_node = dev->dev.of_node; //probe函数的形参就是匹配的设备指针
if(led_node == NULL){
printk("find node failed\n");
return -1;
}
pro = of_find_property(led_node, "compatible", NULL); //获取节点中的compatible属性
printk("compatible name = %s\n", pro->name);
printk("compatible value = %s\n", (char *)(pro->value));
printk("compatible len = %d\n", pro->length);
pro = of_find_property(led_node, "status", NULL);
printk("status name = %s\n", pro->name);
printk("status value = %s\n", (char *)(pro->value));
printk("status len = %d\n", pro->length);
ret = of_property_read_u32_array(led_node, "gpios2", gpioval, 3); //读取gpios2属性,该属性值是<>括起来的,所以数据类型是32位的数组
if(ret == 0){
printk("gpios2 value= %d\t%d\t%d\t\n", gpioval[0], gpioval[1], gpioval[2]);
}else{
printk("read gpios2 failed\n");
}
return 0;
}
int drRemove(struct platform_device *dev){
printk("driver remove\n");
return 0;
}
//match_table
static const struct of_device_id of_leds_match[] = {
{.compatible = DEVICE_NAME},
{},
};
static struct platform_driver pdrv = {
.probe = drProbe, //和设备匹配后会调用probe函数
.remove = drRemove,
.driver = {
.name = "DEVICE_NAME", //如果使用设备树中的设备,则不根据name匹配
.owner = THIS_MODULE,
.of_match_table = of_leds_match, //使用match_table进行匹配
},
};
static int driver_init_led(void){
int ret=0;
ret = platform_driver_register(&pdrv); //向平台注册driver
if(ret < 0){
printk("platform driver regist failed\n");
return -1;
}
return 0;
}
static void driver_exit_led(void){
platform_driver_unregister(&pdrv);
printk("platform driver exit!\n");
}
module_init(driver_init_led);
module_exit(driver_exit_led);
MODULE_LICENSE("Dual BSD/GPL"); //遵循BSD和GPL开源许可
MODULE_AUTHOR("TAXUE"); //模块作者
查看设备树中描述的节点是否存在
#在板卡上
ls /proc/device-tree/
#目录下有所有的节点信息
cat /sys/devices/platform/xxx/of_node/compatible
#xxx表示节点名,这里如果存在,表明节点已经成功注册设备