设备树-平台总线

设备树设备和平台设备的关系

平台总线会将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表示节点名,这里如果存在,表明节点已经成功注册设备
上一篇:Linux内核4.14版本——DMA Engine框架分析(6)-实战(测试dma驱动)


下一篇:linux(安卓)休眠后,printk保持打印