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

Linux驱动-i2c 驱动框架编写

提示:Linux驱动-i2c 驱动框架编写

文章目录

  • 前言
  • 一、参考资料
  • 二、相关文件
  • 三、驱动框架编写
    • 1、设备树-client 端配置
    • 2、i2c 驱动框架
      • 框架编码
      • 对比平台总线-i2c_add_driver
    • 3、i2c 驱动框架实验
  • 四、知识点扩展
    • 驱动层和client 端匹配机制
    • probe 函数对应的 of_device_id 基本规则
    • MODULE_DEVICE_TABLE
    • 查错方法
      • ls /sys/bus/i2c/drivers/
      • ls /sys/bus/i2c/devices/
      • 驱动缺失 MODULE_DEVICE_TABLE
  • 总结

前言

i2C 驱动框架编写,驱动框架学习法,先写一个框架。 既然写框架 基于之前设备树已经配置了,那么写一个基本的框架和设备树节点匹配上。

一、参考资料

本篇内容关联的资料如下:

驱动-I2C-客户端代码编写-编写设备树
驱动-设备树和驱动自动匹配
RK3568驱动指南|第七期-设备树-第65章 设备树下platform_device和platform_driver匹配实验
驱动-平台总线-probe

二、相关文件

kernel/include/linux/i2c.h kernel/drivers/i2c/i2c-core-base.c

对应i2c 注册的一些方法,需要了解、熟悉的。

三、驱动框架编写

1、设备树-client 端配置

如之前 驱动-I2C-客户端代码编写-编写设备树 配置,设备树配置如下:

&i2c1{status="okay";myft5x06:my-ft5x06@38{compatible="my-ft5x06";reg=<0x38>;};};

这里最重要的不就是compatible属性的值嘛

2、i2c 驱动框架

框架编码

框架编码如下

#include<linux/init.h>#include<linux/module.h>#include<linux/i2c.h>#include<linux/of_device.h>intft5x06_probe(struct i2c_client*client,conststruct i2c_device_id*id){printk(KERN_INFO"###### This is ft5x06 probe ######\n");return0;}intft5x06_remove(struct i2c_client*client){printk(KERN_INFO"###### This is ft5x06_remove ######\n");return0;}staticconststruct of_device_id ft5x06_id[]={{.compatible="my-ft5x06"},{/* Sentinel */},};// 关键补充MODULE_DEVICE_TABLE(of,ft5x06_id);staticstruct i2c_driver ft5x06_driver={.driver={.owner=THIS_MODULE,.name="my-ft5x06",.of_match_table=ft5x06_id,},.probe=ft5x06_probe,.remove=ft5x06_remove,};staticint__initft5x06_driver_init(void){intret;ret=i2c_add_driver(&ft5x06_driver);if(ret<0){printk(KERN_ERR"i2c_add_driver failed ret=%d\n",ret);returnret;}printk(KERN_INFO"###### ft5x06 driver register success ######\n");return0;}staticvoid__exitft5x06_driver_exit(void){i2c_del_driver(&ft5x06_driver);printk(KERN_INFO"###### ft5x06 driver unregister ######\n");}module_init(ft5x06_driver_init);module_exit(ft5x06_driver_exit);MODULE_LICENSE("GPL");

对比平台总线-i2c_add_driver

注册平台总线用了方法:i2c_add_driver
看定义地方,路径:kernel/include/linux/i2c.h

externinti2c_register_driver(structmodule*,struct i2c_driver*);externvoidi2c_del_driver(struct i2c_driver*);/* use a define to avoid include chaining to get THIS_MODULE */#definei2c_add_driver(driver)\i2c_register_driver(THIS_MODULE,driver)

看这个方法实现地方,路径:kernel/drivers/i2c/i2c-core-base.c

/* * An i2c_driver is used with one or more i2c_client (device) nodes to access * i2c slave chips, on a bus instance associated with some i2c_adapter. */inti2c_register_driver(structmodule*owner,struct i2c_driver*driver){intres;/* Can't register until after driver model init */if(WARN_ON(!is_registered))return-EAGAIN;/* add the driver to the list of i2c drivers in the driver core */driver->driver.owner=owner;driver->driver.bus=&i2c_bus_type;INIT_LIST_HEAD(&driver->clients);/* When registration returns, the driver core * will have called probe() for all matching-but-unbound devices. */res=driver_register(&driver->driver);if(res)returnres;pr_debug("driver [%s] registered\n",driver->driver.name);/* Walk the adapters that are already present */i2c_for_each_dev(driver,__process_new_driver);return0;}

看到了平台总线上面最基本的驱动注册方法:res = driver_register(&driver->driver);, 说明i2c 模块本身也是遵守平台总线机制。

3、i2c 驱动框架实验

加载驱动:insmod ft5x06_driver.ko,然后看串口打印日志如下:

其实就是回调了probe函数

四、知识点扩展

驱动层和client 端匹配机制

这个是之前的知识点,但是务必掌握,之前的参考资料:
驱动-设备树和驱动自动匹配
RK3568驱动指南|第七期-设备树-第65章 设备树下platform_device和platform_driver匹配实验
驱动-平台总线-probe

也就是说

  • probe方法的回调机制是怎样的,它一定是驱动层和client 相互之间匹配成功才会回调的。
  • 那么如何匹配的呢? 通过of_match_table函数定义规则,匹配client 端的compatible属性

probe 函数对应的 of_device_id 基本规则

如下:.probe = ft5x06_probe,函数定义

staticconststruct of_device_id ft5x06_id[]={{.compatible="my-ft5x06"},{/* Sentinel */},};

第二个参数为什么是一个 空的花括号:{ /* Sentinel */ }, 因为这个就是语法的结束标志,所以一定要有一个花括号{ }

MODULE_DEVICE_TABLE

如下定义了probe回调方法之后,执行了一个宏定义

staticconststruct of_device_id ft5x06_id[]={{.compatible="my-ft5x06"},{/* Sentinel */},};// 关键补充MODULE_DEVICE_TABLE(of,ft5x06_id);

为什么要了解这个,实际测试验证发现 没有这个居然无法匹配client端成功,怎么都不成功,i2c驱动也注册不成功。

后面我查了一下实战项目里面,公司项目里面 还都有这个宏定义添加的,如下:

查错方法

如上对于宏定义MODULE_DEVICE_TABLE没有添加导致的问题 还有其它实战项目中经常遇到的问题,这里给出一些查错方法。

ls /sys/bus/i2c/drivers/

命令:ls /sys/bus/i2c/drivers/就是查节点有木有,没有的话就是注册驱动失败了。
列表里必须出现 my-ft5x06

  • ✅ 存在:驱动注册成功,等待匹配设备;
  • ❌ 不存在:i2c_add_driver 内部隐性失败(极少,我们日志没有报错,可以暂时排除)`

ls /sys/bus/i2c/devices/

命令:ls /sys/bus/i2c/devices/,就是查地址,地址都没有说明设备树有问题。

正常应该看到 1-0038

  • 没有 1-0038 → dts 节点非法 / 冲突,内核没有创建 i2c_client;
  • 存在 1-0038,insmod 依然不进 probe → 匹配表问题(MODULE_DEVICE_TABLE)。

驱动缺失 MODULE_DEVICE_TABLE

staticconststruct of_device_id ft5x06_id[]={{.compatible="my-ft5x06"},{},};// 必须添加!!MODULE_DEVICE_TABLE(of,ft5x06_id);

没有这条宏,匹配表不会导出到模块信息,of_driver_match_device匹配失败,不会进入probe

总结

  • 这里就是i2c 驱动框架的一个总结、整理,对于遇到的问题也要有自己的解决问题思路。
  • i2c 框架理解,其实也就是一套平台总线的封装。
http://www.cnnetsun.cn/news/3520535.html

相关文章:

  • STL缩略图:Windows文件资源管理器3D模型预览终极解决方案
  • BiliTools终极指南:三分钟掌握免费B站下载神器
  • 【 C++ 】模板初阶 —— 函数模板、类模板
  • SplinterDB实战案例:构建高性能嵌入式应用的最佳实践
  • GHelper终极指南:华硕笔记本性能调校的免费轻量级解决方案
  • kableExtra高级技巧:创建响应式表格、添加脚注和分组标题的完整指南
  • 如何用QuickRecorder轻松录制macOS系统声音:从入门到精通的完整指南
  • 性能对比:charset_normalizer vs chardet,谁才是更快的编码检测器?
  • BiliTools终极指南:如何轻松打造你的个人B站资源库
  • Idle Master技术突破:C实现Steam自动挂卡的创新方案
  • SplinterDB高级特性:通知机制与异步操作的实战应用
  • 2026商用片头片尾纯音乐AI工具推荐对比
  • Flask-PyMongo社区生态:探索提升开发效率的实用工具与插件推荐
  • 猫抓cat-catch:5分钟掌握浏览器资源嗅探终极技巧
  • Golang —— map
  • 钉钉位置模拟终极指南:如何5分钟实现灵活办公打卡
  • PyTorch-CNN-Finetune错误排除指南:10个常见问题与解决方案
  • pytorch-cnn-finetune与原生PyTorch对比:为什么选择这个库?
  • Dify/FastGPT工作流深度调优:提示词工程与流程编排
  • shadcn-chatbot-kit社区贡献指南:如何参与开源项目开发
  • 如何快速解决Windows 10/11老游戏兼容性问题:dxwrapper完整解决方案
  • C 语言自学笔记 01:初始C语言
  • 新手必看:T-Header一键安装与常见问题解决方案大全
  • 终极免费方案:3步永久解锁IDM完整功能,享受5倍下载加速
  • learnr教程国际化(i18n)实战:多语言R学习材料制作
  • pytorch-cnn-finetune迁移学习实战:医学影像分类应用案例
  • 测试驱动开发(TDD)实践与API测试策略
  • ScrollScreenshot在企业中的应用:提升测试效率的完整方案
  • 3步掌握Outfit字体:让你的设计瞬间提升专业感的免费开源方案
  • 局域网设备扫描软件一键查看设备信息