当前位置: 首页 > news >正文

Linux学习笔记--i2c_Adapter驱动框架

这是一个虚拟I2C总线适配器驱动,用于创建软件模拟的I2C总线,不依赖实际硬件。

1. 头文件包含

#include <linux/i2c.h>           // I2C核心支持
#include <linux/platform_device.h> // 平台设备驱动
#include <linux/i2c-algo-bit.h>  // I2C算法支持
// ... 其他内核头文件

2. 全局变量

static struct i2c_adapter *g_adapter;  // 全局I2C适配器指针

3. I2C传输函数

static int i2c_bus_virtual_master_xfer(struct i2c_adapter *i2c_adap,struct i2c_msg msgs[], int num)
{int i;for (i = 0; i < num; i++){// do transfer msgs[i];// 这里需要实现具体的I2C传输逻辑// 对于虚拟总线,可以模拟传输或记录日志}return num;  // 返回成功传输的消息数量
}

参数说明

  • i2c_adap:I2C适配器指针

  • msgs[]:I2C消息数组

  • num:消息数量

  • I2C消息结构

struct i2c_msg {__u16 addr;     // 设备地址__u16 flags;    // 读写标志__u16 len;      // 数据长度__u8 *buf;      // 数据缓冲区
};

4. 功能支持函数

static u32 i2c_bus_virtual_func(struct i2c_adapter *adap)
{return I2C_FUNC_I2C | I2C_FUNC_NOSTART | I2C_FUNC_SMBUS_EMUL |I2C_FUNC_SMBUS_READ_BLOCK_DATA |I2C_FUNC_SMBUS_BLOCK_PROC_CALL |I2C_FUNC_PROTOCOL_MANGLING;
}

功能标志说明

  • I2C_FUNC_I2C:支持标准I2C协议

  • I2C_FUNC_NOSTART:支持重复起始条件

  • I2C_FUNC_SMBUS_EMUL:支持SMBus模拟

  • I2C_FUNC_SMBUS_READ_BLOCK_DATA:支持读取块数据

  • I2C_FUNC_SMBUS_BLOCK_PROC_CALL:支持块处理调用

  • I2C_FUNC_PROTOCOL_MANGLING:支持协议处理

5. I2C算法结构体

const struct i2c_algorithm i2c_bus_virtual_algo = {.master_xfer   = i2c_bus_virtual_master_xfer,  // 主传输函数.functionality = i2c_bus_virtual_func,         // 功能查询函数
};

作用:定义I2C总线的操作方法和能力。

6. 平台驱动探测函数

static int i2c_bus_virtual_probe(struct platform_device *pdev)
{/* 从设备树获取信息,设置i2c_adapter/硬件 *//* 分配、设置、注册i2c_adapter */g_adapter = kzalloc(sizeof(*g_adapter), GFP_KERNEL);// 设置适配器属性g_adapter->owner = THIS_MODULE;g_adapter->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;  // 硬件监控和内存SPD类g_adapter->nr = -1;  // 动态分配适配器编号snprintf(g_adapter->name, sizeof(g_adapter->name), "i2c-bus-virtual");g_adapter->algo = &i2c_bus_virtual_algo;  // 设置算法i2c_add_adapter(g_adapter); // 注册适配器到I2C核心// 也可以使用 i2c_add_numbered_adapter(g_adapter);return 0;
}

适配器属性说明

  • owner:模块所有者

  • class:设备类(硬件监控 + 内存SPD)

  • nr:适配器编号(-1表示动态分配)

  • name:适配器名称

  • algo:I2C算法

7. 平台驱动移除函数

static int i2c_bus_virtual_remove(struct platform_device *pdev)
{i2c_del_adapter(g_adapter);  // 从I2C核心注销适配器kfree(g_adapter);           // 释放适配器内存(代码中缺失)return 0;
}

8. 设备树匹配表

static const struct of_device_id i2c_bus_virtual_dt_ids[] = {{ .compatible = "100ask,i2c-bus-virtual", },  // 兼容性字符串{ /* sentinel */ }
};

对应设备树节点

virtual_i2c_bus: i2c@virtual {compatible = "100ask,i2c-bus-virtual";// 可以添加虚拟总线的参数
};

9. 平台驱动结构体

static struct platform_driver i2c_bus_virtual_driver = {.driver		= {.name	= "i2c-gpio",  // 驱动名称.of_match_table	= of_match_ptr(i2c_bus_virtual_dt_ids),  // 设备树匹配表},.probe		= i2c_bus_virtual_probe,   // 探测函数.remove		= i2c_bus_virtual_remove,  // 移除函数
};

注意:驱动名称是"i2c-gpio",但实际是虚拟I2C总线。

10. 模块初始化和退出

static int __init i2c_bus_virtual_init(void)
{int ret;ret = platform_driver_register(&i2c_bus_virtual_driver);if (ret)printk(KERN_ERR "i2c-gpio: probe failed: %d\n", ret);return ret;
}
module_init(i2c_bus_virtual_init);static void __exit i2c_bus_virtual_exit(void)
{platform_driver_unregister(&i2c_bus_virtual_driver);
}
module_exit(i2c_bus_virtual_exit);

完整执行流程

insmod i2c_bus_virtual.ko↓
i2c_bus_virtual_init()↓
platform_driver_register(&i2c_bus_virtual_driver)↓
内核扫描设备树,查找匹配节点↓
找到 compatible = "100ask,i2c-bus-virtual" 的节点↓
调用 i2c_bus_virtual_probe()↓
分配并设置 i2c_adapter↓
i2c_add_adapter(g_adapter)  // 注册虚拟I2C总线

系统状态变化:

注册成功后

# 查看I2C适配器
$ cat /sys/class/i2c-adapter/i2c-*/name
# 会出现 "i2c-bus-virtual"# 使用i2c-tools查看
$ i2cdetect -l
# 会列出虚拟I2C总线

虚拟I2C总线的用途

1. 测试和开发

// 可以在虚拟总线上测试I2C设备驱动,无需真实硬件
static struct i2c_board_info virtual_devices[] = {{ I2C_BOARD_INFO("ap3216c", 0x1e) },{ I2C_BOARD_INFO("at24c02", 0x50) },
};

2. 模拟硬件

// 在master_xfer中模拟硬件行为
static int i2c_bus_virtual_master_xfer(...)
{for (i = 0; i < num; i++) {if (msgs[i].flags & I2C_M_RD) {// 模拟读取操作memset(msgs[i].buf, 0xAA, msgs[i].len);} else {// 模拟写入操作printk("写入数据: %*ph\n", msgs[i].len, msgs[i].buf);}}return num;
}

3. 调试和日志

// 记录所有I2C传输用于调试
static int i2c_bus_virtual_master_xfer(...)
{int i, j;for (i = 0; i < num; i++) {printk("I2C消息 %d: 地址=0x%02x, 标志=0x%04x, 长度=%d\n",i, msgs[i].addr, msgs[i].flags, msgs[i].len);if (!(msgs[i].flags & I2C_M_RD)) {printk("写入数据: ");for (j = 0; j < msgs[i].len; j++)printk("%02x ", msgs[i].buf[j]);printk("\n");}}return num;
}

设备树配置示例

/ {virtual_i2c_bus: i2c@virtual {compatible = "100ask,i2c-bus-virtual";#address-cells = <1>;#size-cells = <0>;// 在虚拟总线上挂载虚拟设备virtual_sensor@1e {compatible = "virtual,ap3216c";reg = <0x1e>;};virtual_eeprom@50 {compatible = "virtual,at24c02";reg = <0x50>;};};
};
http://www.dtcms.com/a/446520.html

相关文章:

  • 新乡做网站建设工程网站有哪些
  • liferay 做网站仿wordpress站
  • MySQL 中一条 SQL 语句的执行流程
  • 2025年--Lc162--H169.多数元素(数组和字符串)--Java版
  • wordpress搭建个人网站蚌埠市建设工程质监站网站
  • 中国建设銀行网站投诉电话wordpress 钩子列表
  • 腾讯云微服务平台TSF
  • 第125期:借助 n8n 构建 AI 智能体:10个自动化实践方案
  • 网站开发 案例wordpress怎么安装在宝塔软件
  • 网站权重对应的等级商丘至开网络科技有限公司
  • C++ 优先队列(priority_queue)深度解析
  • php 8.4.4 更新日志
  • 自己搭建网站做网上商城做系统网站赚钱
  • 【征文计划】基于Rokid CXR-M SDK 打造AI 实时会议助手:从连接到自定义界面的完整实践
  • 多模态推理的“思维之跃”:紫东太初4.0如何重塑AI认知边界
  • 实现 RTOS 操作系统 【零】内核编程实践
  • 做产品推广哪个网站好欧米茄表官网
  • 带后台的免费网站模板网站建设培训班上的讲话
  • 【学习笔记】泊松表面重建探讨
  • 做彩票网站需要学习什么深圳招工包吃住8000元
  • 株洲网站建设 磐石网络中国环球贸易网
  • 如何买域名发布网站电子商务网站建设类论文
  • 6. linux shell命令(2)基本系统维护命令与用户管理
  • 我的智能清洁日记:一台有鹿机器人的社区见闻录
  • 建英文网站费用找外包开发一个小程序需要多少钱
  • C++中的装饰器模式变体
  • 【代码随想录day 35】 力扣 416. 分割等和子集
  • 网站的关键字 设置php 网站后台管理系统
  • 沈阳手机端建站模板大数据适合什么人学
  • C语言-字符函数和字符串函数