【北京迅为】《i.MX8MM嵌入式Linux开发指南》-第三篇 嵌入式Linux驱动开发篇-第五十三章 设备树下的platform驱动
i.MX8MM处理器采用了先进的14LPCFinFET工艺,提供更快的速度和更高的电源效率;四核Cortex-A53,单核Cortex-M4,多达五个内核 ,主频高达1.8GHz,2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT、4G模块、CAN、RS485等接口一应俱全。H264、VP8视频硬编码,H.264、H.265、VP8、VP9视频硬解码,并提供相关历程,支持8路PDM接口、5路SAI接口、2路Speaker。系统支持Android9.0(支持获取root限)Linux4.14.78+Qt5.10.1、Yocto、Ubuntu20、Debian9系统。适用于智能充电桩,物联网,工业控制,医疗,智能交通等,可用于任何通用工业和物联网应用、
【公众号】迅为电子
【粉丝群】258811263
第五十三章 设备树下的platform驱动
本章导读
本章节我们来学习设备树下的platform驱动,之前我们学习了linux下的平台总线模型但是我们是使用传统的方法进行学习。什么是传统的方法呢?传统的方法就是把我们的驱动分为两个部分,第一部分是device.c,第二部分是driver.c,当device.c和driver.c匹配成功以后,进入probe函数后就可以获取硬件资源了,然后可以注册杂项设备,注册字符设备。
我们现在使用的是设备树,设备树相当于之前学习的device.c。之前传统的方法是使用“name”进行匹配的,我们使用设备树要怎么和我们的driver进行匹配呢?之前讲设备树语法的时候我们学习过compitable属性,那么这个compitable属性就是和driver.c匹配的。我们打开设备树文件,在设备树的根节点下,也有一个compitable属性,比如说内核在iTOP-3399开发板上面可以运行,那么这个内核放到4412开发板,imx6Q开发板上可以运行吗?答案肯定是不可以的,因为内核运行之前会进行一次匹配,内核在运行之前会检查下这个板子是否支持运行,那么他是根据根节点下的compitable属性来进行判断的。
53.1章节在前面52章节的基础上修改设备树文件,并查看是否生成设备节点。
53.2章节编写了驱动程序,该程序是设备树下的Platform驱动,匹配成功后在probe函数中获取到硬件资源,映射寄存器物理地址等等。
本章内容对应视频讲解链接(在线观看):
设备树下的platform总线 → https://www.bilibili.com/video/BV1Vy4y1B7ta?p=28
程序源码在网盘资料“iTOP-i.MX8MM开发板\02-i.MX8MM开发板网盘资料汇总(不含光盘内容)\嵌入式Linux开发指南(iTOP-i.MX8MM)手册配套资料\2.驱动程序例程\011-设备树下的platform驱动”路径下。
53.1 设备树下的Platform设备
Linux 系统中 platform 平台框架包括总线、设备和驱动,其中总线不用我们去操心,Linux 内核中会自动管理,我们只需要关心设备和驱动如何实现。在不支持设备树的内核中,我们需要分别实现 platform_device和 platform_driver,其中 platform_device 是在平台文件中实现的。在支持设备树的内核中,我们就不用实现 platform_device 了,而是在设备树文件中添加设备信息。下面看一下在设备树文件中添加设备信息。
在之前关于设备树语法的章节中,我们学习了如何在根节点“/”下去添加一个设备节点信息。其中最重要的就是 compatible 属性值,compatible 属性使用来和驱动进行匹配的。下面是本实验用到的设备的设备节点:
在编写驱动以前,有一个地方需要注意一下,我们在加载driver.ko之前,一定要在开发板上已经成功地添加了test的节点,你可以在linux系统里面查看到你添加的节点,查看节点方法请参考51.1 查看设备树节点方法章节,添加自定义节点请参考51.2添加自定义节点章节。查看到test节点的comtabile属性的值为test1234,如下图所示:
53.2 实验程序编写
53.2.1 Platform驱动程序
程序源码在网盘资料“iTOP-i.MX8MM开发板\02-i.MX8MM开发板网盘资料汇总(不含光盘内容)\嵌入式Linux开发指南(iTOP-i.MX8MM)手册配套资料\2.驱动程序例程\011-设备树下的platform驱动\001”路径下。
我们在Ubuntu的/home/topeet/imx8mm/11/001目录下新建driver.c文件,修改代码为如下所示
/** @Author: topeet* @Description: 实现设备树下Platform驱动匹配进入probe函数*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_address.h>/*** @description: platform 驱动的 probe 函数,当驱动与设备匹配以后此函数就会执行* @param {*}pdev : platform 设备* @return {*}0,成功;其他负值,失败*/
int led_probe(struct platform_device *pdev)
{ //匹配成功以后,进入到probe函数printk("led_probe\n");return 0;
}
int led_remove(struct platform_device *pdev)
{printk("led_remove\n");return 0;
}
const struct platform_device_id led_idtable = {.name = "led_test",
};
const struct of_device_id of_match_table_test[] = {{.compatible = "test1234"},{},
};
struct platform_driver led_driver = {//3. 在led_driver结构体中完成了led_probe和led_remove.probe = led_probe,.remove = led_remove,.driver = {.owner = THIS_MODULE,.name = "led_test",.of_match_table = of_match_table_test //接下来我们改一下驱动,让他来匹配设备树里面test的节点},.id_table = &led_idtable //4 .id_table的优先级要比driver.name的优先级要高,优先与.id_table进行匹配
};static int led_driver_init(void)
{// 1.我们看驱动文件要从init函数开始看int ret = 0;//2. 在init函数里面注册了platform_driverret = platform_driver_register(&led_driver);if (ret < 0){printk("platform_driver_register error \n");}printk("platform_driver_register ok \n");return 0;
}static void led_driver_exit(void)
{platform_driver_unregister(&led_driver);printk("goodbye! \n");
}
module_init(led_driver_init);
module_exit(led_driver_exit);MODULE_LICENSE("GPL");
保存driver.c文件,编译driver.c为驱动模块,如下图所示:
驱动编译完,我们通过nfs将编译好的驱动程序加载模块。我们进入共享目录,加载刚刚编译好的driver.ko,如下图所示:
insmod driver.ko
如上图所示,已经匹配成功进入到probe函数中。如果没有进入probe函数,可能出现匹配不成功的原因是1 device或者设备树根本没有加到我们系统里面2 名字不一样导致匹配不成功。
53.2.2 获取资源
程序源码在网盘资料“iTOP-i.MX8MM开发板\02-i.MX8MM开发板网盘资料汇总(不含光盘内容)\嵌入式Linux开发指南(iTOP-i.MX8MM)手册配套资料\2.驱动程序例程\011-设备树下的platform驱动\002”路径下。
我们进入了probe函数,可以在probe函数中获取资源,如下所示:
int led_probe(struct platform_device *pdev)
{ //匹配成功以后,进入到probe函数printk("led_probe\n");
/*********************方法一:直接获取节点**************************/printk("node name is %s\n",pdev->dev.of_node->name);return 0;
}
编译驱动,然后加载驱动后,如下图所示:
如上图所示,加载驱动以后,设备树上的节点和驱动程序匹配成功,进入了probe函数,并打印了节点的名字。
我们也可以用第52章学习过的of操作函数来获取我们的设备资源,修改driver.c为如下所示:
int led_probe(struct platform_device *pdev)
{ //匹配成功以后,进入到probe函数printk("led_probe\n");/*********************方法一:直接获取节点**************************/// printk("node name is %s\n",pdev->dev.of_node->name);/*********************方法二:通过函数获取硬件资源**************************///获得设备节点test_device_node = of_find_node_by_path("/test"); //获得设备节点if (test_device_node == NULL){printk("of_find_node_by_path is error \n");return -1;}//获取reg属性ret = of_property_read_u32_array(pdev->dev.of_node, "reg", out_values, 4);if (ret < 0){printk("of_property_read_u32_array is error \n");return -1;}printk("out_values[0] is 0x%08x\n", out_values[0]);printk("out_values[1] is 0x%08x\n", out_values[1]);printk("out_values[2] is 0x%08x\n", out_values[2]);printk("out_values[3] is 0x%08x\n", out_values[3]);return 0;
}
编译驱动,然后加载驱动后,如下图所示:
如上图所示,我们已经成功地获得设备树里面的reg属性。
53.2.3 获取节点属性
程序源码在网盘资料“iTOP-i.MX8MM开发板\02-i.MX8MM开发板网盘资料汇总(不含光盘内容)\嵌入式Linux开发指南(iTOP-i.MX8MM)手册配套资料\2.驱动程序例程\011-设备树下的platform驱动\003”路径下。
我们修改driver.c如下所示:
int led_probe(struct platform_device *pdev)
{ //匹配成功以后,进入到probe函数printk("led_probe\n");/*********************方法一:直接获取节点**************************/// printk("node name is %s\n",pdev->dev.of_node->name);/*********************方法二:通过函数获取硬件资源**************************///获得设备节点// test_device_node = of_find_node_by_path("/test"); //获得设备节点// if (test_device_node == NULL)// {// printk("of_find_node_by_path is error \n");// return -1;// }//获取reg属性ret = of_property_read_u32_array(pdev->dev.of_node, "reg", out_values, 4);if (ret < 0){printk("of_property_read_u32_array is error \n");return -1;}printk("out_values[0] is 0x%08x\n", out_values[0]);printk("out_values[1] is 0x%08x\n", out_values[1]);printk("out_values[2] is 0x%08x\n", out_values[2]);printk("out_values[3] is 0x%08x\n", out_values[3]);return 0;
}
编译驱动,然后加载驱动后,如下图所示:
如上图所示,可以直接通过节点获取到reg属性的值。
53.2.4 映射物理地址
程序源码在网盘资料“iTOP-i.MX8MM开发板\02-i.MX8MM开发板网盘资料汇总(不含光盘内容)\嵌入式Linux开发指南(iTOP-i.MX8MM)手册配套资料\2.驱动程序例程\011-设备树下的platform驱动\004”路径下。
现在我们已经拿到了寄存器的地址,接下来可以注册杂项设备或者字符设备,我们先将获取到的物理地址映射为虚拟地址,修改driver.c代码如下:
int led_probe(struct platform_device *pdev)
{ //匹配成功以后,进入到probe函数printk("led_probe\n");/*********************方法一:直接获取节点**************************/// printk("node name is %s\n",pdev->dev.of_node->name);/*********************方法二:通过函数获取硬件资源**************************///获得设备节点// test_device_node = of_find_node_by_path("/test"); //获得设备节点// if (test_device_node == NULL)// {// printk("of_find_node_by_path is error \n");// return -1;// }//获取reg属性ret = of_property_read_u32_array(pdev->dev.of_node, "reg", out_values, 4);if (ret < 0){printk("of_property_read_u32_array is error \n");return -1;}printk("out_values[0] is 0x%08x\n", out_values[0]);printk("out_values[1] is 0x%08x\n", out_values[1]);printk("out_values[2] is 0x%08x\n", out_values[2]);printk("out_values[3] is 0x%08x\n", out_values[3]);//映射GPIO资源vir_gpio1_io13 = of_iomap(pdev->dev.of_node, 0);if (vir_gpio1_io13 == NULL){printk("GPIO1_IO13 iomap is error \n");return EBUSY;}printk("GPIO1_IO13 iomap is ok \n");vir_gpio1_io13_gdir = of_iomap(pdev->dev.of_node, 0);if (vir_gpio1_io13_gdir == NULL){printk("GPIO1_IO13_GDIR iomap is error \n");return EBUSY;}printk("GPIO1_IO13_GDIR iomap is ok \n");return 0;
}
编译驱动,然后加载驱动后,如下图所示:
如上图所示,物理地址已经映射为虚拟地址,接下来可以注册字符设备和杂项设备,流程和我们前面学习到的内容是一模一样的。
相关文章:

【北京迅为】《i.MX8MM嵌入式Linux开发指南》-第三篇 嵌入式Linux驱动开发篇-第五十三章 设备树下的platform驱动
i.MX8MM处理器采用了先进的14LPCFinFET工艺,提供更快的速度和更高的电源效率;四核Cortex-A53,单核Cortex-M4,多达五个内核 ,主频高达1.8GHz,2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT…...
Java正则表达式判断有无特殊字符
//^代表否定,匹配除了数字、字母、下划线的特殊字符。 private static final String SPECIAL_CHAR_PATTERN "[^a-zA-Z0-9_]"; Pattern pattern Pattern.compile(SPECIAL_CHAR_PATTERN); Matcher matcher pattern.matcher(userAccount); // 如果 find(…...
使用Java和Spring AMQP构建消息驱动应用
使用Java和Spring AMQP构建消息驱动应用 大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿! 消息驱动应用程序在现代系统架构中扮演着重要角色,特别是在处理高并发和异步任务时。Spring AMQ…...
【NLP】提升文本生成多样性的实用方法
比如用T5模型,训练数据是inputText-outputText格式,预测时do_sample=False # 预测代码from transformers import TFAutoModelForSeq2SeqLM from transformers import AutoTokenizercheckpoint_local = "./path/" tokenizer = AutoTokenizer.from_pretrained(check…...

鸿蒙(HarmonyOS)下拉选择控件
一、操作环境 操作系统: Windows 11 专业版、IDE:DevEco Studio 3.1.1 Release、SDK:HarmonyOS 3.1.0(API 9) 二、效果图 三、代码 SelectPVComponent.ets Component export default struct SelectPVComponent {Link selection: SelectOption[]priva…...
Java类加载器实现机制详细笔记
1. 类加载器的基本概念 类加载器(ClassLoader):在Java中,类加载器负责将Java类动态加载到JVM中。它是实现动态类加载机制的核心组件,对于开发复杂应用程序(如插件系统、模块化设计等)至关重要。…...

Git之repo sync -l与repo forall -c git checkout用法区别(四十九)
简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒…...
【公式解释】《系统论》《控制论》《信息论》的共同重构:探索核心公式与深度解析
《系统论》《控制论》《信息论》的共同重构:探索核心公式与深度解析 关键词:系统论、控制论、信息论、状态空间方程、系统矩阵。 Keywords: System theory, Control theory, Information theory, State-space equations, System matrices. 核心公式与三论共同之处 在系统…...

电脑格式化好还是恢复出厂设置好?
电脑格式化好还是恢复出厂设置好?使用电脑的过程中,系统问题、病毒感染、性能下降等原因可能会导致我们考虑对电脑进行大规模的清理和恢复操作。本文将详细探讨电脑格式化和恢复出厂设置的区别、优缺点,以及不同场景选择哪种方法合适。 选择电…...

使用 Windows 应用程序 SDK 构建下一代应用程序
微软面临的最大问题之一是如何让 Windows 再次成为吸引开发者的平台。无论用户使用什么设备和操作系统,都可以很容易地将 Web 前端放在支持桌面和移动用户的云原生应用程序上。 我们处在一个奇怪的境地,唯一能利用最新 PC 硬件的应用程序是 Office、Phot…...
可消费的媒体类型和可生成的媒体类型
可消费的媒体类型和可生成的媒体类型 在 Spring MVC 中,“可消费的媒体类型”和“可生成的媒体类型”是两个重要的概念,用于控制控制器方法处理和返回的内容类型。它们分别通过 consumes 和 produces 属性来指定。下面是它们的详细区别: 可…...
C++中指针与迭代器的区别
C中的迭代器和指针都是用于访问和操作内存中的数据结构的机制,但它们在使用方式和功能上有一些关键的区别。 #mermaid-svg-23bevhEih3Ch4ucl {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-23bevhEih3Ch…...

若依框架 : 生成代码
6.生成代码 6.1.配置生成设置 ruoyi-generator -> src -> main -> resources -> generator.yml 由于 案例中 表都有 前缀 为 tta_ , 这里设置去掉 6.2.生成代码 6.2.1.导入数据库中的表 6.2.2.修改设置 6.2.2.1.设置生成信息 点击 编辑 -> 生成信息 特别…...
RTMP协议解析
RTMP(Real Time Message Protocol)是一种由Adobe公司提出的应用层协议,主要用于实时音视频数据的传输。RTMP协议的主要有以下特点: 1. 多路复用:RTMP允许多个音视频数据流在单个TCP连接上进行传输。 2. 分包传输&…...
禁忌搜索算法(Tabu Search,TS)及其Python和MATLAB实现
禁忌搜索算法是一种现代启发式搜索方案,主要用于解决组合优化问题。该算法由George F. Lugeral于1986年首次提出,旨在增强局部搜索算法的性能,避免其陷入局部最优解。禁忌搜索利用一个称为“禁忌表”的数据结构,记住最近访问的解决…...
Meta发布Llama 3.1 405B模型:开源与闭源模型之争的新篇章
引言 在人工智能领域,开源与闭源模型之争一直是热点话题。近日,Meta发布了最新的Llama 3.1 405B模型,以其强大的性能和庞大的参数规模,成为了开源模型中的佼佼者。本文将详细介绍Llama 3.1 405B模型的性能、功能及其在开源领域的…...
Linux网络协议深度解析:从IP到TCP/IP堆栈
Linux网络协议深度解析是一个复杂而详细的主题,它涵盖了从基本的数据包传输到复杂的协议交互。以下是对"Linux网络协议深度解析:从IP到TCP/IP堆栈"这一主题的简要解析: IP协议(Internet Protocol) •作用:…...

AWS DMS MySQL为源端,如何在更改分区的时候避免报错
问题描述: 文档[1]中描述MySQL compatible Databases作为DMS任务的源端,不支持MySQL 分区表的 DDL 更改。 在源端MySQL进行分区添加时,日志里会出现如下报错: [SOURCE_CAPTURE ]W: Cannot change partition in table members…...
Java从基础到高级特性及应用
Java,作为一门历史悠久且广泛应用的编程语言,自1995年问世以来,便以其跨平台性、面向对象、自动内存管理等特点,在软件开发领域占据了举足轻重的地位。从桌面应用到企业级系统,从移动开发到云计算服务,Java…...

JavaScript(17)——事件监听
什么是事件? 事件是在编程时系统内发生的动作或发生的事情,比如用户在网页上单击一个按钮 什么是事件监听? 就是让程序检测是否有事件产生,一旦有事件触发,就立刻调用一个函数做出响应,也称为绑定事件或…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型
摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...

第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...
土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等
🔍 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术,可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势,还能有效评价重大生态工程…...
Matlab | matlab常用命令总结
常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...
今日科技热点速览
🔥 今日科技热点速览 🎮 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售,主打更强图形性能与沉浸式体验,支持多模态交互,受到全球玩家热捧 。 🤖 人工智能持续突破 DeepSeek-R1&…...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...
.Net Framework 4/C# 关键字(非常用,持续更新...)
一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...
安卓基础(aar)
重新设置java21的环境,临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的: MyApp/ ├── app/ …...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...

打手机检测算法AI智能分析网关V4守护公共/工业/医疗等多场景安全应用
一、方案背景 在现代生产与生活场景中,如工厂高危作业区、医院手术室、公共场景等,人员违规打手机的行为潜藏着巨大风险。传统依靠人工巡查的监管方式,存在效率低、覆盖面不足、判断主观性强等问题,难以满足对人员打手机行为精…...