PowerPC + Linux2.6.25平台下的I2C驱动架构分析
Sailor_forever sailing_9806#163.com
(本原创文章发表于Sailor_forever 的个人blog,未经本人许可,不得用于商业用途。任何个人、媒体、其他网站不得私自抄袭;网络媒体转载请注明出处,增加原文链接,否则属于侵权行为。如 有任何问题,请留言或者发邮件给sailing_9806#163.com)
http://blog.csdn.net/sailor_8318/archive/2010/09/25/5905988.aspx
【摘要】本文以PowerPC+Linux 2.6.25 平台为例,详细分析了I2C总线的驱动架构。首先介绍了I2C的总体架构,从用户的角度将其分为三个层面,不同的开发者只需要关注相应的层面即可。然后分析了主要数据结构及其之间的相互关系,接着分析了不同层的具体实现,最后以一款EEPEOM为例讲述了如何在用户空间访问I2C驱动。对于ARM + Linux平台,只有平台依赖层即总线适配器驱动有差异。
【关键字】PowerPC, I2C, i2c-core, adapter , i2c_algorithm, RTC, EEPROM
目录
1 I2C概述 3
2 I2C总体架构 3
2.1 硬件抽象层 3
2.2 平台依赖层 3
2.3 用户接口层 3
3 主要的数据结构 4
3.1 Adapter 4
3.2 I2c_algorithm 5
3.3 i2c_driver 5
3.4 Client 6
4 平台依赖层-总线适配器驱动 7
4.1 platform device 7
4.2 platform driver 9
4.3 Adapter及algorithm 12
5 硬件抽象层-I2C core 13
5.1 总线初始化 13
5.2 Adapter注册 15
5.3 驱动注册 16
5.4 数据传输 17
6 用户接口层-I2C设备驱动 18
6.1 统一的设备模型 18
6.1.1 关键数据结构 18
6.1.2 初始化 19
6.1.3 Open及release 21
6.1.4 数据收发 22
6.2 特定的设备驱动 26
6.2.1 关键数据结构 26
6.2.2 初始化 27
6.2.3 数据收发 29
7 驱动访问示例 29
7.1.1 写操作 29
7.1.2 读操作 31
8 参考鸣谢 33
1 I2C概述
I2C只有两条线,一条串行数据线:SDA,一条是时钟线SCL。I2C是一种多主机控制总线,同一总线上可允许多个master,即总线上的设备都有主动发起数据传输的可能,依靠线与逻辑来实现无损仲裁。但通常情况是总线上有个带CPU的master,其他设备被master访问。
2 I2C总体架构
在2.6的Linux内核中,I2C的驱动架构分为如下三个层次:硬件抽象层、平台依赖层和用户接口层。
2.1 硬件抽象层
i2c-core.h和i2c-core.c为其主体框架代码,提供了核心数据结构的定义、i2c适配器驱动和设备驱动的注册、注销管理等API。其为硬件平台无关层,向下屏蔽了物理总线适配器的差异,定义了统一的访问策略和接口;其向上提供了统一的接口,以便I2C设备驱动通过总线适配器进行数据收发。
2.2 平台依赖层
i2c总线适配器(adapter)就是一条i2c总线的控制器(所谓控制是相对于本CPU来说的),在物理上连接若干i2c设备。在Linux驱动中,每种处理器平台有自己的适配器驱动,属于平台移植相关层。每一个特定的硬件平台在i2c/busses/目录下都有一个adapter的实现,对于PowerPC平台来说,其是i2c-mpc.c。其按照核心层定义的接口实现了i2c_adapter,提供了具体的访问方式i2c_algorithm。
2.3 用户接口层
设备驱动层为用户接口层,其为用户提供了通过I2C总线访问具体设备的接口。
3 主要的数据结构
3.1 Adapter
Adapter是对某一条I2C总线的抽象,是特定总线的相关属性的集合。
http://lxr.linux.no/#linux+v2.6.25/include/linux/i2c.h#L312
312struct i2c_adapter {
313 struct module *owner;
314 unsigned int id;
315 unsigned int class;
316 const struct i2c_algorithm *algo; /* the algorithm to access the bus */
317 void *algo_data;
318
319 /* --- administration stuff. */
320 int (*client_register)(struct i2c_client *);
321 int (*client_unregister)(struct i2c_client *);
322
323 /* data fields that are valid for all devices */
324 u8 level; /* nesting level for lockdep */
325 struct mutex bus_lock; //
326 struct mutex clist_lock;
327
328 int timeout;
329 int retries;
330 struct device dev; /* the adapter device */
331
332 int nr; /*该成员描述了总线号*/
333 struct list_head clients; /* i2c_client结构链表,该结构包含device,driver和 adapter结构*/
334 char name[48];
335 struct completion dev_released;
336};
Algo是和底层硬件的接口,标识了具体的物理总线传输的实现。
Clients为使用该总线的client链表。
Nr为该适配器也就是某条I2C总线占据的全局编号。
bus_lock总线的互斥锁,防止总线冲突。
3.2 I2c_algorithm
http://lxr.linux.no/#linux+v2.6.25/include/linux/i2c.h#L291
291struct i2c_algorithm {
292 /* If an adapter algorithm can't do I2C-level access, set master_xfer
293 to NULL. If an adapter algorithm can do SMBus access, set
294 smbus_xfer. If set to NULL, the SMBus protocol is simulated
295 using common I2C messages */
296 /* master_xfer should return the number of messages successfully
297 processed, or a negative value on error */
298 int (*master_xfer)(struct i2c_adapter *adap,struct i2c_msg *msgs,
299 int num);
300 int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,
301 unsigned short flags, char read_write,
302 u8 command, int size, union i2c_smbus_data * data);
303
304 /* To determine what the adapter supports */
305 u32 (*functionality) (struct i2c_adapter *);
306};
主要就是master_xfer方法,其和具体的总线控制器相关,不同的CPU在实现上可能有差异。
3.3 i2c_driver
http://lxr.linux.no/#linux+v2.6.25/include/linux/i2c.h#L105
105struct i2c_driver {
106 int id;
107 unsigned int class;
108
109 /* Notifies the driver that a new bus has appeared. This routine
110 * can be used by the driver to test if the bus meets its conditions
111 * & seek for the presence of the chip(s) it supports. If found, it
112 * registers the client(s) that are on the bus to the i2c admin. via
113 * i2c_attach_client. (LEGACY I2C DRIVERS ONLY)
114 */
115 int (*attach_adapter)(struct i2c_adapter *);
116 int (*detach_adapter)(struct i2c_adapter *);
117
118 /* tells the driver that a client is about to be deleted & gives it
119 * the chance to remove its private data. Also, if the client struct
120 * has been dynamically allocated by the driver in the function above,
121 * it must be freed here. (LEGACY I2C DRIVERS ONLY)
122 */
123 int (*detach_client)(struct i2c_client *);
124
125 /* Standard driver model interfaces, for "new style" i2c drivers.
126 * With the driver model, device enumeration is NEVER done by drivers;
127 * it's done by infrastructure. (NEW STYLE DRIVERS ONLY)
128 */
129 int (*probe)(struct i2c_client *);
130 int (*remove)(struct i2c_client *);
131
132 /* driver model interfaces that don't relate to enumeration */
133 void (*shutdown)(struct i2c_client *);
134 int (*suspend)(struct i2c_client *, pm_message_t mesg);
135 int (*resume)(struct i2c_client *);
136
137 /* a ioctl like command that can be used to perform specific functions
138 * with the device.
139 */
140 int (*command)(struct i2c_client *client,unsigned int cmd, void *arg);
141
142 struct device_driver driver;
143};
Driver是为device服务的,i2c_driver注册时会扫描i2c bus上的设备,进行驱动和设备的绑定。主要有两种接口attach_adapter和probe,二者分别针对旧的和新式的驱动。
3.4 Client
http://lxr.linux.no/#linux+v2.6.25/include/linux/i2c.h#L168
168struct i2c_client {
169 unsigned short flags; /* div., see below */
170 unsigned short addr; /* chip address - NOTE: 7bit */
171 /* addresses are stored in the */
172 /* _LOWER_ 7 bits */
173 char name[I2C_NAME_SIZE];
174 struct i2c_adapter *adapter; /* the adapter we sit on */
175 struct i2c_driver *driver; /* and our access routines */
176 struct device dev; /* the device structure */
177 int irq; /* irq issued by device (or -1) */
178 char driver_name[KOBJ_NAME_LEN];
179 struct list_head list; /* DEPRECATED */
180 struct completion released;
181};
通常来说i2c_client对应着I2C总线上某个特定的slave或者是user space的某个用户对应,而此时的slave可以动态变化。
4 平台依赖层-总线适配器驱动
总线适配器驱动,本质上就是实现了具体的总线传输算法并向核心层注册了适配器。主要分为三个层面,platform device,platform driver及与I2C core的接口层。
Linux内核的所有适配器驱动程序都在driver/i2c/busses/目录下, MPC8xxx驱动是i2c-mpc.c。
4.1 platform device
2.6内核中硬件资源的注册都采用了platform device的机制。对于PowerPC来说,其硬件资源是通过DTS来描述的。
i2c@3000 {
#address-cells = <1>;
#size-cells = <0>;
cell-index = <0>;
compatible = "fsl-i2c";
reg = <0x3000 0x100>;
interrupts = <14 0x8>;
interrupt-parent = <&ipic>;
dfsrr;
};
i2c@3100 {
#address-cells = <1>;
#size-cells = <0>;
cell-index = <1>;
compatible = "fsl-i2c";
reg = <0x3100 0x100>;
interrupts = <15 0x8>;
interrupt-parent = <&ipic>;
dfsrr;
rtc@51 { //legacy I2C device,静态定义
device_type = "rtc";
compatible = "Philips,8563"; //设备类型
reg = <0x51>; //I2C地址
};
};
中断号及寄存器的基地址等信息会在设备树中描述了,此后只需利用platform_get_resource等标准接口自动获取即可,实现了驱动和资源的分离。cell-index标识了总线编号,也就是adapter的编号。
随后在系统启动阶段会解析DTB文件,将相关资源注册到Platform bus上。
http://lxr.linux.no/#linux+v2.6.25/arch/powerpc/sysdev/fsl_soc.c#L454
458static int __init fsl_i2c_of_init(void)
501 of_register_i2c_devices(np, i++);
429static void __init of_register_i2c_devices(struct device_node *adap_node,
430 int bus_num)
431{
432 struct device_node *node = NULL;
433
434 while ((node = of_get_next_child(adap_node, node))) {
435 struct i2c_board_info info = {};
436 const u32 *addr;
437 int len;
438
439 addr = of_get_property(node, "reg", &len);
440 if (!addr || len < sizeof(int) || *addr > (1 << 10) - 1) {
441 printk(KERN_WARNING "fsl_soc.c: invalid i2c device entry/n");
442 continue;
443 }
4