主页 > 互联网  > 

I2C驱动(九)--i2c_adapter控制器驱动框架编写

I2C驱动(九)--i2c_adapter控制器驱动框架编写
相关文章

I2C驱动(一) – I2C协议 I2C驱动(二) – SMBus协议 I2C驱动(三) – 驱动中的几个重要结构 I2C驱动(四) – I2C-Tools介绍 I2C驱动(五) – 通用驱动i2c-dev.c分析 I2C驱动(六) – I2C驱动程序模型 I2C驱动(七) – 编写I2C设备驱动之i2c_driver I2C驱动(八) – 编写I2C设备驱动之i2c_client

文章目录 相关文章参考资料一、回顾1.1 I2C驱动程序的层次1.2 I2C总线-设备-驱动模型 二、I2C_Adapter驱动框架2.1 重要结构2.2 驱动程序框架 三、总结


参考资料 Linux内核文档: Linux-4.9.88\Documentation\devicetree\bindings\i2c\i2c-gpio.txt Linux内核驱动程序:使用GPIO模拟I2C Linux-4.9.88\drivers\i2c\busses\i2c-gpio.c Linux内核真正的I2C控制器驱动程序 IMX6ULL: Linux-4.9.88\drivers\i2c\busses\i2c-imx.c 一、回顾 1.1 I2C驱动程序的层次

假设有一个epprom设备,应用层想要往里写 “abc” 三个字符,步骤如下: (1)应用层 应用层就是个大爷,他不管底层怎么实现,他只调用write往里写“abc”. (2)i2c设备驱动层 设备驱动层,知道要怎么发,他会分3次往里写:

S 0x50 0x0 ‘a’ p //发出start信号,往设备地址0x50的寄存器0x0写入’a’,发出停止信号pS 0x50 0x1 ‘a’ pS 0x50 0x2 ‘a’ p

(3)核心层 抽象出一些通用接口,辅助实现传输 (4)控制器层 真正做i2c读写操作

1.2 I2C总线-设备-驱动模型

前面我们已经分析知道i2c设备驱动基于i2c总线-设备-驱动模型,可以分为i2c_client和i2c_driver两边,并分别讲述了二者的编写过程。其中i2c_client结构中包含一个i2c_adapter类型变量,也就是这个i2c设备对应的控制器。下面介绍i2c_adapter的框架和编写过程。

二、I2C_Adapter驱动框架 2.1 重要结构

(1)i2c_adapter 它代表一个i2c控制器,最重要的两个成员:*algo 里面提供了各种传输函数;nr表示第几条i2c总线。

struct i2c_adapter { ... const struct i2c_algorithm *algo; //i2c算法,里面包含有传输函数 ... int nr; //表示第几条i2c总线 ... };

(2)i2c_algorithm

struct i2c_algorithm { /* 这是最重要的函数,它实现了一般的I2C传输,用来传输一个或多个i2c_msg */ int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs, int num); /* 实现SMBus传输,如果不提供这个函数,SMBus传输会使用master_xfer来模拟 */ int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data *data); /* 返回所支持的flags:各类I2C_FUNC_* */ u32 (*functionality) (struct i2c_adapter *); #if IS_ENABLED(CONFIG_I2C_SLAVE) /* 有些I2C Adapter也可工作与Slave模式,用来实现或模拟一个I2C设备 * reg_slave就是让把一个i2c_client注册到I2C Adapter,换句话说就是让这 * 个I2C Adapter模拟该i2c_client; unreg_slave:反注册 */ int (*reg_slave)(struct i2c_client *client); int (*unreg_slave)(struct i2c_client *client); #endif }; 2.2 驱动程序框架

(1)怎么写驱动?

还是一样的套路:分配、设置、注册i2c_adapter结构体:

i2c_adapter的核心是i2c_algorithm i2c_algorithm的核心是master_xfer

(2)在哪里分配、设置、注册i2c_adapter结构体?

使用万能的驱动程序结构:platform总线-设备-驱动模型,和i2c总线-设备-驱动模型是同一个道理,程序分为platform_device 和 platform_driver两边,platform_device 也可以是设备树定义,二者进行匹配,成功就调用probe函数。probe函数中我们分配、设备、注册一个i2c_adpater结构体。 (3)编写程序 1. 添加设备树 在根节点下添加

/{ i2c-bus-virtual{ compatible = "100ask, i2c-bus-virtual"; }; }

2. 编写i2c_adapter驱动框架 参考gpio-i2c.c

#include <linux/completion.h> #include <linux/debugfs.h> #include <linux/delay.h> #include <linux/gpio/consumer.h> #include <linux/i2c-algo-bit.h> #include <linux/i2c.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/module.h> #include <linux/of.h> #include <linux/platform_data/i2c-gpio.h> #include <linux/platform_device.h> #include <linux/slab.h> static struct i2c_adapter *g_adapter; /* 核心:传输函数 */ 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]; } return num; } /* 返回可支持的功能函数 */ 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; } const struct i2c_algorithm i2c_bus_virtual_algo = { .master_xfer = i2c_bus_virtual_master_xfer, .functionality = i2c_bus_virtual_func, }; 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; 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); //不管adap->nr原来是什么,都动态设置adap->nr // i2c_add_numbered_adapter(g_adapter); //如果adap->nr == -1 则动态分配nr; 否则使用该nr return 0; } static int i2c_bus_virtual_remove(struct platform_device *pdev) { i2c_del_adapter(g_adapter); return 0; } static const struct of_device_id i2c_bus_virtual_dt_ids[] = { { patible = "100ask,i2c-bus-virtual", }, { /* sentinel */ } }; /* 构造platform_driver结构体 */ static struct platform_driver i2c_bus_virtual_driver = { .driver = { .name = "i2c-bus-virtual", .of_match_table = of_match_ptr(i2c_bus_virtual_dt_ids), }, .probe = i2c_bus_virtual_probe, .remove = i2c_bus_virtual_remove, }; /* 入口函数 */ static int __init i2c_bus_virtual_init(void) { int ret; /* 注册platform_driver结构 */ ret = platform_driver_register(&i2c_bus_virtual_driver); if (ret) printk(KERN_ERR "i2c-gpio: probe failed: %d\n", ret); return ret; } /*出口函数 */ static void __exit i2c_bus_virtual_exit(void) { /* 卸载platform_driver结构 */ platform_driver_unregister(&i2c_bus_virtual_driver); } module_init(i2c_bus_virtual_init); module_exit(i2c_bus_virtual_exit); MODULE_AUTHOR("zhongpz"); MODULE_LICENSE("GPL"); 三、总结

本文介绍了i2c_adapter的结构和编写步骤,并编写出了驱动框架。

标签:

I2C驱动(九)--i2c_adapter控制器驱动框架编写由讯客互联互联网栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“I2C驱动(九)--i2c_adapter控制器驱动框架编写