Chinaunix首页 | 论坛 | 博客
  • 博客访问: 349524
  • 博文数量: 73
  • 博客积分: 4096
  • 博客等级: 上校
  • 技术积分: 1102
  • 用 户 组: 普通用户
  • 注册时间: 2007-11-21 14:53
文章分类
文章存档

2009年(3)

2008年(70)

我的朋友

分类: LINUX

2008-12-18 13:56:40

1、           LINUXI2C驱动架构

LINUXI2C总线的驱动分为两个部分:总线驱动(BUS)和设备驱动(DEVICE)。

总线驱动的职责是:为系统中每个I2C总线增加相应的读写方法。但是总线驱动本身不进行任何的通讯,它等待设备驱动调用其函数。

设备驱动是挂在I2C总线上的具体的设备通讯的驱动。通过I2C总线驱动提供的函数,设备驱动可以忽略不同总线控制器的差异,不考虑其实现细节地与硬件设备进行通讯。

 

 

 

1 LINUXI2C驱动架构图

 

2、           总线驱动

系统启动后,首先装载的是I2C总线驱动。一个总线驱动用于支持一条特定的I2C总线的读写。一个总线驱动通常需要两个模块:struct i2c_adapterstruct i2c_algorithm

linux-2.6.19.2_mx27/include/linux/i2c.h:

 



struct i2c_adapter {

    struct module *owner;

    unsigned int id;

    unsigned int class;

    const struct i2c_algorithm *algo; /* the algorithm to access the bus */

    void *algo_data;

 

    /* --- administration stuff. */

    int (*client_register)(struct i2c_client *);

    int (*client_unregister)(struct i2c_client *);

 

    /* data fields that are valid for all devices   */

    struct mutex bus_lock;

    struct mutex clist_lock;

 

    int timeout;

    int retries;

    struct device dev;      /* the adapter device */

    struct class_device class_dev;  /* the class device */

 

    int nr;

    struct list_head clients;

    struct list_head list;

    char name[I2C_NAME_SIZE];

    struct completion dev_released;

    struct completion class_dev_released;

};

 

 



这个模块没有提供读写函数,具体的读写方法由第二个模块:struct i2c_algorithm提供。

I2C Algorithm是为了I2C总线驱动和I2C总线之间能够对话。

I2C Algorithm的具体“算法”实现在driver/i2c/algos/i2c-algo-***.c中。

linux-2.6.19.2_mx27/include/linux/i2c.h:

 



struct i2c_algorithm {

    /* If an adapter algorithm can't do I2C-level access, set master_xfer

       to NULL. If an adapter algorithm can do SMBus access, set

       smbus_xfer. If set to NULL, the SMBus protocol is simulated

       using common I2C messages */

    /* master_xfer should return the number of messages successfully

       processed, or a negative value on error */

    int (*master_xfer)(struct i2c_adapter *adap,struct i2c_msg *msgs,

                       int num);

    int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,

                       unsigned short flags, char read_write,

                       u8 command, int size, union i2c_smbus_data * data);

 

    /* --- ioctl like call to set div. parameters. */

    int (*algo_control)(struct i2c_adapter *, unsigned int, unsigned long);

 

    /* To determine what the adapter supports */

    u32 (*functionality) (struct i2c_adapter *);

};

 

 



这个模块为总线驱动增加读写“算法”。通常情况下每个I2C总线驱动都定义了一个自己的读写算法,但是鉴于有些总线使用相同的算法,所以可以共用同一套读写算法。

 

然后通过:linux-2.6.19.2_mx27/drivers/i2c/i2c-core.c:

         int i2c_add_adapter(struct i2c_adapter *adap);

          具体的调用流程是:

 


linux-2.6.19.2_mx27/drivers/i2c/busses/i2c-ite.c: module_init(iic_ite_init);

 

 


linux-2.6.19.2_mx27/drivers/i2c/busses/i2c-ite.c: static int __init iic_ite_init(void);

 

 

linux-2.6.19.2_mx27/drivers/i2c/algos/ i2c-algo-ite.c:int i2c_iic_add_bus(struct i2c_adapter *adap)

 

 

linux-2.6.19.2_mx27/drivers/i2c/i2c-core.c: int i2c_add_adapter(struct i2c_adapter *adap)

 

 


 


3、           设备驱动

总线驱动只提供了对一条总线的读写机制,本身并不会去做通信。通信是由I2C设备驱动来做的,设备驱动通过I2C总线同具体的设备进行通信。

一个设备驱动有两个模块来描述:struct i2c_driver和struct i2c_client。

系统启动后,I2C总线驱动加载完成后,就可以加载设备驱动。

首先装入如下结构:

linux-2.6.19.2_mx27/include/linux/i2c.h:

 

 



struct i2c_driver {

    int id;

    unsigned int class;

 

    /* Notifies the driver that a new bus has appeared. This routine

     * can be used by the driver to test if the bus meets its conditions

     * & seek for the presence of the chip(s) it supports. If found, it

     * registers the client(s) that are on the bus to the i2c admin. via

     * i2c_attach_client.

     */

    int (*attach_adapter)(struct i2c_adapter *);

    int (*detach_adapter)(struct i2c_adapter *);

 

    /* tells the driver that a client is about to be deleted & gives it

     * the chance to remove its private data. Also, if the client struct

     * has been dynamically allocated by the driver in the function above,

     * it must be freed here.

     */

    int (*detach_client)(struct i2c_client *);

   

    /* a ioctl like command that can be used to perform specific functions

     * with the device.

     */

    int (*command)(struct i2c_client *client,unsigned int cmd, void *arg);

 

    struct device_driver driver;

    struct list_head list;

};

 



这个i2c_driver一旦装入完成后,其中的attach_adapter函数会被调用。在其中可以遍历系统中的每个I2C总线驱动,探测想要访问的设备:

 

注意:探测可能会找到多个设备,因而不仅一个I2C总线可以挂多个不同类型的设备,一个设备驱动也可以同时为挂在多个不同I2C总线上的设备服务。

 

  每当设备驱动探测到一个它能支持的设备,它就创建一个struct i2c_client来标识这个设备:

linux-2.6.19.2_mx27/include/linux/i2c.h:

 

 



struct i2c_client {

    unsigned int flags;     /* div., see below      */

    unsigned short addr;        /* chip address - NOTE: 7bit    */

                    /* addresses are stored in the  */

                    /* _LOWER_ 7 bits       */

    struct i2c_adapter *adapter;    /* the adapter we sit on    */

    struct i2c_driver *driver;  /* and our access routines  */

    int usage_count;        /* How many accesses currently  */

                    /* to the client        */

    struct device dev;      /* the device structure     */

    struct list_head list;

    char name[I2C_NAME_SIZE];

    struct completion released;

};

 



一个i2c_client代表着位于adapter总线上,地址为address,使用driver来驱动的一个设备。它将总线驱动和设备驱动,以及设备地址绑定在了一起。一个i2c_client就代表着一个I2C设备。

 

当得到I2C设备以后,就可以直接对此设备进行读写了:

这两个函数的具体实现是在:linux-2.6.19.2_mx27/drivers/i2c/i2c-core.c:中。

 



/*

 * The master routines are the ones normally used to transmit data to devices

 * on a bus (or read from them). Apart from two basic transfer functions to

 * transmit one message at a time, a more complex version can be used to

 * transmit an arbitrary number of messages without interruption.

 */

extern int i2c_master_send(struct i2c_client *,const char* ,int);

extern int i2c_master_recv(struct i2c_client *,char* ,int);

 

 


 

 

阅读(3455) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~