嵌入式linux驱动框架 I2C系统驱动程序模型分析
引言:在嵌入式 Linux 系统中,I2C(Inter-Integrated Circuit)是一种常用的通信协议,用于连接低速设备(如传感器、显示器、存储器等)与主控制器。I2C 系统驱动程序模型通过层次化的设计,使得 I2C 总线设备和驱动程序能够高效、灵活地进行通信和管理。
本分析旨在详细介绍 I2C 驱动程序框架,重点分析其核心组成部分,如
i2c_driver和i2c_client,以及 I2C 总线、设备和驱动程序的交互关系。
目录
1. I2C驱动程序的层次
3. I2C总线-设备-驱动模型
2.1 i2c_driver
2.2 i2c_client
1. I2C驱动程序的层次

I2C Core就是I2C核心层,它的作用:
-
提供统一的访问函数,比如i2c_transfer、i2c_smbus_xfer等
-
实现
I2C总线-设备-驱动模型,管理:I2C设备(i2c_client)、I2C设备驱动(i2c_driver)、I2C控制器(i2c_adapter)
上述内容也是我们之前讲过的,想深度了解也可以回顾之前的文章学习。
2. I2C总线-设备-驱动模型

2.1 i2c_driver
i2c_driver表明能支持哪些设备:
-
使用of_match_table来判断
-
设备树中,某个I2C控制器节点下可以创建I2C设备的节点
-
如果I2C设备节点的compatible属性跟of_match_table的某项兼容,则匹配成功
-
-
i2c_client.name跟某个of_match_table[i].compatible值相同,则匹配成功
-
-
使用id_table来判断
-
i2c_client.name跟某个id_table[i].name值相同,则匹配成功
-
i2c_driver跟i2c_client匹配成功后,就调用i2c_driver.probe函数。


可以观察上述的代码内容,也就是通过match来实现配对的。


上述我们任意拿一个IIC设备当例子,我们也可以看出之前分析的匹配结构。
2.2 i2c_client
其次就是这个结构体,是非常重要的,如下所示:



之前位于驱动屏的IIC驱动一文也讲过,重点是这个设备树会自动解析成I2C设备,
&i2c1 {status = "okay";ts@5d {compatible = "goodix,gt9xx";reg = <0x5d>;tp-size = <89>;max-x = <1280>;max-y = <800>;touch-gpio = <&gpio1 RK_PA0 IRQ_TYPE_LEVEL_LOW>;//复位引脚reset-gpio = <&gpio1 RK_PA1 GPIO_ACTIVE_LOW>;};
};
上述代码就是在 Linux 内核中,I2C_client 是用来表示一个通过 I2C 总线连接的设备的结构体。设备树描述了硬件设备的信息,而 I2C_client 是内核中用于管理这些设备的关键数据结构。当设备树加载时,内核会解析其中的硬件描述,并与相应的驱动程序进行匹配,自动生成并管理 I2C_client 结构体。
详细解释:
-
设备树与
I2C_client:在你的设备树片段中,ts@5d节点描述了一个 I2C 设备,并且设置了设备的 I2C 地址(reg = <0x5d>)。当 Linux 内核启动时,它会读取设备树并识别出这个 I2C 设备(ts@5d)。内核会根据这个设备树节点生成一个I2C_client结构体。 -
I2C_driver和匹配:内核通过设备树中的compatible字段(在这个例子中是goodix,gt9xx)来选择相应的驱动程序。在这种情况下,内核会找到与goodix,gt9xx匹配的 I2C 驱动(通常是goodix_gt9xx驱动),然后由内核调用该驱动的probe()函数进行设备初始化。 -
设备树与
I2C_client关联:I2C_driver中的probe()函数会接收到一个I2C_client参数,这个参数就是内核在启动时为该设备(ts@5d)生成的I2C_client结构体。在probe()函数中,你可以获取设备的详细信息,并使用该结构体进行设备的进一步操作。 -
I2C_client的作用:I2C_client结构体包含了与 I2C 设备相关的信息,如设备的 I2C 地址、设备的父设备(I2C 控制器)、设备的驱动程序等。通过这个结构体,驱动可以与硬件进行交互。
过程简述:
- 内核启动时解析设备树,发现
ts@5d节点,并识别出该设备是通过 I2C 总线连接的设备。 - 内核根据
compatible = "goodix,gt9xx"字段,匹配到相应的驱动程序(例如goodix_gt9xx)。 - 驱动的
probe()函数被调用,并且设备信息被封装到I2C_client结构体中。 - 驱动通过
I2C_client与硬件设备进行通信,并进行初始化操作。
&i2c1 是 I2C 总线的标识符
设备树中定义的 &i2c1 是一个对 I2C 总线的引用,它代表着 I2C 控制器硬件设备。通常,在设备树中,i2c1 是指特定的 I2C 总线,而 &i2c1 是用来告诉内核这个设备连接到哪一个 I2C 总线。它是 I2C 设备连接的父节点。通常,&i2c1 这样的标识符指向一个 I2C 控制器的节点,这个控制器的硬件资源会在设备树中被描述出来(例如,I2C 控制器的基地址、时钟等配置)。
ts@5d 节点描述了一个 I2C 设备
在你提供的设备树片段中,ts@5d 是一个 I2C 设备的子节点。它的 @5d 表示该设备的 I2C 地址为 0x5d(即通过 reg = <0x5d> 字段指定)。这个节点描述了一个具体的 I2C 设备,它与 &i2c1 连接,ts@5d 代表的设备将会通过 I2C 总线进行通信。
-
compatible字段:compatible = "goodix,gt9xx"字段指定了该设备是goodix,gt9xx类型的触摸屏设备。内核会使用这个compatible字段来匹配驱动程序。例如,在内核中可能已经有一个与"goodix,gt9xx"兼容的驱动程序。 -
reg字段:reg = <0x5d>指定了 I2C 地址,这告诉内核这个设备应该使用地址0x5d来进行通信。
自动注册为 I2C_client
内核根据设备树的内容和驱动程序之间的匹配机制,自动注册设备并为其创建 I2C_client 结构体。这个过程是通过 I2C_driver 实现的,具体流程如下:
-
I2C 总线设备的驱动程序匹配:内核在启动时会通过
compatible字段查找与设备树节点匹配的驱动程序。例如,如果你在内核中定义了一个I2C_driver,它的of_match_table中包含"goodix,gt9xx",那么这个驱动就会被选中与设备树中的ts@5d设备节点匹配。 -
设备创建
I2C_client:在设备树中,当节点ts@5d被解析时,内核会自动为该设备创建一个I2C_client结构体。这个结构体包含设备的 I2C 地址(0x5d)和与其相关的其他信息。 -
驱动
probe函数调用:内核通过I2C_driver的probe()函数来初始化设备。在probe()函数中,内核将I2C_client结构体传递给驱动程序,驱动程序可以使用这个结构体进行设备的初始化和数据交互。
通过I2C bus number来创建
int i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len);
通过设备树来创建
i2c1: i2c@400a0000 {/* ... master properties skipped ... */clock-frequency = <100000>;flash@50 {compatible = "atmel,24c256";reg = <0x50>;};pca9532: gpio@60 {compatible = "nxp,pca9532";gpio-controller;#gpio-cells = <2>;reg = <0x60>;};};
方法2 有时候无法知道该设备挂载哪个I2C bus下,无法知道它对应的I2C bus number。 但是可以通过其他方法知道对应的i2c_adapter结构体。 可以使用下面两个函数来创建i2c_client:
-
i2c_new_device
static struct i2c_board_info sfe4001_hwmon_info = {I2C_BOARD_INFO("max6647", 0x4e),};int sfe4001_init(struct efx_nic *efx){(...)efx->board_info.hwmon_client =i2c_new_device(&efx->i2c_adap, &sfe4001_hwmon_info);(...)}
i2c_new_probed_device
static const unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };static int usb_hcd_nxp_probe(struct platform_device *pdev){(...)struct i2c_adapter *i2c_adap;struct i2c_board_info i2c_info;(...)i2c_adap = i2c_get_adapter(2);memset(&i2c_info, 0, sizeof(struct i2c_board_info));strscpy(i2c_info.type, "isp1301_nxp", sizeof(i2c_info.type));isp1301_i2c_client = i2c_new_probed_device(i2c_adap, &i2c_info,normal_i2c, NULL);i2c_put_adapter(i2c_adap);(...)}
差别:
-
i2c_new_device:会创建i2c_client,即使该设备并不存在
-
i2c_new_probed_device:
-
它成功的话,会创建i2c_client,并且表示这个设备肯定存在
-
I2C设备的地址可能发生变化,比如AT24C02的引脚A2A1A0电平不一样时,设备地址就不一样
-
可以罗列出可能的地址
-
i2c_new_probed_device使用这些地址判断设备是否存在
-
-
方法3(不推荐):由i2c_driver.detect函数来判断是否有对应的I2C设备并生成i2c_client
-
方法4:通过用户空间(user-space)生成 调试时、或者不方便通过代码明确地生成i2c_client时,可以通过用户空间来生成。
// 创建一个i2c_client, .name = "eeprom", .addr=0x50, .adapter是i2c-3# echo eeprom 0x50 > /sys/bus/i2c/devices/i2c-3/new_device// 删除一个i2c_client# echo 0x50 > /sys/bus/i2c/devices/i2c-3/delete_device相关文章:
嵌入式linux驱动框架 I2C系统驱动程序模型分析
引言:在嵌入式 Linux 系统中,I2C(Inter-Integrated Circuit)是一种常用的通信协议,用于连接低速设备(如传感器、显示器、存储器等)与主控制器。I2C 系统驱动程序模型通过层次化的设计࿰…...
深度学习实验十七 优化算法比较
目录 一、优化算法的实验设定 1.1 2D可视化实验(被优化函数为) 1.2 简单拟合实验 二、学习率调整 2.1 AdaGrad算法 2.2 RMSprop算法 三、梯度修正估计 3.1 动量法 3.2 Adam算法 四、被优化函数变为的2D可视化 五、不同优化器的3D可视化对比 …...
一个双非选手的秋招总结
个人bg介绍 25届双非本硕(非杭电深大,垫底双非),两段实习经历,本科没学过Java,有c语言和408基础;2023年10月份中途转语言,Java速成选手。 战绩总结:实习秋招面试总论次…...
如何提高永磁电动机的节电效果
在现代工业和家庭应用中,永磁电动机因其优越的性能和节能特性,逐渐成为主流选择。随着能源日益紧缺和环境问题的日益严重,寻求高效的电动机节能方案显得尤为重要。 一、永磁电动机的基本原理 永磁电动机的核心是永磁体,这些永磁…...
在一个服务器上抓取 Docker 镜像并在另一个服务器上运行
要在一个服务器上抓取 Docker 镜像并在另一个服务器上运行,您可以按照以下步骤进行操作: 1. 保存 Docker 镜像 在源服务器上,您可以使用 docker save 命令将 Docker 镜像保存为一个 tar 文件。例如,如果您的镜像名称是 face_det…...
开源轮子 - Logback 和 Slf4j
spring boot内置:Logback 文章目录 spring boot内置:Logback一:Logback强在哪?二:简单使用三:把 log4j 转成 logback四:日志门面SLF4J1:什么是SLF4J2:SLF4J 解决了什么痛…...
内部知识库的未来展望:技术融合与用户体验的双重升级
在当今数字化飞速发展的时代,企业内部知识库作为知识管理的关键载体,正站在变革的十字路口,即将迎来技术融合与用户体验双重升级的崭新时代,这一系列变化将深度重塑企业知识管理的格局。 一、技术融合:开启知识管理新…...
【Linux系列】Shell 命令:`echo ““ > img.sh`及其应用
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...
【RAG实战】语言模型基础
语言模型赋予了计算机理解和生成人类语言的能力。它结合了统计学原理和深度神经网络技术,通过对大量的样本数据进行复杂的概率分布分析来学习语言结构的内在模式和相关性。具体地,语言模型可根据上下文中已出现的词序列,使用概率推断来预测接…...
【MySQL】7.0 入门学习(七)——MySQL基本指令:帮助、清除输入、查询等
1.0 help ? 帮助指令,查询某个指令的解释、用法、说明等。详情参考博文: 【数据库】6.0 MySQL入门学习(六)——MySQL启动与停止、官方手册、文档查询 https://www.cnblogs.com/xiaofu007/p/10301005.html 2.0 在cmd命…...
我的 2024 年终总结
2024 年,我离开了待了两年的互联网公司,来到了一家聚焦教育机器人和激光切割机的公司,没错,是一家硬件公司,从未接触过的领域,但这还不是我今年最重要的里程碑事件 5 月份的时候,正式提出了离职…...
STM32CUBEMX+STM32H743ZIT6+IAP+UART在线升级初始化和代码解析
1、STM32H7带的ITCM,DTCM,AXI SRAM,SRAM1,SRAM2,SRAM3,SRAM4和备份SRAM五块。 其中, ①TCM区包括ITCM和DTCM,这两个是直连CPU的。 速率与CPU一致,最高能到480MHz。 DTCM地…...
半连接转内连接 | OceanBase SQL 查询改写
查询优化器是关系型数据库系统的核心模块,是数据库内核开发的重点和难点,也是衡量整个数据库系统成熟度的“试金石”。为了帮助大家更好地理解 OceanBase 查询优化器,我们撰写了查询改写系列文章,带大家更好地掌握查询改写的精髓&…...
Git使用经历
目录 1、先创建文件夹 2、仓库初始化 3、配置gitee用户名和密码 4、克隆指定仓库的中指定分支到本地仓库 5、查看当前所在分支、切换分支 6、查看状态,判断是否有修改 7、把更新的内容添加到缓存区 8、把缓存区的数据提交 9、把数据推送到远程仓库 10、把…...
永磁同步电机控制算法-自适应带宽LADRC转速控制器
一、原理介绍 设计了自适应带宽 LADRC 控制方法,继承了 LADRC 优点的同时,加入自适应带宽控制,提出运用 Softsign 函数设计带宽自适应函数,根据电机转速自动调节控制带宽,解决了永磁同步电机在复杂且多变的环境下受到…...
基于springboot+vue实现的博物馆游客预约系统 (源码+L文+ppt)4-127
摘 要 旅游行业的快速发展使得博物馆游客预约系统成为了一个必不可少的工具。基于Java的博物馆游客预约系统旨在提供高效、准确和便捷的适用博物馆游客预约服务。本文讲述了基于java语言开发,后台数据库选择MySQL进行数据的存储。该软件的主要功能是进行博物馆游客…...
LeetCode 1705.吃苹果的最大数目:贪心(优先队列) - 清晰题解
【LetMeFly】1705.吃苹果的最大数目:贪心(优先队列) - 清晰题解 力扣题目链接:https://leetcode.cn/problems/maximum-number-of-eaten-apples/ 有一棵特殊的苹果树,一连 n 天,每天都可以长出若干个苹果。在第 i 天,…...
vim多窗格
vim打开文件分为三个阶段:buffer、window与tab buffer就是在同一个界面打开的文件window就是使用水平分割与垂直分割的窗口tab则是可以是上述两者的总集合 buffer :e filename在已打开文件的界面中再打开一个新文件,显示这个新文件,原文件被隐…...
ubuntu paddle ocr 部署bug问题解决
ubuntu paddle ocr 部署会出现异常报错。 尝试安装以下版本: pip install paddlepaddle2.5.2 -i https://pypi.tuna.tsinghua.edu.cn/simpl 助力快速掌握数据集的信息和使用方式。 数据可以如此美好!...
OpenFeign快速入门 示例:黑马商城
使用起因 之前我们利用了Nacos实现了服务的治理,利用RestTemplate实现了服务的远程调用。这样一来购物车虽然通过远程调用实现了调用商品服务的方法,但是远程调用的代码太复杂了: 解决方法 并且这种调用方式比较复杂,一会儿远程调用,一会儿本地调用。 因…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...
【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...
CSS设置元素的宽度根据其内容自动调整
width: fit-content 是 CSS 中的一个属性值,用于设置元素的宽度根据其内容自动调整,确保宽度刚好容纳内容而不会超出。 效果对比 默认情况(width: auto): 块级元素(如 <div>)会占满父容器…...
NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合
在汽车智能化的汹涌浪潮中,车辆不再仅仅是传统的交通工具,而是逐步演变为高度智能的移动终端。这一转变的核心支撑,来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒(T-Box)方案:NXP S32K146 与…...
20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...
JS手写代码篇----使用Promise封装AJAX请求
15、使用Promise封装AJAX请求 promise就有reject和resolve了,就不必写成功和失败的回调函数了 const BASEURL ./手写ajax/test.jsonfunction promiseAjax() {return new Promise((resolve, reject) > {const xhr new XMLHttpRequest();xhr.open("get&quo…...
打手机检测算法AI智能分析网关V4守护公共/工业/医疗等多场景安全应用
一、方案背景 在现代生产与生活场景中,如工厂高危作业区、医院手术室、公共场景等,人员违规打手机的行为潜藏着巨大风险。传统依靠人工巡查的监管方式,存在效率低、覆盖面不足、判断主观性强等问题,难以满足对人员打手机行为精…...
苹果AI眼镜:从“工具”到“社交姿态”的范式革命——重新定义AI交互入口的未来机会
在2025年的AI硬件浪潮中,苹果AI眼镜(Apple Glasses)正在引发一场关于“人机交互形态”的深度思考。它并非简单地替代AirPods或Apple Watch,而是开辟了一个全新的、日常可接受的AI入口。其核心价值不在于功能的堆叠,而在于如何通过形态设计打破社交壁垒,成为用户“全天佩戴…...
