RK3568驱动指南|第七期-设备树-第65章 设备树下platform_device和platform_driver匹配实验

瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码,支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU,可用于轻量级人工智能应用。RK3568 支持安卓 11 和 linux 系统,主要面向物联网网关、NVR 存储、工控平板、工业检测、工控盒、卡拉 OK、云终端、车载中控等行业。

【公众号】迅为电子

【粉丝群】824412014(加群获取驱动文档+例程)

【视频观看】嵌入式学习之Linux驱动(第七期_设备树_全新升级)_基于RK3568

【购买链接】迅为RK3568开发板瑞芯微Linux安卓鸿蒙ARM核心板人工智能AI主板


第65章 设备树下platform_device和platform_driver匹配实验

在上一章节中我们学习了从device_node到platform_device的转换流程,转换完成之后操作系统才能够识别和管理设备,从而与platform_driver进行匹配,在本章将将会对设备树下platform_device和platform_driver的匹配进行讲解。

65.1 of_match_table

在前面平台总线相关章节的学习中,了解到只有platform_device结构体中的name 属性与platform_driver结构体中嵌套的driver结构体name属性或者id_table相同才能加载probe初始化函数。

而为了使设备树能够与驱动程序进行匹配,需要在platform_driver驱动程序中添加driver结构体的of_match_table 属性。这个属性是一个指向 const struct of_device_id 结构的指针,用于描述设备树节点和驱动程序之间的匹配规则。of_device_id 结构体定义在内核源码的"/include/linux/mod_devicetable.h"文件中,具体内容如下所示:

cpp 复制代码
struct of_device_id {
	char	name[32];
	char	type[32];
	char	compatible[128];
	const void *data;
};

struct of_device_id 结构体通常作为一个数组在驱动程序中定义,用于描述设备树节点和驱动程序之间的匹配规则。数组的最后一个元素必须是一个空的结构体,以标记数组的结束。

以下是一个示例,展示了如何在驱动程序中使用 struct of_device_id 进行设备树匹配:

cpp 复制代码
static const struct of_device_id my_driver_match[] = {
    { .compatible = "vendor,device-1" },
    { .compatible = "vendor,device-2" },
    { },
};

在上述示例中,my_driver_match 是一个 struct of_device_id 结构体数组。每个数组元素都包含了一个 compatible 字段,用于指定设备树节点的兼容性字符串。驱动程序将根据这些兼容性字符串与设备树中的节点进行匹配。

65.2实验程序编写

本次实验的要求使用设备树描述下面的内存资源:
内存资源:

起始地址:0xFDD60000

结束地址:0xFDD60004

然后编写对应的platform_driver驱动程序,要求跟上述内存资源所创建的节点进行匹配,从而验证 上一小节讲解的of_match_table 属性。

65.2.1 设备树的编写

改完成的dts文件和编译完成的boot.img镜像对应的网盘路径为:iTOP-RK3568开发板【底板V1.7版本】\03_【iTOP-RK3568开发板】指南教程\02_Linux驱动配套资料\04_Linux驱动例程\54_devicetree_probe\dts。

首先来对rk3568的设备树结构进行以下介绍,根据sdk源码目录下的"device/rockchip/rk356x/BoardConfig-rk3568-evb1-ddr4-v10.mk"默认配置文件可以了解到编译的设备树为rk3568-evb1-ddr4-v10-linux.dts,设备树之间的包含关系如下表所示:

|--------|-------------------------------------------------------------------------------|-------------------|
| 顶层设备树 | rk3568-evb1-ddr4-v10-linux.dts ||
| 第二级设备树 | rk3568-evb1-ddr4-v10.dtsi | rk3568-linux.dtsi |
| 第三级设备树 | rk3568.dtsi rk3568-evb.dtsi topeet_screen_choose.dtsi topeet_rk3568_lcds.dtsi | |

rk3568-evb1-ddr4-v10-linux.dts是顶层设备树,为了便于理解我们之后在该设备树下进行节点的添加(当然这里也可以修改其他设备树),进入该设备树文件之后如下(图 65-1)所示:

图 65-1

然后将根据需求编写的设备树节点添加到rk3568-evb1-ddr4-v10-linux.dts中,要添加的内容如下所示:

cpp 复制代码
/{
    topeet{
        #address-cells = <1>;
        #size-cells = <1>;
        compatible = "simple-bus";

        myLed{
            compatible = "my devicetree";
            reg = <0xFDD60000 0x00000004>;
        };  
    };  
};       

为了避免#address-cells = <1>; 和 #size-cells = <1>;这两个属性改变根节点其他的节点的属性,所以在这里创建了一个topeet节点。在这个示例中,#address-cells 设置为 1表示地址使用一个32位的单元,#size-cells 也设置为 1 表示大小使用一个32位的单元。

第5行:将compatible属性设置为"simple-bus"用于表示 topeet 节点的兼容性,指明它是一个简单总线设备,在转换platform_device的过程中,会继续查找该节点的子节点。

第8行:myLed 节点下的compatible属性为"my devicetree",表明该节点将会被转换为platform_device。

第9行:这个属性用于描述 myLed 节点的寄存器信息。reg 属性的值 <0xFDD60000 0x00000004> 表示 myLed 设备的寄存器起始地址为 0xFDD60000,大小为 0x00000004。

添加完成如下所示:

图 205-2

保存退出之后,重新编译内核源码,编译完成之后将生成的boot.img烧写到开发板即可。

66.2.2 驱动程序的编写

本实验驱动对应的网盘路径为:iTOP-RK3568开发板【底板V1.7版本】\03_【iTOP-RK3568开发板】指南教程\02_Linux驱动配套资料\04_Linux驱动例程\54_devicetree_probe\module。

本小节驱动程序是由"第52章 注册platform驱动实验"程序修改而来,相较于源程序只是添加了of_match_table相关代码,用来与设备树节点进行匹配。

编写完成的platform_driver.c代码如下所示:

cpp 复制代码
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/mod_devicetable.h>
// 平台设备的初始化函数
static int my_platform_probe(struct platform_device *pdev)
{
    printk(KERN_INFO "my_platform_probe: Probing platform device\n");

    // 添加设备特定的操作
    // ...

    return 0;
}

// 平台设备的移除函数
static int my_platform_remove(struct platform_device *pdev)
{
    printk(KERN_INFO "my_platform_remove: Removing platform device\n");

    // 清理设备特定的操作
    // ...

    return 0;
}


const struct of_device_id of_match_table_id[]  = {
	{.compatible="my devicetree"},
};

// 定义平台驱动结构体
static struct platform_driver my_platform_driver = {
    .probe = my_platform_probe,
    .remove = my_platform_remove,
    .driver = {
        .name = "my_platform_device",
        .owner = THIS_MODULE,
		.of_match_table =  of_match_table_id,
    },
};

// 模块初始化函数
static int __init my_platform_driver_init(void)
{
    int ret;

    // 注册平台驱动
    ret = platform_driver_register(&my_platform_driver);
    if (ret) {
        printk(KERN_ERR "Failed to register platform driver\n");
        return ret;
    }

    printk(KERN_INFO "my_platform_driver: Platform driver initialized\n");

    return 0;
}

// 模块退出函数
static void __exit my_platform_driver_exit(void)
{
    // 注销平台驱动
    platform_driver_unregister(&my_platform_driver);

    printk(KERN_INFO "my_platform_driver: Platform driver exited\n");
}

module_init(my_platform_driver_init);
module_exit(my_platform_driver_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("topeet");

65.3 运行测试

65.3.1 编译驱动程序

在上一小节中的platform_driver.c代码同一目录下创建 Makefile 文件,Makefile 文件内容如下所示:

cpp 复制代码
export ARCH=arm64#设置平台架构
export CROSS_COMPILE=aarch64-linux-gnu-#交叉编译器前缀
obj-m += platform_driver.o    #此处要和你的驱动源文件同名
KDIR :=/home/topeet/Linux/linux_sdk/kernel    #这里是你的内核目录                                                                                                                            
PWD ?= $(shell pwd)
all:
    make -C $(KDIR) M=$(PWD) modules    #make操作
clean:
    make -C $(KDIR) M=$(PWD) clean    #make clean操作

对于Makefile的内容注释已在上图添加,保存退出之后,来到存放platform_driver.c和Makefile文件目录下,如下图(图65-1)所示:

图 65-3

然后使用命令"make"进行驱动的编译,编译完成如下图(图65-4)所示:

图 65-4

编译完生成platform_driver.ko目标文件,如下图(图65-5)所示:

图 65-5

至此驱动模块就编译成功了。

65.3.2 运行测试

在进行实验之前,首先要确保开发板烧写的是我们在65.2.1小节中编译出来的boot.img。开发板启动之后,首先进入到"/proc/device-tree"目录下,查看是否已经存在了topeet目录,如下图(图 65-6)所示:

图 65-6

只有在设备树节点编写正确的前提下,这里才会生成topeet目录,如果没有出现topeet目录就要回头检查看看了。

然后使用以下命令进行驱动模块的加载,如下图(图65-7)所示:

cpp 复制代码
insmod platform_driver.ko

可以看到成功打印了在probe函数中的打印,证明我们添加的设备树节点和platform_driver驱动匹配成功了。

然后使用以下命令进行驱动模块的卸载,如下图(图65-8)所示:

cpp 复制代码
rmmod platform_driver.ko

图 65-8

至此,设备树下platform_device和platform_driver匹配实验就完成了。


相关推荐
多吃蔬菜!!!1 小时前
vscode 搭建C/C++开发环境搭建(linux)
linux·c语言·c++
李李李li1 小时前
Ubuntu 22.04 安装tensorrt
linux·tensorrt
phoenix09813 小时前
Linux入门DAY29
linux·运维
入秋3 小时前
Linux服务器安装部署 Nginx、Redis、PostgreSQL、Docker
linux·前端
Mr. Cao code4 小时前
使用Tomcat Clustering和Redis Session Manager实现Session共享
java·linux·运维·redis·缓存·tomcat
zcz16071278214 小时前
Linux 网络命令大全
linux·运维·网络
the sun344 小时前
Reactor设计模式及其在epoll中的应用
linux·运维·服务器·c++
喜欢你,还有大家4 小时前
Linux笔记7——shell编程基础-1
linux·运维·笔记
运维成长记4 小时前
Top 100 Linux Interview Questions and Answers
linux·运维·服务器
人工智能训练师4 小时前
openEuler系统中如何将docker安装在指定目录
linux·运维·服务器·人工智能·ubuntu