I2C驱动(十一) -- gpio模拟的i2c总线驱动i2c-gpio.c分析
相关文章
I2C驱动(一) – I2C协议
I2C驱动(二) – SMBus协议
I2C驱动(三) – 驱动中的几个重要结构
I2C驱动(四) – I2C-Tools介绍
I2C驱动(五) – 通用驱动i2c-dev.c分析
I2C驱动(六) – I2C驱动程序模型
I2C驱动(七) – 编写I2C设备驱动之i2c_driver
I2C驱动(八) – 编写I2C设备驱动之i2c_client
I2C驱动(九) – i2c_adapter控制器驱动框架编写
I2C驱动(十) – i2c_adapter控制器驱动完善与上机实验
文章目录
- 相关文章
- 参考资料
- 一、平台-总线-设备驱动模型
- 二、设备树分析
- 三、驱动程序分析
- 3.1 i2c-gpio驱动层次
- 3.2 `bit_xfer`传输函数分析
- 四、怎么使用i2c-gpio
- 五、总结
参考资料
- i2c_spec.pdf
- Linux文档
Linux-4.9.88\Documentation\devicetree\bindings\i2c\i2c-gpio.txt
- Linux驱动源码
Linux-4.9.88\drivers\i2c\busses\i2c-gpio.c
一、平台-总线-设备驱动模型
i2c-gpio.c也是基于万能框架:平台-总线-设备模型来写的。platform_device部分来自设备树,platform_driver就是i2c-gpio.c驱动。下面分析两边的代码。

二、设备树分析
设备树节点如下:
i2c_gpio: i2c-gpio {compatible = "i2c-gpio";#address-cells = <1>;#size-cells = <0>;pinctrl-names = "default";pinctrl-0 = <&pinctrl_i2c_gpio>;gpios = <&gpio5 1 GPIO_ACTIVE_HIGH /* SDA */&gpio5 0 GPIO_ACTIVE_HIGH /* SCL */>;i2c-gpio,delay-us = <5>; /* ~100 kHz */status = "okay";ds1339: rtc@68 {compatible = "dallas,ds1339";reg = <0x68>;status = "disabled";};};
compatible属性用于和i2c-gpio.c程序中.of_match_table结构中的compatible进行比较。#address-cells和#size-cells属性用来指定reg属性的地址和大小用多少个32位数据表示。reg属性在子节点中用了表示i2c设备地址。pinctrl-names和pinctrl-0属性表示使用pinctrl将引脚配置成gpio模式。gpios属性用于指定gpio引脚i2c-gpio,delay-us属性表示时钟频率status属性节点使能状态ds1339: rtc@68表示的是这个i2c总线下挂的设备,地址是0x68。
三、驱动程序分析
3.1 i2c-gpio驱动层次
从入口函数开始,入口函数注册了一个platform_driver结构。
tatic int __init i2c_gpio_init(void)
{
...ret = platform_driver_register(&i2c_gpio_driver);
...
}
platform_driver结构包含了of_match_table数组,probe函数。
static struct platform_driver i2c_gpio_driver = {.driver = {.name = "i2c-gpio",.of_match_table = of_match_ptr(i2c_gpio_dt_ids), //和设备树比较},.probe = i2c_gpio_probe, //匹配成功调用.remove = i2c_gpio_remove, //做一些和probe相反的工作
};
of_match_table数组中的compatible 和设备树匹配成功,调用probe函数。
static const struct of_device_id i2c_gpio_dt_ids[] = {{ .compatible = "i2c-gpio", }, //与设备树的compatible 比较{ /* sentinel */ }
};
来看probe函数:
of_i2c_gpio_get_pins从设备树获取gpio引脚。adap = &priv->adap;分配的i2c_adapter。of_i2c_gpio_get_props从设备树获取属性值,用来设置硬件参数和i2c_adapter结构。i2c_bit_add_numbered_bus注册i2c_adapter,这个是重点,这里面会有算法部分设置,下面继续分析。
static int i2c_gpio_probe(struct platform_device *pdev)
{
...unsigned int sda_pin, scl_pin; //sda 和 scl引脚int ret;/* First get the GPIO pins; if it fails, we'll defer the probe. */if (pdev->dev.of_node) {/* 从设备树中获取 sda 和 scl */ret = of_i2c_gpio_get_pins(pdev->dev.of_node,&sda_pin, &scl_pin);if (ret)return ret;} else {if (!dev_get_platdata(&pdev->dev))return -ENXIO;pdata = dev_get_platdata(&pdev->dev);sda_pin = pdata->sda_pin;scl_pin = pdata->scl_pin;}/*devm_gpio_request 可以自动处理清理工作 */ret = devm_gpio_request(&pdev->dev, sda_pin, "sda");if (ret) {if (ret == -EINVAL)ret = -EPROBE_DEFER; /* Try again later */return ret;}ret = devm_gpio_request(&pdev->dev, scl_pin, "scl");if (ret) {if (ret == -EINVAL)ret = -EPROBE_DEFER; /* Try again later */return ret;}priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);if (!priv)return -ENOMEM;/* 分配了i2c_adapter */ adap = &priv->adap;bit_data = &priv->bit_data;pdata = &priv->pdata;if (pdev->dev.of_node) {pdata->sda_pin = sda_pin;pdata->scl_pin = scl_pin;/*从设备树获取属性*/of_i2c_gpio_get_props(pdev->dev.of_node, pdata);} else {memcpy(pdata, dev_get_platdata(&pdev->dev), sizeof(*pdata));}/* 根据获取的设备树属性值设置开漏情况 */if (pdata->sda_is_open_drain) {gpio_direction_output(pdata->sda_pin, 1);bit_data->setsda = i2c_gpio_setsda_val;} else {gpio_direction_input(pdata->sda_pin);bit_data->setsda = i2c_gpio_setsda_dir;}if (pdata->scl_is_open_drain || pdata->scl_is_output_only) {gpio_direction_output(pdata->scl_pin, 1);bit_data->setscl = i2c_gpio_setscl_val;} else {gpio_direction_input(pdata->scl_pin);bit_data->setscl = i2c_gpio_setscl_dir;}/* 根据获取的设备树属性值设置时间参数 */if (!pdata->scl_is_output_only)bit_data->getscl = i2c_gpio_getscl;bit_data->getsda = i2c_gpio_getsda;if (pdata->udelay)bit_data->udelay = pdata->udelay;else if (pdata->scl_is_output_only)bit_data->udelay = 50; /* 10 kHz */elsebit_data->udelay = 5; /* 100 kHz */if (pdata->timeout)bit_data->timeout = pdata->timeout;elsebit_data->timeout = HZ / 10; /* 100 ms */bit_data->data = pdata;/* 根据设备树解析的值设置i2c_adapter */adap->owner = THIS_MODULE;if (pdev->dev.of_node)strlcpy(adap->name, dev_name(&pdev->dev), sizeof(adap->name));elsesnprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdev->id);adap->algo_data = bit_data;adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;adap->dev.parent = &pdev->dev;adap->dev.of_node = pdev->dev.of_node;adap->nr = pdev->id;/* 注册i2c_adapter */ret = i2c_bit_add_numbered_bus(adap);
...
}
进入i2c_bit_add_numbered_bus看看,这个函数在drivers\i2c\algos\i2c-algo-bit.c中定义,他调用__i2c_bit_add_bus,__i2c_bit_add_bus里面设置了adap->algo = &i2c_bit_algo;,这就是i2c核心算法结构,下面继续看i2c_bit_algo。
int i2c_bit_add_numbered_bus(struct i2c_adapter *adap)
{return __i2c_bit_add_bus(adap, i2c_add_numbered_adapter);
}static int __i2c_bit_add_bus(struct i2c_adapter *adap,int (*add_adapter)(struct i2c_adapter *))
{
.../* 核心算法 */adap->algo = &i2c_bit_algo;
...
}
i2c_bit_algo结构中bit_xfer就是gpio模拟i2c_adapter的传输函数。
const struct i2c_algorithm i2c_bit_algo = {.master_xfer = bit_xfer,.functionality = bit_func,
};
从上面的分析,可以知道I2C-GPIO的驱动层次如下:

3.2 bit_xfer传输函数分析
传输函数是根据i2c协议来完成的,i2c_start发起一个start信号,接着根据i2c_msg 来判断读写,readbytes读一个字节,sendbytes写一个字节。结束后i2c_stop发出停止信号。
static int bit_xfer(struct i2c_adapter *i2c_adap,struct i2c_msg msgs[], int num)
{struct i2c_msg *pmsg;struct i2c_algo_bit_data *adap = i2c_adap->algo_data;int i, ret;unsigned short nak_ok;if (adap->pre_xfer) {ret = adap->pre_xfer(i2c_adap);if (ret < 0)return ret;}bit_dbg(3, &i2c_adap->dev, "emitting start condition\n");i2c_start(adap); //发出Start信号for (i = 0; i < num; i++) {pmsg = &msgs[i]; //循环取出i2c_msg nak_ok = pmsg->flags & I2C_M_IGNORE_NAK;if (!(pmsg->flags & I2C_M_NOSTART)) {if (i) {bit_dbg(3, &i2c_adap->dev, "emitting ""repeated start condition\n");i2c_repstart(adap);}ret = bit_doAddress(i2c_adap, pmsg);if ((ret != 0) && !nak_ok) {bit_dbg(1, &i2c_adap->dev, "NAK from ""device addr 0x%02x msg #%d\n",msgs[i].addr, i);goto bailout;}}if (pmsg->flags & I2C_M_RD) {/* read bytes into buffer(读一个字节)*/ ret = readbytes(i2c_adap, pmsg);if (ret >= 1)bit_dbg(2, &i2c_adap->dev, "read %d byte%s\n",ret, ret == 1 ? "" : "s");if (ret < pmsg->len) {if (ret >= 0)ret = -EIO;goto bailout;}} else {/* write bytes from buffer (写一个字节)*/ret = sendbytes(i2c_adap, pmsg);if (ret >= 1)bit_dbg(2, &i2c_adap->dev, "wrote %d byte%s\n",ret, ret == 1 ? "" : "s");if (ret < pmsg->len) {if (ret >= 0)ret = -EIO;goto bailout;}}}ret = i;bailout:bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n");i2c_stop(adap);if (adap->post_xfer)adap->post_xfer(i2c_adap);return ret;
}
字节读写再细分到位操作,在i2c_outb函数中实现。
static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c)
{int i;int sb;int ack;struct i2c_algo_bit_data *adap = i2c_adap->algo_data;/* assert: scl is low */for (i = 7; i >= 0; i--) {sb = (c >> i) & 1;setsda(adap, sb);udelay((adap->udelay + 1) / 2);if (sclhi(adap) < 0) { /* timed out */bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, ""timeout at bit #%d\n", (int)c, i);return -ETIMEDOUT;}/* FIXME do arbitration here:* if (sb && !getsda(adap)) -> ouch! Get out of here.** Report a unique code, so higher level code can retry* the whole (combined) message and *NOT* issue STOP.*/scllo(adap);}sdahi(adap);if (sclhi(adap) < 0) { /* timeout */bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, ""timeout at ack\n", (int)c);return -ETIMEDOUT;}/* read ack: SDA should be pulled down by slave, or it may* NAK (usually to report problems with the data we wrote).*/ack = !getsda(adap); /* ack: sda is pulled low -> success */bit_dbg(2, &i2c_adap->dev, "i2c_outb: 0x%02x %s\n", (int)c,ack ? "A" : "NA");scllo(adap);return ack;/* assert: scl is low (sda undef) */
}
四、怎么使用i2c-gpio
设置设备树,在里面添加一个节点即可,示例代码看上面"设备树分析"部分,也可以参考 Linux-4.9.88\Documentation\devicetree\bindings\i2c\i2c-gpio.txt。
五、总结
本文分析了gpio模拟的i2c_adapter驱动程序i2c-gpio.c。
相关文章:
I2C驱动(十一) -- gpio模拟的i2c总线驱动i2c-gpio.c分析
相关文章 I2C驱动(一) – I2C协议 I2C驱动(二) – SMBus协议 I2C驱动(三) – 驱动中的几个重要结构 I2C驱动(四) – I2C-Tools介绍 I2C驱动(五) – 通用驱动i2c-dev.c分析 I2C驱动(六) – I2C驱动程序模型 I2C驱动(七) – 编写I2C设备驱动之i2c_driver I2C驱动(八) – 编写I2C…...
不要升级,Flutter Debug 在 iOS 18.4 beta 无法运行,提示 mprotect failed: Permission denied
近期如果有开发者的 iOS 真机升级到 18.4 beta,大概率会发现在 debug 运行时会有 Permission denied 的相关错误提示,其实从 log 可以很直观看出来,就是 Dart VM 在初始化时,对内核文件「解释运行(JIT)」时…...
zjbdt
嵌入式软件工程师可以通过考取相关职业证书来提升专业能力和职业竞争力。以下是几种含金量较高且广受认可的证书: 1. NIEH 嵌入式技术工程师证书 颁发机构:教育部考试中心级别:初级、中级、高级内容:涵盖嵌入式系统的基础理论、开…...
【3天快速入门WPF】11-附加属性
目录 1. 步骤1:定义附加属性2. 示例代码3. 步骤2:在XAML中使用附加属性3.1. 示例代码4. 步骤3:扩展使用场景4.1. 示例代码5. 总结上一篇讲到了依赖属性,本篇主要想说一下附加属性。 在WPF中,附加属性(Attached Property)是一种特殊的依赖属性,允许你在不属于某个类的控…...
私有化部署大模型推理性能分析
从用户感知角度分析私有化部署的大模型推理性能,这里的用户感知包括响应速度、生成速度、系统可用性以及系统稳定性。大模型首先获取输入内容的字符串,将这部分内容转换为模型token,过模型推理,到最后输出第一个token的时间是ttft,从这以后&a…...
版图自动化连接算法开发 00001 ------ 直接连接两个给定的坐标点
版图自动化连接算法开发 00001 ------ 直接连接两个给定的坐标点 引言正文定义坐标点的类绘图显示代码直接连接两个坐标点引言 由于人工智能的加速普及,每次手动绘制版图都会觉得特别繁琐,作者本人在想可否搞一个自动化连接器件端口的算法,后期可以根据一些设定的限制进行避…...
UniApp 按钮组件 open-type 属性详解:功能、场景与平台差异
文章目录 引言一、open-type 基础概念1.1 核心作用1.2 通用使用模板 二、主流 open-type 值详解2.1 contact - 客服会话功能说明平台支持代码示例 2.2 share - 内容转发功能说明平台支持注意事项 2.3 getUserInfo - 获取用户信息功能说明平台支持代码示例 2.4 getPhoneNumber -…...
EtherCAT总线绝对值伺服如何使用
EtherCAT总线掉线如何自动重启。 EtherCAT总线掉线如何自动重启_ethercat从站断线-CSDN博客文章浏览阅读1.2k次。本文介绍了在EtherCAT通信中,当从站出现掉线情况时,如何通过设置自动重启功能来解决这一问题。详细步骤包括在CODESYS环境中启用从站的自动重启选项。https://r…...
可商用街头文化艺术海报封面手写涂鸦标题LOGO排版英文字体 FS163 TYPE FACE
Freestyle 163 (FS163)是一个受街头文化和城市艺术启发的视觉宣言。该字体旨在突出我们的文化和创意根源,反映了街头运动、城市艺术以及来自社会和边缘的故事。 FS163与面临挑战、质疑规范、放大被忽视声音的品牌和个人联系在一起,…...
使用3090显卡部署Wan2.1生成视频
layout: post title: 使用3090显卡部署Wan2.1生成视频 catalog: true tag: [Kubernetes, GPU, AI] 使用3090显卡部署Wan2.1生成视频 1. 环境说明2. 模型下载3. 克隆仓库4. 安装依赖5. 生成视频 5.1. 使用generate脚本生成5.2. 使用gradio启动UI界面生成 5.2.1. 启动gradio服务5…...
js逆向常用代码
js逆向常用代码 加载 const loadingStyle #loadingDiv {position: fixed;z-index: 9999;top: 0;left: 0;width: 100%;height: 100%;background-color: rgba(255, 255, 255, 0.8);display: flex;align-items: center;justify-content: center;flex-direction: column;}.loade…...
Diffusion——扩散模型(未完待续)
论文链接:https://arxiv.org/abs/2006.11239 简介 扩散模型(Diffusion Model)是用于生成数据的一类深度生成模型,特别擅长于图像生成。其工作原理基于通过随机噪声的逐步转换来生成目标数据。扩散模型分为两部分:正向…...
Java内存管理与性能优化实践
Java内存管理与性能优化实践 Java作为一种广泛使用的编程语言,其内存管理和性能优化是开发者在日常工作中需要深入了解的重要内容。Java的内存管理机制借助于垃圾回收(GC)来自动处理内存的分配和释放,但要实现高效的内存管理和优…...
unsloth报错FileNotFoundError: [WinError 3] 系统找不到指定的路径。
运行平台 Windows 报错信息 Traceback (most recent call last): File “C:\Python312\Lib\site-packages\IPython\core\interactiveshell.py”, line 3577, in run_code exec(code_obj, self.user_global_ns, self.user_ns) File “”, line 1, in runfile(‘D:\python_pr…...
不同规模企业如何精准选择AI工具: DeepSeek、Grok 和 ChatGPT 三款主流 AI 工具深度剖析与对比
本文深入探讨了最近国内外主流的 DeepSeek、Grok 和 ChatGPT 三款主流 AI 工具的技术细节、性能表现、应用场景及局限性,并从技术能力、功能需求、成本预算、数据安全和合规以及服务与支持五个关键维度,详细分析了不同规模企业在选择 AI 工具时的考量因素…...
各章节详细总结与 Vue 学习收尾
各章节详细总结与 Vue学习收尾 第一章:基础入门 通俗理解:这就像你刚踏入一个新的游戏世界,得先搞清楚游戏的基本规则和操作方法。在 Vue 3 的学习里,就是要搭建好开发环境,认识 Vue 3 的基本概念,比如模…...
c++ 文件及基本读写总结
在 C 中,文件操作是非常重要的一部分,主要用于将数据存储到文件中,或者从文件中读取数据。C 标准库提供了fstream头文件,其中包含了用于文件操作的类,主要有ifstream(用于输入文件流,即从文件读…...
如何调试Linux内核?
通过创建一个最小的根文件系统,并使用QEMU和GDB进行调试。 1.准备工作环境 确保系统上安装了所有必要的工具和依赖项。 sudo apt-get update //更新一下软件包 sudo apt-get install build-essential git libncurses-dev bison flex libssl-dev qemu-system-x…...
Docker入门指南:Windows下docker配置镜像源加速下载
Windows下docker配置镜像源加速下载 docker的官方镜像是海外仓库,默认下载耗时较长,而且经常出现断站的现象,因此需要配置国内镜像源。 国内镜像源概述 国内现有如下镜像源可以使用 "http://hub-mirror.c.163.com", "http…...
java后端开发day24--阶段项目(一)
(以下内容全部来自上述课程) GUI:Graphical User Interface 图形用户接口,采取图形化的方式显示操作界面 分为两套体系:AWT包(有兼容问题)和Swing包(常用) 拼图小游戏…...
TVbox蜂蜜影视:智能电视观影新选择,简洁界面与强大功能兼具
蜂蜜影视是一款基于猫影视开源项目 CatVodTVJarLoader 开发的智能电视软件,专为追求简洁与高效观影体验的用户设计。该软件从零开始编写,界面清爽,操作流畅,特别适合在智能电视上使用。其最大的亮点在于能够自动跳过失效的播放地址…...
2025.3.2机器学习笔记:PINN文献阅读
2025.3.2周报 一、文献阅读题目信息摘要Abstract创新点网络架构实验结论不足以及展望 一、文献阅读 题目信息 题目: Physics-Informed Neural Networks of the Saint-Venant Equations for Downscaling a Large-Scale River Model期刊: Water Resource…...
2025AI 有哪些重要的发展趋势?
2025 年,AI 有哪些重要的发展趋势? 看看大佬们的看法: 马斯克:“人形机器人生产、自动驾驶突破、脑机接口进化” 奥特曼:“2025年,AGI即将到来” 黄仁勋:“通用机器人元年、能源效率的提升”…...
uni-app 全局请求封装:支持 Promise,自动刷新 Token,解决 401 过期问题
在 uni-app 中封装一个全局通用的 ajax 请求函数,支持 Promise,使用 uni.request() 进行请求,并且具备 自动刷新 token 的功能。以下是详细步骤: 实现步骤 创建 request.js 统一封装 ajax 请求管理 token(存储、获取、…...
IDEAPyCharm安装ProxyAI(CodeGPT)插件连接DeepSeek-R1教程
背景:最近DeepSeek比较火嘛,然后在githup上也看到了GitHub Copilot,就想着现在AI的准确率已经可以提高工作效率了。所以从网上找了一些编程插件,发现Proxy支持的模型比较多,通用性和适配性比较好。所以本文记录一下pro…...
【实战 ES】实战 Elasticsearch:快速上手与深度实践-2.1.2字段类型选择:keyword vs text、nested对象
👉 点击关注不迷路 👉 点击关注不迷路 👉 点击关注不迷路 文章大纲 第2章 数据建模与高效写入:ES字段类型选择最佳实践:keyword vs text与nested对象深度解析1. 索引设计核心原则2. keyword与text类型终极对决2.1 核心…...
【前端基础】Day 3 CSS-2
目录 1. Emmet语法 1.1 快速生成HTML结构语法 1.2 快速生成CSS样式语法 2. CSS的复合选择器 2.1 后代选择器 2.2 子选择器 2.3 并集选择器 2.4 伪类选择器 2.4.1 链接伪类选择器 2.4.2 focus伪类选择器 2.5 复合选择器总结 3. CSS的元素显示模式 3.1 什么是元素显示…...
windows电脑上安装llama-factory实现大模型微调
一、安装环境准备 这是官方给的llama-factory安装教程,安装 - LLaMA Factory,上面介绍了linux系统上以及windows系统上如何正确安装。大家依照安装步骤基本能够完成安装,但是可能由于缺少经验或者相关的知识导致启动webUi界面运行相应内容时…...
汽车无人驾驶系统中的防撞设计
一、系统方案介绍 无人驾驶汽车的防撞系统是保障行车安全的核心模块,本文设计的系统以STM32F103C8T6单片机为主控制器,结合超声波测距、WiFi通信、人机交互等模块,实现障碍物实时检测、动态阈值设置、多级报警和数据可视化功能。系统通过软…...
sql server 版本更新日期
SQL Server 2019 内部版本(KB4518398) - SQL Server | Microsoft Learn SQL Server 的最新更新和版本历史记录 - SQL Server | Microsoft Learn sql server 2019 版本更新时间和补丁版本号...
