【嵌入式Linux学习七步曲之第五篇 Linux内核及驱动编程】PowerPC + Linux2.6.25平台下的I2C驱动架构分析

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

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值