【嵌入式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                }
 444
 445                info.irq = irq_of_parse_and_map(node, 0);
 446                if (info.irq == NO_IRQ)
 447                        info.irq = -1;
 448
 449                if (of_find_i2c_driver(node, &info) < 0)
 450                        continue;
 451
 452                info.addr = *addr;
 453
 454                i2c_register_board_info(bus_num, &info, 1);
 455        }
 456}
 397static struct i2c_driver_device i2c_devices[] __initdata = {
 398        {"ricoh,rs5c372a", "rtc-rs5c372", "rs5c372a",},
 399        {"ricoh,rs5c372b", "rtc-rs5c372", "rs5c372b",},
 400        {"ricoh,rv5c386",  "rtc-rs5c372", "rv5c386",},
 401        {"ricoh,rv5c387a", "rtc-rs5c372", "rv5c387a",},
 402        {"dallas,ds1307",  "rtc-ds1307",  "ds1307",},
 403        {"dallas,ds1337",  "rtc-ds1307",  "ds1337",},
 404        {"dallas,ds1338",  "rtc-ds1307",  "ds1338",},
 405        {"dallas,ds1339",  "rtc-ds1307",  "ds1339",},
 406        {"dallas,ds1340",  "rtc-ds1307",  "ds1340",},
 407        {"stm,m41t00",     "rtc-ds1307",  "m41t00"},
 408        {"dallas,ds1374",  "rtc-ds1374",  "rtc-ds1374",},
 409};
 410
在i2c_devices列表里描述了那些采用传统的I2C驱动的设备列表。同时DTS文件中也需要描述,二者会利用of_find_i2c_driver进行匹配。

 411static int __init of_find_i2c_driver(struct device_node *node,
 412                                     struct i2c_board_info *info)
 413{
 414        int i;
 415
 416        for (i = 0; i < ARRAY_SIZE(i2c_devices); i++) {
 417                if (!of_device_is_compatible(node, i2c_devices[i].of_device))
 418                        continue;
 419                if (strlcpy(info->driver_name, i2c_devices[i].i2c_driver,
 420                            KOBJ_NAME_LEN) >= KOBJ_NAME_LEN ||
 421                    strlcpy(info->type, i2c_devices[i].i2c_type,
 422                            I2C_NAME_SIZE) >= I2C_NAME_SIZE)
 423                        return -ENOMEM;
 424                return 0;
 425        }
 426        return -ENODEV;
 427}

4.2    platform driver
394
 395/* Structure for a device driver */
 396static struct platform_driver fsl_i2c_driver = {
 397        .probe = fsl_i2c_probe,
 398        .remove = fsl_i2c_remove,
 399        .driver = {
 400                .owner = THIS_MODULE,
 401                .name = "fsl-i2c",  //匹配因子
 402        },
 403};
 404
 405static int __init fsl_i2c_init(void)
 406{
 407        return platform_driver_register(&fsl_i2c_driver);
 408}
 409
 410static void __exit fsl_i2c_exit(void)
 411{
 412        platform_driver_unregister(&fsl_i2c_driver);
 413}
 414
 415module_init(fsl_i2c_init);
 416module_exit(fsl_i2c_exit);

fsl_i2c_driver注册时会扫描platform bus上的所有设备,匹配因子是fsl-i2c,匹配成功后调用fsl_i2c_probe将设备和驱动绑定起来,具体过程参加《详解Linux2.6内核中基于platform机制的驱动模型》,随后向系统注册一个adapter。
http://blog.csdn.net/sailor_8318/archive/2010/01/29/5267698.aspx

318static int fsl_i2c_probe(struct platform_device *pdev)
 319{
 320        int result = 0;
 321        struct mpc_i2c *i2c;
 322        struct fsl_i2c_platform_data *pdata;
 323        struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 324
 325        pdata = (struct fsl_i2c_platform_data *) pdev->dev.platform_data;
 326
 327        i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
 328        if (!i2c)
 329                return -ENOMEM;
 330
 331        i2c->irq = platform_get_irq(pdev, 0);
 332        if (i2c->irq < 0) {
 333                result = -ENXIO;
 334                goto fail_get_irq;
 335        }
 336        i2c->flags = pdata->device_flags;
 337        init_waitqueue_head(&i2c->queue);
 338
 339        i2c->base = ioremap((phys_addr_t)r->start, MPC_I2C_REGION);
 340
 341        if (!i2c->base) {
 342                printk(KERN_ERR "i2c-mpc - failed to map controller/n");
 343                result = -ENOMEM;
 344                goto fail_map;
 345        }
 346
 347        if (i2c->irq != 0)
 348                if ((result = request_irq(i2c->irq, mpc_i2c_isr,
 349                                          IRQF_SHARED, "i2c-mpc", i2c)) < 0) {
 350                        printk(KERN_ERR
 351                               "i2c-mpc - failed to attach interrupt/n");
 352                        goto fail_irq;
 353                }
 354
 355        mpc_i2c_setclock(i2c);
 356        platform_set_drvdata(pdev, i2c);
 357
 358        i2c->adap = mpc_ops;
 359        i2c->adap.nr = pdev->id;
 360        i2c_set_adapdata(&i2c->adap, i2c);
 361        i2c->adap.dev.parent = &pdev->dev;
 362        if ((result = i2c_add_numbered_adapter(&i2c->adap)) < 0) {
 363                printk(KERN_ERR "i2c-mpc - failed to add adapter/n");
 364                goto fail_add;
 365        }
 366
 367        return result;
 368
 369      fail_add:
 370        if (i2c->irq != 0)
 371                free_irq(i2c->irq, i2c);
 372      fail_irq:
 373        iounmap(i2c->base);
 374      fail_map:
 375      fail_get_irq:
 376        kfree(i2c);
 377        return result;
 378};
 379
 380static int fsl_i2c_remove(struct platform_device *pdev)
 381{
 382        struct mpc_i2c *i2c = platform_get_drvdata(pdev);
 383
 384        i2c_del_adapter(&i2c->adap);
 385        platform_set_drvdata(pdev, NULL);
 386
 387        if (i2c->irq != 0)
 388                free_irq(i2c->irq, i2c);
 389
 390        iounmap(i2c->base);
 391        kfree(i2c);
 392        return 0;
 393};
pdev->id为platform data中的devid,为I2C的总线编号,其在设备树文件中描述。

PowerPC的adapter驱动使用了i2c_add_numbered_adapter()注册,总线号最初保存在 platform_data中。

4.3    Adapter及algorithm
这一层主要是定义了关键的数据结构adapter和algorithm。

http://lxr.linux.no/#linux+v2.6.25/drivers/i2c/busses/i2c-mpc.c#L309
309static struct i2c_adapter mpc_ops = {
 310        .owner = THIS_MODULE,
 311        .name = "MPC adapter",
 312        .id = I2C_HW_MPC107,
 313        .algo = &mpc_algo,
 314        .class = I2C_CLASS_HWMON,
 315        .timeout = 1,
 316};

304static const struct i2c_algorithm mpc_algo = {
 305        .master_xfer = mpc_xfer,
 306        .functionality = mpc_functionality,
 307};
 308

http://lxr.linux.no/#linux+v2.6.25/drivers/i2c/busses/i2c-mpc.c#L256
256static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
 257{
 258        struct i2c_msg *pmsg;
 259        int i;
 260        int ret = 0;
 261        unsigned long orig_jiffies = jiffies;
 262        struct mpc_i2c *i2c = i2c_get_adapdata(adap);
 263
 264        mpc_i2c_start(i2c);
 265
 266        /* Allow bus up to 1s to become not busy */  //一定程度上避免总线冲突,收发数据前先查询总线状态
 267        while (readb(i2c->base + MPC_I2C_SR) & CSR_MBB) {
 268                if (signal_pending(current)) {
 269                        pr_debug("I2C: Interrupted/n");
 270                        writeccr(i2c, 0);
 271                        return -EINTR;
 272                }
 273                if (time_after(jiffies, orig_jiffies + HZ)) {
 274                        pr_debug("I2C: timeout/n");
 275                        if (readb(i2c->base + MPC_I2C_SR) ==
 276                            (CSR_MCF | CSR_MBB | CSR_RXAK))
 277                                mpc_i2c_fixup(i2c);
 278                        return -EIO;
 279                }
 280                schedule();
 281        }
 282
 283        for (i = 0; ret >= 0 && i < num; i++) {
 284                pmsg = &msgs[i];
 285                pr_debug("Doing %s %d bytes to 0x%02x - %d of %d messages/n",
 286                         pmsg->flags & I2C_M_RD ? "read" : "write",
 287                         pmsg->len, pmsg->addr, i + 1, num);
 288                if (pmsg->flags & I2C_M_RD)
 289                        ret =
 290                            mpc_read(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);
 291                else
 292                        ret =
 293                            mpc_write(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);
 294        }
 295        mpc_i2c_stop(i2c);
 296        return (ret < 0) ? ret : num;
 297}


5    硬件抽象层-I2C core
5.1    总线初始化
http://lxr.linux.no/#linux+v2.6.25/drivers/i2c/i2c-core.c#L914
 885static int __init i2c_init(void)
 886{
 887        int retval;
 888
 889        retval = bus_register(&i2c_bus_type);
 890        if (retval)
 891                return retval;
 892        retval = class_register(&i2c_adapter_class);
 893        if (retval)
 894                goto bus_err;
 895        retval = i2c_add_driver(&dummy_driver);
 896        if (retval)
 897                goto class_err;
 898        return 0;
 899
 900class_err:
 901        class_unregister(&i2c_adapter_class);
 902bus_err:
 903        bus_unregister(&i2c_bus_type);
 904        return retval;
 905}
 906
 907static void __exit i2c_exit(void)
 908{
 909        i2c_del_driver(&dummy_driver);
 910        class_unregister(&i2c_adapter_class);
 911        bus_unregister(&i2c_bus_type);
 912}
 913
 914subsys_initcall(i2c_init);
 915module_exit(i2c_exit);

关于被subsys_initcall修饰的i2c_init何时初始化,请参考下文《详解Linux2.6内核中基于platform机制的驱动模型》
http://blog.csdn.net/sailor_8318/archive/2010/01/29/5267698.aspx
此时platform bus及platform device已经注册完毕,因此I2C控制器的相关资源已经就绪。

该过程主要完成了sysfs总线结构,最终形成如下结构:
/sys/bus/i2c/
|-- devices
|-- drivers
|   |-- dummy
|      |-- bind
|      |-- uevent
|      `-- unbind
|-- drivers_autoprobe
|-- drivers_probe
`-- uevent

/sys/class/i2c-adapter/
dummy_driver 仅仅是注册了一个空的设备驱动,注册驱动时会遍历加载/sys/class/i2c-adapter/中的所有设备,该过程在初始化总线过程中完成, /sys/class/i2c-adapter/基本为空,所以我认为这里的驱动注册只是验证i2c总线结构的完整性考虑的。

5.2    Adapter注册
在 kernel中提供了两个adapter注册接口,分别为i2c_add_adapter()和i2c_add_numbered_adapter()。 由于在系统中可能存在多个adapter,因此每一条I2C总线对应一个编号,下文中称为I2C总线号。对于i2c_add_adapter()而言, 它使用的是动态总线号,即由系统给其分配一个总线号,而i2c_add_numbered_adapter()则是自己指定总线号,如果这个总线号非法或者是被占用,就会注册失败。

http://lxr.linux.no/#linux+v2.6.25/drivers/i2c/i2c-core.c#L403

403static int i2c_register_adapter(struct i2c_adapter *adap)
 404{
 405        int res = 0, dummy;
 406
 407        mutex_init(&adap->bus_lock);
 408        mutex_init(&adap->clist_lock);
 409        INIT_LIST_HEAD(&adap->clients);
 410
 411        mutex_lock(&core_lock);
 412
 413        /* Add the adapter to the driver core.
 414         * If the parent pointer is not set up,
 415         * we add this adapter to the host bus.
 416         */
 417        if (adap->dev.parent == NULL) {
 418                adap->dev.parent = &platform_bus;
 419                pr_debug("I2C adapter driver [%s] forgot to specify "
 420                         "physical device/n", adap->name);
 421        }
 422        sprintf(adap->dev.bus_id, "i2c-%d", adap->nr);
 423        adap->dev.release = &i2c_adapter_dev_release;
 424        adap->dev.class = &i2c_adapter_class;
 425        res = device_register(&adap->dev);
 426        if (res)
 427                goto out_list;
 428
 429        dev_dbg(&adap->dev, "adapter [%s] registered/n", adap->name);
 430
 431        /* create pre-declared device nodes for new-style drivers */
 432        if (adap->nr < __i2c_first_dynamic_bus_num)
 433                i2c_scan_static_board_info(adap); //完成静态定义的I2C设备的扫描,将设备和adapter挂上钩,即将设备挂在总线上
 434
 435        /* let legacy drivers scan this bus for matching devices */
 436        dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap,
 437                                 i2c_do_add_adapter); /*探测总线上的所有i2c设备驱动,如果匹配则完成client、driver、device、adapter的绑定*/ 
 438
 439out_unlock:
 440        mutex_unlock(&core_lock);
 441        return res;
 442
 443out_list:
 444        idr_remove(&i2c_adapter_idr, adap->nr);
 445        goto out_unlock;
 446}

5.3    驱动注册
http://lxr.linux.no/#linux+v2.6.25/drivers/i2c/i2c-core.c#L635
635int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
 636{
 637        int res;
 638
 639        /* new style driver methods can't mix with legacy ones */
 640        if (is_newstyle_driver(driver)) {
 641                if (driver->attach_adapter || driver->detach_adapter
 642                                || driver->detach_client) {
 643                        printk(KERN_WARNING
 644                                        "i2c-core: driver [%s] is confused/n",
 645                                        driver->driver.name);
 646                        return -EINVAL;
 647                }
 648        }
 649
 650        /* add the driver to the list of i2c drivers in the driver core */
 651        driver->driver.owner = owner;
 652        driver->driver.bus = &i2c_bus_type;
 653
 654        /* for new style drivers, when registration returns the driver core
 655         * will have called probe() for all matching-but-unbound devices.
 656         */
 657        res = driver_register(&driver->driver);
 658        if (res)
 659                return res;
 660
 661        mutex_lock(&core_lock);
 662
 663        pr_debug("i2c-core: driver [%s] registered/n", driver->driver.name);
 664
 665        /* legacy drivers scan i2c busses directly */
 666        if (driver->attach_adapter) {
 667                struct i2c_adapter *adapter;
 668
 669                down(&i2c_adapter_class.sem);
 670                list_for_each_entry(adapter, &i2c_adapter_class.devices,
 671                                    dev.node) {
 672                        driver->attach_adapter(adapter);
 673                }
 674                up(&i2c_adapter_class.sem);
 675        }
 676
 677        mutex_unlock(&core_lock);
 678        return 0;
 679}
 680EXPORT_SYMBOL(i2c_register_driver);

两种注册方式。对于new style驱动,将采用内核通用的驱动模型,其流程和platform driver的注册过程类似,请请参考下文《详解Linux2.6内核中基于platform机制的驱动模型》
http://blog.csdn.net/sailor_8318/archive/2010/01/29/5267698.aspx

而对于legacy driver,是如何匹配注册的呢?TBD

5.4    数据传输
917/* ----------------------------------------------------
 918 * the functional interface to the i2c busses.
 919 * ----------------------------------------------------
 920 */
 921
 922int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num)
 923{
 924        int ret;
 925
 926        if (adap->algo->master_xfer) {
 927#ifdef DEBUG
 928                for (ret = 0; ret < num; ret++) {
 929                        dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
 930                                "len=%d%s/n", ret, (msgs[ret].flags & I2C_M_RD)
 931                                ? 'R' : 'W', msgs[ret].addr, msgs[ret].len,
 932                                (msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");
 933                }
 934#endif
 935
 936                if (in_atomic() || irqs_disabled()) { //原子上下文或者中断禁止时不能获取自旋锁,防止休眠死锁,只能试探锁
 937                        ret = mutex_trylock(&adap->bus_lock);
 938                        if (!ret)
 939                                /* I2C activity is ongoing. */
 940                                return -EAGAIN;
 941                } else {
 942                        mutex_lock_nested(&adap->bus_lock, adap->level);
 943                }
 944
 945                ret = adap->algo->master_xfer(adap,msgs,num);
 946                mutex_unlock(&adap->bus_lock);
 947
 948                return ret;
 949        } else {
 950                dev_dbg(&adap->dev, "I2C level transfers not supported/n");
 951                return -ENOSYS;
 952        }
 953}
 954EXPORT_SYMBOL(i2c_transfer);

核心层提供的通用数据收发接口,屏蔽了底层差异。利用adapter进行数据传输前先获得互斥锁,因此保证只有一个调用者占用总线,这样数据传输才是原子的。多个msgs可以一次传输完毕,因此对于读操作,两次I2C总线的访问(先写后读)需要在一个io ctrl中处理完毕

6    用户接口层-I2C设备驱动
6.1    统一的设备模型
此驱动模型是针对I2C控制器的,因为对I2C slave的寻址是通过报文的内容来实现的,而对于I2C控制器来说,slave的地址仅仅是某个具体的报文而已,对控制器来说是透明的,因此用户空间访问的设备本质上就是I2C控制器。
6.1.1    关键数据结构
550static struct i2c_driver i2cdev_driver = {
 551        .driver = {
 552                .name   = "dev_driver",
 553        },
 554        .id             = I2C_DRIVERID_I2CDEV,
 555        .attach_adapter = i2cdev_attach_adapter,
 556        .detach_adapter = i2cdev_detach_adapter,
 557        .detach_client  = i2cdev_detach_client,
 558};
定义了一个标准的i2c_driver。

  41/*
  42 * An i2c_dev represents an i2c_adapter ... an I2C or SMBus master, not a
  43 * slave (i2c_client) with which messages will be exchanged.  It's coupled
  44 * with a character special file which is accessed by user mode drivers.
  45 *
  46 * The list of i2c_dev structures is parallel to the i2c_adapter lists
  47 * maintained by the driver model, and is updated using notifications
  48 * delivered to the i2cdev_driver.
  49 */
  50struct i2c_dev {
  51        struct list_head list;
  52        struct i2c_adapter *adap;
  53        struct device *dev;
  54};
  55
  56#define I2C_MINORS      256
  57static LIST_HEAD(i2c_dev_list);
  58static DEFINE_SPINLOCK(i2c_dev_list_lock);
定义了一个i2c_dev列表,每个adapter对应一个i2c_dev。

478static const struct file_operations i2cdev_fops = {
 479        .owner          = THIS_MODULE,
 480        .llseek         = no_llseek,
 481        .read           = i2cdev_read,
 482        .write          = i2cdev_write,
 483        .ioctl          = i2cdev_ioctl,
 484        .open           = i2cdev_open,
 485        .release        = i2cdev_release,
 486};
 487
任意一个需要和用户空间通信的驱动必备的数据结构,其定义了具体的读写操作方法。

6.1.2    初始化
http://lxr.linux.no/#linux+v2.6.25/drivers/i2c/i2c-dev.c#L607
566static int __init i2c_dev_init(void)
 567{
 568        int res;
 569
 570        printk(KERN_INFO "i2c /dev entries driver/n");
 571
 572        res = register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops);
 573        if (res)
 574                goto out;
 575
 576        i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");
 577        if (IS_ERR(i2c_dev_class))
 578                goto out_unreg_chrdev;
 579
 580        res = i2c_add_driver(&i2cdev_driver);
 581        if (res)
 582                goto out_unreg_class;
 583
 584        return 0;
 585
 586out_unreg_class:
 587        class_destroy(i2c_dev_class);
 588out_unreg_chrdev:
 589        unregister_chrdev(I2C_MAJOR, "i2c");
 590out:
 591        printk(KERN_ERR "%s: Driver Initialisation failed/n", __FILE__);
 592        return res;
 593}
 594
 595static void __exit i2c_dev_exit(void)
 596{
 597        i2c_del_driver(&i2cdev_driver);
 598        class_destroy(i2c_dev_class);
 599        unregister_chrdev(I2C_MAJOR,"i2c");
 600}
首先注册了一个字符型设备驱动,然后注册i2c_driver,将驱动和adapter绑定起来,匹配成功后将调用i2c_driver 的attach_adapter 方法,即i2cdev_attach_adapter, 建立dev设备节点,并维护了一个i2c_dev链表保存设备节点和adapter的关系。


http://lxr.linux.no/#linux+v2.6.25/drivers/i2c/i2c-dev.c#L498
498static int i2cdev_attach_adapter(struct i2c_adapter *adap)
 499{
 500        struct i2c_dev *i2c_dev;
 501        int res;
 502
 503        i2c_dev = get_free_i2c_dev(adap);  //添加一个adapter到i2c_dev列表中
 504        if (IS_ERR(i2c_dev))
 505                return PTR_ERR(i2c_dev);
 506
 507        /* register this i2c device with the driver core */
 508        i2c_dev->dev = device_create(i2c_dev_class, &adap->dev,
 509                                     MKDEV(I2C_MAJOR, adap->nr),
 510                                     "i2c-%d", adap->nr);
 511        if (IS_ERR(i2c_dev->dev)) {
 512                res = PTR_ERR(i2c_dev->dev);
 513                goto error;
 514        }
 515        res = device_create_file(i2c_dev->dev, &dev_attr_name);
 516        if (res)
 517                goto error_destroy;
 518
 519        pr_debug("i2c-dev: adapter [%s] registered as minor %d/n",
 520                 adap->name, adap->nr);
 521        return 0;
 522error_destroy:
 523        device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));
 524error:
 525        return_i2c_dev(i2c_dev);
 526        return res;
 527}
以I2C_MAJOR和adap->nr为主从设备号注册设备节点,如果系统有udev或者是hotplug,那么就么在/dev下自动创建相关的设备节点了

6.1.3    Open及release
431static int i2cdev_open(struct inode *inode, struct file *file)
 432{
 433        unsigned int minor = iminor(inode);
 434        struct i2c_client *client;
 435        struct i2c_adapter *adap;
 436        struct i2c_dev *i2c_dev;
 437
 438        i2c_dev = i2c_dev_get_by_minor(minor); //由次设备号获得i2c_dev即可获得对应的adapter
 439        if (!i2c_dev)
 440                return -ENODEV;
 441
 442        adap = i2c_get_adapter(i2c_dev->adap->nr);  //对module引用进行计数
 443        if (!adap)
 444                return -ENODEV;
 445
 446        /* This creates an anonymous i2c_client, which may later be
 447         * pointed to some address using I2C_SLAVE or I2C_SLAVE_FORCE.
 448         *
 449         * This client is ** NEVER REGISTERED ** with the driver model
 450         * or I2C core code!!  It just holds private copies of addressing
 451         * information and maybe a PEC flag.
 452         */
 453        client = kzalloc(sizeof(*client), GFP_KERNEL);
 454        if (!client) {
 455                i2c_put_adapter(adap);
 456                return -ENOMEM;
 457        }
 458        snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);
 459        client->driver = &i2cdev_driver;
 460
 461        client->adapter = adap;
 462        file->private_data = client;
 463
 464        return 0;
 465}

Open操作是用户空间程序和内核驱动交换的第一步,最终返回给用户空间的就是struct file结构体。对于I2C 驱动来说,用户空间所获得的就是client这个关键信息,在其中可以找到所有有关的信息如client所在的adapter及i2c_driver。此i2c_client并没有遵循设备模型的方式注册进系统,在sys下面没有任何信息。
6.1.4    数据收发
对于I2C驱动来说,数据收发有两种途径,read/write或者ioctl方式。
对于read/write方式来说,必须先通过ioctl的I2C_SLAVE设置从设备的地址。随后再通过read/write对相应的slave直接进行数据收发。

117/*
 118 * After opening an instance of this character special file, a file
 119 * descriptor starts out associated only with an i2c_adapter (and bus).
 120 *
 121 * Using the I2C_RDWR ioctl(), you can then *immediately* issue i2c_msg
 122 * traffic to any devices on the bus used by that adapter.  That's because
 123 * the i2c_msg vectors embed all the addressing information they need, and
 124 * are submitted directly to an i2c_adapter.  However, SMBus-only adapters
 125 * don't support that interface.
 126 *
 127 * To use read()/write() system calls on that file descriptor, or to use
 128 * SMBus interfaces (and work with SMBus-only hosts!), you must first issue
 129 * an I2C_SLAVE (or I2C_SLAVE_FORCE) ioctl.  That configures an anonymous
 130 * (never registered) i2c_client so it holds the addressing information
 131 * needed by those system calls and by this SMBus interface.
 132 */
 133
 134static ssize_t i2cdev_read (struct file *file, char __user *buf, size_t count,
 135                            loff_t *offset)
 136{

read/write与用户空间的接口是buf和count,为收发的相应数据指针和数据长度。
SMBus只能利用read/write方式和用户空间通信??

对于ioctl方式,相关的cmd是I2C_RDWR

203static int i2cdev_ioctl(struct inode *inode, struct file *file,
 204                unsigned int cmd, unsigned long arg)
 205{
 206        struct i2c_client *client = (struct i2c_client *)file->private_data;
 207        struct i2c_rdwr_ioctl_data rdwr_arg;
 208        struct i2c_smbus_ioctl_data data_arg;
 209        union i2c_smbus_data temp;
 210        struct i2c_msg *rdwr_pa;
 211        u8 __user **data_ptrs;
 212        int i,datasize,res;
 213        unsigned long funcs;

255        case I2C_RDWR:
 256                if (copy_from_user(&rdwr_arg,
 257                                   (struct i2c_rdwr_ioctl_data __user *)arg,
 258                                   sizeof(rdwr_arg)))
 259                        return -EFAULT;
 260
 261                /* Put an arbitrary limit on the number of messages that can
 262                 * be sent at once */
 263                if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)
 264                        return -EINVAL;
 265
 266                rdwr_pa = (struct i2c_msg *)
 267                        kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg),
 268                        GFP_KERNEL);
 269
 270                if (rdwr_pa == NULL) return -ENOMEM;
 271
 272                if (copy_from_user(rdwr_pa, rdwr_arg.msgs,
 273                                   rdwr_arg.nmsgs * sizeof(struct i2c_msg))) {
 274                        kfree(rdwr_pa);
 275                        return -EFAULT;
 276                }
 277
 278                data_ptrs = kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL);
 279                if (data_ptrs == NULL) {
 280                        kfree(rdwr_pa);
 281                        return -ENOMEM;
 282                }
 283
 284                res = 0;
 285                for( i=0; i<rdwr_arg.nmsgs; i++ ) {
 286                        /* Limit the size of the message to a sane amount;
 287                         * and don't let length change either. */
 288                        if ((rdwr_pa[i].len > 8192) ||
 289                            (rdwr_pa[i].flags & I2C_M_RECV_LEN)) {
 290                                res = -EINVAL;
 291                                break;
 292                        }
 293                        data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf;
 294                        rdwr_pa[i].buf = kmalloc(rdwr_pa[i].len, GFP_KERNEL);
 295                        if(rdwr_pa[i].buf == NULL) {
 296                                res = -ENOMEM;
 297                                break;
 298                        }
 299                        if(copy_from_user(rdwr_pa[i].buf,
 300                                data_ptrs[i],
 301                                rdwr_pa[i].len)) {
 302                                        ++i; /* Needs to be kfreed too */
 303                                        res = -EFAULT;
 304                                break;
 305                        }
 306                }
 307                if (res < 0) {
 308                        int j;
 309                        for (j = 0; j < i; ++j)
 310                                kfree(rdwr_pa[j].buf);
 311                        kfree(data_ptrs);
 312                        kfree(rdwr_pa);
 313                        return res;
 314                }
 315
//上述所有操作就是将用户空间的数据拷贝到内核空间。组织成以rdwr_pa为首地址的nmsgs个msg
 316                res = i2c_transfer(client->adapter,
 317                        rdwr_pa,
 318                        rdwr_arg.nmsgs);
 319                while(i-- > 0) {
 320                        if( res>=0 && (rdwr_pa[i].flags & I2C_M_RD)) {
 321                                if(copy_to_user(  //如果是读操作,再将内核空间中缓存的数据拷贝到用户空间
 322                                        data_ptrs[i],
 323                                        rdwr_pa[i].buf,
 324                                        rdwr_pa[i].len)) {
 325                                        res = -EFAULT;
 326                                }
 327                        }
 328                        kfree(rdwr_pa[i].buf);
 329                }
 330                kfree(data_ptrs);
 331                kfree(rdwr_pa);
 332                return res;

与用户空间的接口是i2c_rdwr_ioctl_data
/* This is the structure as used in the I2C_RDWR ioctl call */
struct i2c_rdwr_ioctl_data {
    struct i2c_msg __user *msgs;    /* pointers to i2c_msgs */
    __u32 nmsgs;            /* number of i2c_msgs */
};
所有待收发的数据都已经由用户空间组织好了

/**
 * struct i2c_msg - an I2C transaction segment beginning with START
 * @addr: Slave address, either seven or ten bits.  When this is a ten
 *    bit address, I2C_M_TEN must be set in @flags and the adapter
 *    must support I2C_FUNC_10BIT_ADDR.
 * @flags: I2C_M_RD is handled by all adapters.  No other flags may be
 *    provided unless the adapter exported the relevant I2C_FUNC_*
 *    flags through i2c_check_functionality().
 * @len: Number of data bytes in @buf being read from or written to the
 *    I2C slave address.  For read transactions where I2C_M_RECV_LEN
 *    is set, the caller guarantees that this buffer can hold up to
 *    32 bytes in addition to the initial length byte sent by the
 *    slave (plus, if used, the SMBus PEC); and this value will be
 *    incremented by the number of block data bytes received.
 * @buf: The buffer into which data is read, or from which it's written.
 *
 * An i2c_msg is the low level representation of one segment of an I2C
 * transaction.  It is visible to drivers in the @i2c_transfer() procedure,
 * to userspace from i2c-dev, and to I2C adapter drivers through the
 * @i2c_adapter.@master_xfer() method.
 *
 * Except when I2C "protocol mangling" is used, all I2C adapters implement
 * the standard rules for I2C transactions.  Each transaction begins with a
 * START.  That is followed by the slave address, and a bit encoding read
 * versus write.  Then follow all the data bytes, possibly including a byte
 * with SMBus PEC.  The transfer terminates with a NAK, or when all those
 * bytes have been transferred and ACKed.  If this is the last message in a
 * group, it is followed by a STOP.  Otherwise it is followed by the next
 * @i2c_msg transaction segment, beginning with a (repeated) START.
 *
 * Alternatively, when the adapter supports I2C_FUNC_PROTOCOL_MANGLING then
 * passing certain @flags may have changed those standard protocol behaviors.
 * Those flags are only for use with broken/nonconforming slaves, and with
 * adapters which are known to support the specific mangling options they
 * need (one or more of IGNORE_NAK, NO_RD_ACK, NOSTART, and REV_DIR_ADDR).
 */
struct i2c_msg {
    __u16 addr;    /* slave address            */
    __u16 flags;
#define I2C_M_TEN        0x0010    /* this is a ten bit chip address */
#define I2C_M_RD        0x0001    /* read data, from slave to master */
。。。
#define I2C_M_RECV_LEN        0x0400    /* length will be first received byte */
    __u16 len;        /* msg length                */
    __u8 *buf;        /* pointer to msg data            */
};

6.2    特定的设备驱动
原则上所有的I2C从设备的方法都可以通过上述统一的设备模型I2c-dev来访问,但I2c-dev上传输的是透明的数据,而对于某些I2C从设备,其数据传输遵循一定的格式,如果用I2c-dev来访问,则用户需要组织好所有的i2c_msg,对一般用户来说可能比较复杂。为了提供更加user friendly的接口,可以对特定I2C从设备的访问进行再次封装。

如I2C的RTC,其数据的转换较为复杂,为了减少用户空间的转换,提供了专用的RTC驱动供用户程序访问,其向上屏蔽了具体RTC芯片的差异。

下面以drivers/rtc/rtc-pcf8563.c为例来进行讲述。
6.2.1    关键数据结构
struct pcf8563 {
    struct i2c_client client;
    /*
     * The meaning of MO_C bit varies by the chip type.
     * From PCF8563 datasheet: this bit is toggled when the years
     * register overflows from 99 to 00
     *   0 indicates the century is 20xx
     *   1 indicates the century is 19xx
     * From RTC8564 datasheet: this bit indicates change of
     * century. When the year digit data overflows from 99 to 00,
     * this bit is set. By presetting it to 0 while still in the
     * 20th century, it will be set in year 2000, ...
     * There seems no reliable way to know how the system use this
     * bit.  So let's do it heuristically, assuming we are live in
     * 1970...2069.
     */
    int c_polarity;    /* 0: MO_C=1 means 19xx, otherwise MO_C=1 means 20xx */
};
pcf8563关键信息的全局表示。

static struct i2c_driver pcf8563_driver = {
    .driver        = {
        .name    = "pcf8563",
    },
    .id        = I2C_DRIVERID_PCF8563,
    .attach_adapter = &pcf8563_attach,
    .detach_client    = &pcf8563_detach,
};
特定的pcf8563_driver,有自己特定的pcf8563_attach方法。

static const struct rtc_class_ops pcf8563_rtc_ops = {
    .read_time    = pcf8563_rtc_read_time,
    .set_time    = pcf8563_rtc_set_time,
};
向RTC子系统注册的读写方法。
6.2.2    初始化
static int __init pcf8563_init(void)
{
    return i2c_add_driver(&pcf8563_driver);
}

static void __exit pcf8563_exit(void)
{
    i2c_del_driver(&pcf8563_driver);
}

调用i2c_add_driver向I2C总线上注册pcf8563_driver的I2C驱动,根据pcf8563这个driver的name进行匹配,匹配成功后将自动调用pcf8563_attach。

static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind)
{
    struct pcf8563 *pcf8563;
    struct i2c_client *client;
    struct rtc_device *rtc;

    int err = 0;

    dev_dbg(&adapter->dev, "%s/n", __FUNCTION__);

    if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
        err = -ENODEV;
        goto exit;
    }

    if (!(pcf8563 = kzalloc(sizeof(struct pcf8563), GFP_KERNEL))) {
        err = -ENOMEM;
        goto exit;
    }

    client = &pcf8563->client;
    client->addr = address;  //此address即为该slave的I2C设备地址
    client->driver = &pcf8563_driver;
    client->adapter    = adapter;
//上述几步和统一的I2C设备模型的client一样

    strlcpy(client->name, pcf8563_driver.driver.name, I2C_NAME_SIZE);

    /* Verify the chip is really an PCF8563 */
    if (kind < 0) {
        if (pcf8563_validate_client(client) < 0) {  //探测相关slave是否存在,简单的收发数据进行验证
            err = -ENODEV;
            goto exit_kfree;
        }
    }

    /* Inform the i2c layer */
    if ((err = i2c_attach_client(client)))  //将本client挂接到依附的adapter上        goto exit_kfree;

    dev_info(&client->dev, "chip found, driver version " DRV_VERSION "/n");

    rtc = rtc_device_register(pcf8563_driver.driver.name, &client->dev,
                &pcf8563_rtc_ops, THIS_MODULE);
//向RTC子系统注册pcf8563设备

    if (IS_ERR(rtc)) {
        err = PTR_ERR(rtc);
        goto exit_detach;
    }

    i2c_set_clientdata(client, rtc);

    return 0;

exit_detach:
    i2c_detach_client(client);

exit_kfree:
    kfree(pcf8563);

exit:
    return err;
}

6.2.3    数据收发
RTC设备的数据收发是通过drivers/rtc/rtc-dev.c进行的。
static const struct file_operations rtc_dev_fops = {
    .owner        = THIS_MODULE,
    .llseek        = no_llseek,
    .read        = rtc_dev_read,
    .poll        = rtc_dev_poll,
    .ioctl        = rtc_dev_ioctl,
    .open        = rtc_dev_open,
    .release    = rtc_dev_release,
    .fasync        = rtc_dev_fasync,
};
该file_operations向用户空间提供了统一接口。

7    驱动访问示例
下面以一款EEPOM AT24C64AN为例来讲述用户空间如何访问I2C设备。
7.1.1    写操作
I2C总线的写操作通常比较简单,分为byte write和page write
 
但两种方式对于SW来说没有区别,SW只需要指定发送的数据长度即可。
/**********
i2cBus为总线编号,也就是adapter编号,应该是本I2C设备所挂接的I2C总线
devAddr,为待访问的I2C设备地址
bTwoByteAddr,为待访问的从设备内部寄存器偏移量地址的宽度,即8位或16位,对应1或2个字节
offAddr,为待访问的从设备内部寄存器偏移量起始地址
byteLen,待写的数据长度,不包括总线协议上的dev addr及word address
i2cBuff1,待发送到有效数据即DATA
********/
int i2c_write(BYTE i2cBus, BYTE devAddr, BOOL bTwoByteAddr,
                           WORD offAddr, WORD byteLen, BYTE* i2cBuff1)
{
  char   fileName[20];
  BYTE   i2cBuff0[256];   /* buffer to send offset address & data*/
  int    file, iRealDataStart;
 
  sprintf(fileName, "/dev/i2c-%d", i2cBus);  //打开相应的I2C总线设备
 
  file = open(fileName, O_RDWR);
  if (file < 0)
  {
    fprintf(stderr, "Fail: Could not open file `/dev/i2c-%d': %s/n", /
    i2cBus, strerror(ENOENT));
    return -1;
  }
 
  if(!bTwoByteAddr)
  {
    i2cBuff0[0] = (BYTE)(offAddr & 0x00FF);
    iRealDataStart = 1;
  }
  else
  {
    i2cBuff0[0] = (BYTE)((offAddr & 0xFF00)>>8);
    i2cBuff0[1] = (BYTE)(offAddr & 0x00FF);
    iRealDataStart = 2;
  }
 
  /* Build write buffer */
  memcpy(&i2cBuff0[iRealDataStart], i2cBuff1, byteLen);  //构造i2c_msg中的buf
 
  sI2ccMessages[0].addr = devAddr;
  sI2ccMessages[0].flags = 0; /* Write flag = 0 */
  sI2ccMessages[0].len = byteLen + iRealDataStart;  //此长度为DATA和WORD ADDRESS
  sI2ccMessages[0].buf = i2cBuff0;
 
  sI2ccIoctData.msgs = sI2ccMessages;
  sI2ccIoctData.nmsgs = 1;
 
  if (ioctl(file, I2C_RDWR, &sI2ccIoctData) < 0)
  {
    fprintf(stderr, "Fail: fails to write to I2C device 0x%x at address 0x%x/n", devAddr, offAddr);
    close(file);
    return -1;
  }
 
  close(file);
 
  return 0;
}

7.1.2    读操作
I2C设备的读操作较复杂,需要先写待读的内部寄存器地址,然后再发起总线的读操作。时序如下:
 
因此需要在总线上连续进行两次数据传输,即两个i2c_msg。

/**********
i2cBus为总线编号,也就是adapter编号,应该是本I2C设备所挂接的I2C总线
devAddr,为待访问的I2C设备地址
bTwoByteAddr,为待访问的从设备内部寄存器偏移量地址的宽度,即8位或16位,对应1或2个字节
offAddr,为待访问的从设备内部寄存器偏移量起始地址
byteLen,待读的数据长度
i2cBuff1,待读的有效数据即DATA
********/

int i2c_read(BYTE i2cBus, BYTE devAddr, BOOL bTwoByteAddr,
                           WORD offAddr, WORD byteLen, BYTE* i2cBuff1)
{
  char   fileName[20];
  BYTE   i2cBuff0[2];     /* buffer to send offset address */
  int    file= 0;
 
  sprintf(fileName, "/dev/i2c-%d", i2cBus);
 
  file = open(fileName, O_RDWR);
  if (file < 0)
  {
    fprintf(stderr, "Fail: Could not open file `/dev/i2c-%d': %s/n", /
            i2cBus, strerror(ENOENT));
   
    return -1;
  }
 
  sI2ccMessages[0].addr = devAddr;
  sI2ccMessages[0].flags = 0; /* write flag = 0 */
 
  if(!bTwoByteAddr)
  {
    i2cBuff0[0] = (BYTE)(offAddr & 0x00FF);
    sI2ccMessages[0].len = 1; 
  }
  else
  {
    i2cBuff0[0] = (BYTE)((offAddr& 0xFF00)>>8);
    i2cBuff0[1] = (BYTE)(offAddr& 0x00FF);
    sI2ccMessages[0].len = 2;
  }
  sI2ccMessages[0].buf = i2cBuff0;  //第一个msg只是一个默认的写操作
 
  sI2ccMessages[1].addr = devAddr;
  sI2ccMessages[1].flags = I2C_M_RD; /* read flag */
  sI2ccMessages[1].len = byteLen;
  sI2ccMessages[1].buf = i2cBuff1;  //此仅仅为DATA域
 
  sI2ccIoctData.msgs = sI2ccMessages;
  sI2ccIoctData.nmsgs = 2;
 
  if (ioctl(file, I2C_RDWR, &sI2ccIoctData) < 0)  //一个ioctl必须连续发送两个msg
  {
    fprintf(stderr, "Fail: fails to read from I2C device 0x%x at address 0x%x/n", /
            devAddr, offAddr);
    close(file);
    return -1;
  }
 
  close(file);
  return 0;
}

8    参考鸣谢

http://blog.chinaunix.net/u1/51562/showart_1403925.html
http://blog.csdn.net/tjd0227/archive/2010/07/21/5753606.aspx

你可能感兴趣的:(编程,c,linux,嵌入式,平台,linux内核)