提示Linux驱动-i2c 驱动框架编写文章目录前言一、参考资料二、相关文件三、驱动框架编写1、设备树-client 端配置2、i2c 驱动框架框架编码对比平台总线-i2c_add_driver3、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{statusokay;myft5x06:my-ft5x0638{compatiblemy-ft5x06;reg0x38;};};这里最重要的不就是compatible属性的值嘛2、i2c 驱动框架框架编码框架编码如下#includelinux/init.h#includelinux/module.h#includelinux/i2c.h#includelinux/of_device.hintft5x06_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[]{{.compatiblemy-ft5x06},{/* Sentinel */},};// 关键补充MODULE_DEVICE_TABLE(of,ft5x06_id);staticstruct i2c_driver ft5x06_driver{.driver{.ownerTHIS_MODULE,.namemy-ft5x06,.of_match_tableft5x06_id,},.probeft5x06_probe,.removeft5x06_remove,};staticint__initft5x06_driver_init(void){intret;reti2c_add_driver(ft5x06_driver);if(ret0){printk(KERN_ERRi2c_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.hexterninti2c_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;/* Cant 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.ownerowner;driver-driver.busi2c_bus_type;INIT_LIST_HEAD(driver-clients);/* When registration returns, the driver core * will have called probe() for all matching-but-unbound devices. */resdriver_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[]{{.compatiblemy-ft5x06},{/* Sentinel */},};第二个参数为什么是一个 空的花括号{ /* Sentinel */ } 因为这个就是语法的结束标志所以一定要有一个花括号{ }。MODULE_DEVICE_TABLE如下定义了probe回调方法之后执行了一个宏定义staticconststruct of_device_id ft5x06_id[]{{.compatiblemy-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-0038insmod 依然不进 probe → 匹配表问题MODULE_DEVICE_TABLE。驱动缺失 MODULE_DEVICE_TABLEstaticconststruct of_device_id ft5x06_id[]{{.compatiblemy-ft5x06},{},};// 必须添加MODULE_DEVICE_TABLE(of,ft5x06_id);没有这条宏匹配表不会导出到模块信息of_driver_match_device匹配失败不会进入probe。总结这里就是i2c 驱动框架的一个总结、整理对于遇到的问题也要有自己的解决问题思路。i2c 框架理解其实也就是一套平台总线的封装。