Linux内核I2C子系统驱动(一)

来源:互联网 发布:arm编程 编辑:程序博客网 时间:2024/05/29 12:54

I2C子系统驱动(一)
一、I2C体系结构
      Linux的I2C体系结构分为3个组成部分:I2C核心、I2C总线驱动、I2C设备驱动,如下图所示。I2C核心提供总线驱动和设备驱动的注册、注销方法,algorithm;I2C总线驱动对硬件体系结构中适配器的实现,主要包括适配器i2c_adapter、适配器通信算法i2c_algorithm,如果CPU集成了I2C控制器并且linux内核支持这个CPU,那么总线驱动就不用管,比如S3C2440就属于这类情况,在后文中我们将分析它的总线驱动;I2C设备驱动是具体的一个设备(如AT24C02),挂接在CPU控制的I2C适配器的设备驱动,有了这部分驱动才能使用控制器操作该设备,设备驱动主要包括i2c_driver 和i2c_client数据结构。

      在linux-2.6.32.2的include/linux/i2c.h中定义了i2c_adapter、i2c_algorithm、i2c_driver、i2c_client数据结构如下所示,这4个结构体相互之间的关系。
[cpp] view plaincopyprint?struct i2c_adapter { 
    struct module *owner; 
    unsigned int id; 
    unsigned int class;       /* classes to allow probing for */ 
    const struct i2c_algorithm *algo; /* the algorithm to access the bus总线通信方法结构体指针 */ 
    void *algo_data;                  /* algorithm数据 */ 
 
    /* data fields that are valid for all devices   */ 
    u8 level;           /* nesting level for lockdep */ 
    struct mutex bus_lock; 
 
    int timeout;            /* in jiffies */ 
    int retries;                    /* 重试次数 */ 
    struct device dev;      /* the adapter device */ 
 
    int nr; 
    char name[48]; 
    struct completion dev_released; 
}; 
struct i2c_algorithm { 
    int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs, 
               int num);               /*i2c传输函数指针*/ 
    int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr, 
               unsigned short flags, char read_write, 
               u8 command, int size, union i2c_smbus_data *data);    /*smbus传输函数指针*/ 
 
    /* To determine what the adapter supports */ 
    u32 (*functionality) (struct i2c_adapter *);            /*返回适配器支持的功能*/ 
}; 
struct i2c_driver { 
    unsigned int class; 
 
    int (*attach_adapter)(struct i2c_adapter *);       /*依附i2c_adapter函数指针*/ 
    int (*detach_adapter)(struct i2c_adapter *);       /*脱离i2c_adapter函数指针*/ 
 
    /* Standard driver model interfaces */ 
    int (*probe)(struct i2c_client *, const struct i2c_device_id *); 
    int (*remove)(struct i2c_client *); 
 
    /* driver model interfaces that don't relate to enumeration  */ 
    void (*shutdown)(struct i2c_client *); 
    int (*suspend)(struct i2c_client *, pm_message_t mesg); 
    int (*resume)(struct i2c_client *);        /* probe,remove,suspend,resume驱动方法重要成员函数 */ 
 
    /* 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);   /*类似ioctl*/ 
  
    struct device_driver driver; 
    const struct i2c_device_id *id_table;   /* 驱动支持多个设备,这里面就要包含这些设备的ID */ 
 
    /* Device detection callback for automatic device creation */ 
    int (*detect)(struct i2c_client *, int kind, struct i2c_board_info *);   /*i2c client脱离函数指针*/ 
    const struct i2c_client_address_data *address_data; 
    struct list_head clients; 
}; 
struct i2c_client { 
    unsigned short flags;       /* div., see below      */ 
    unsigned short addr;        /* chip address - NOTE: 7bit  芯片地址  */ 
                    /* addresses are stored in the  */ 
                    /* _LOWER_ 7 bits       */ 
    char name[I2C_NAME_SIZE]; 
    struct i2c_adapter *adapter;    /* the adapter we sit on  依附的i2c_adapter    */ 
    struct i2c_driver *driver;  /* and our access routines 依附的i2c_driver    */ 
    struct device dev;      /* the device structure     */ 
    int irq;            /* irq issued by device     */ 
    struct list_head detected; 
}; 

struct i2c_adapter {
 struct module *owner;
 unsigned int id;
 unsigned int class;    /* classes to allow probing for */
 const struct i2c_algorithm *algo; /* the algorithm to access the bus总线通信方法结构体指针 */
 void *algo_data;                  /* algorithm数据 */

 /* data fields that are valid for all devices */
 u8 level;    /* nesting level for lockdep */
 struct mutex bus_lock;

 int timeout;   /* in jiffies */
 int retries;                    /* 重试次数 */
 struct device dev;  /* the adapter device */

 int nr;
 char name[48];
 struct completion dev_released;
};
struct i2c_algorithm {
 int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,
      int num);               /*i2c传输函数指针*/
 int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,
      unsigned short flags, char read_write,
      u8 command, int size, union i2c_smbus_data *data);    /*smbus传输函数指针*/

 /* To determine what the adapter supports */
 u32 (*functionality) (struct i2c_adapter *);            /*返回适配器支持的功能*/
};
struct i2c_driver {
 unsigned int class;

 int (*attach_adapter)(struct i2c_adapter *);       /*依附i2c_adapter函数指针*/
 int (*detach_adapter)(struct i2c_adapter *);       /*脱离i2c_adapter函数指针*/

 /* Standard driver model interfaces */
 int (*probe)(struct i2c_client *, const struct i2c_device_id *);
 int (*remove)(struct i2c_client *);

 /* driver model interfaces that don't relate to enumeration  */
 void (*shutdown)(struct i2c_client *);
 int (*suspend)(struct i2c_client *, pm_message_t mesg);
 int (*resume)(struct i2c_client *);        /* probe,remove,suspend,resume驱动方法重要成员函数 */

 /* 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);   /*类似ioctl*/
 
 struct device_driver driver;
 const struct i2c_device_id *id_table;   /* 驱动支持多个设备,这里面就要包含这些设备的ID */

 /* Device detection callback for automatic device creation */
 int (*detect)(struct i2c_client *, int kind, struct i2c_board_info *);   /*i2c client脱离函数指针*/
 const struct i2c_client_address_data *address_data;
 struct list_head clients;
};
struct i2c_client {
 unsigned short flags;  /* div., see below  */
 unsigned short addr;  /* chip address - NOTE: 7bit  芯片地址 */
     /* addresses are stored in the */
     /* _LOWER_ 7 bits  */
 char name[I2C_NAME_SIZE];
 struct i2c_adapter *adapter; /* the adapter we sit on  依附的i2c_adapter */
 struct i2c_driver *driver; /* and our access routines 依附的i2c_driver */
 struct device dev;  /* the device structure  */
 int irq;   /* irq issued by device  */
 struct list_head detected;
};1、i2c_adapter 与i2c_algorithm,i2c_adapter 对应于物理上的一个适配器,而i2c_algorithm对应一套通信方法。一个I2C适配器需要i2c_algorithm中提供的通信函数来控制适配器上产生特定的访问周期。缺少i2c_algorithm 的i2c_adapter 什么也做不了,因此i2c_adapter 中包含其使用的i2c_algorithm的指针。i2c_algorithm 中的关键函数master_xfer()用于产生I2C 访问周期需要的信号,以i2c_msg(即I2C消息)为单位。i2c_msg结构体也非常关键。
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_NOSTART           0x4000    /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_REV_DIR_ADDR 0x2000    /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK    0x1000    /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NO_RD_ACK             0x0800    /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_RECV_LEN         0x0400    /* length will be first received byte */
       __u16 len;             /* msg length                       */
       __u8 *buf;             /* pointer to msg data                  */
};
2、i2c_driver 与i2c_client,i2c_driver 对应一套驱动方法,是纯粹的用于辅助作用的数据结构,它不对应于任何的物理实体。i2c_client对应于真实的物理设备,每个I2C设备都需要一个i2c_client来描述。i2c_client一般被包含在I2C字符设备的私有信息结构体中。
3、i2c_adpater 与i2c_client,i2c_adpater 与i2c_client 的关系与I2C 硬件体系中适配器和设备的关系一致,即i2c_client 依附于i2c_adpater。
二、I2C核心
    I2C核心是总线驱动和设备驱动的纽带,源码位于drivers/i2c/i2c-core.c,它并不依赖于硬件平台的接口函数,I2C核心中一些重要函数如下:
增加/删除i2c_adapter
int i2c_add_adapter(struct i2c_adapter *adapter)
int i2c_del_adapter(struct i2c_adapter *adapter)
增加/删除i2c_driver
int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
int i2c_add_driver(struct i2c_driver *driver)         //调用i2c_register_driver
void i2c_del_driver(struct i2c_driver *driver)
增加/删除i2c_client
struct i2c_client *i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
void i2c_unregister_device(struct i2c_client *client)
      注:在2.6.30版本之前使用的是i2c_attach_client()和i2c_detach_client()函数。之后attach被merge到了i2c_new_device中,而detach直接被unresister取代。实际上这两个函数内部都是调用了device_register()和device_unregister()
I2C传输、发送接收
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
int i2c_master_send(struct i2c_client *client,const char *buf ,int count)
int i2c_master_recv(struct i2c_client *client, char *buf ,int count)
      i2c_transfer()函数用于进行I2C 适配器和I2C 设备之间的一组消息交互,i2c_master_send()函数和i2c_master_recv()函数内部会调用i2c_transfer()函数分别完成一条写消息和一条读消息,i2c_transfer()本身不能喝硬件完成消息交互,它寻找i2c_adapter对应的i2c_algorithm,要实现数据传送就要实现i2c_algorithm的master_xfer(),在总线驱动中就是重点。

0 0