Linux2.6.37 I2C驱动框架分析(一)

来源:互联网 发布:linux挂载ntfs硬盘 编辑:程序博客网 时间:2024/06/16 01:26
 

  最近工作中又使用到了I2C,所以借S3C2440开发板GT2440为硬件平台温习一遍I2C驱动体系。

 

linux内核中IIC驱动的体系框架

linux内核中IIC部分驱动代码位于:/drivers/i2c下,代码大致分为几个小目录及i2c目录下的的i2c核心代码:

核心代码:  /drivers/i2c/i2c-core.c  /drivers/i2c/i2c-core.h 

busses目录:各种IIC控制器相关的驱动代码(也称为IIC总线驱动代码),如果S3C2440A内部集成了IIC控制器,它在busses目录下对应的控制器驱动代码为i2c-s3c2410.c

algos目录:定义的是一些通信方法,对于S3C2440A的IIC控制器的通信方法没在里面

muxes目录:各种外接在IIC控制器上的IIC从设备相关的驱动代码

从以上的目录我们可以看出,linux内IIC驱动体系分为3部分:IIC核心、IIC总线驱动、IIC设备驱动。

 

IIC核心:

IIC核心定义了各种数据结构及抽象出通用接口函数:

如注册(销)IIC适配器:

i2c_add_adapter(struct i2c_adapter *adapter);

i2c_del_adapter(struct i2c_adapter *adapter);

 

注册(销)IIC设备驱动:

 i2c_register_drive(struct module *owner ,struct i2c_driver *driver);

 i2c_del_driver(struct i2c_driver *driver);

IIC抽象的传输、发送和接收函数:

i2c_transfe(struct i2c_adapter *adapter,struct i2c_msg *msg,int num);

i2c_master_send(struct i2c_client *client,const char *buf,int count);

i2c_master_recv(struct i2c_client *client , char * buf , int count);

 

IIC总线驱动:

  IIC总线驱动及IIC控制器驱动,为此linux内核中定义一个i2c_adapter数据结构来描述一个IIC适配器,而在不同架构上有不同实现方法:如S3C2440A上就使用i2c-s3c2410.c来实现了S3C2440A上的IIC控制器驱动

 

IIC设备驱动:

  IIC设备在linux内核中用struct i2c_client结构来描述,而使用i2c_driver结构来描述挂载在IIC控制器上的IIC从设备如何与主机进行通信。

 

问:像IIC裸机驱动那样一个文件就能搞定的IIC驱动在linux中的结构却相当的复杂?

原因在于linux内核,IIC驱动是一类驱动,如果像裸机驱动那样,那么这个驱动只能用于特定的IIC控制器及IIC设备,这样一来如果有很多不同类型的IIC控制器或IIC设备,那么所有的代码都必须重写。这显然是不明智的,一个简单的方法是将不同类型的IIC控制器及IIC设备之间进行通信的共同点给抽象出来,而这部分的代码不管是任何IIC控制器或IIC设备都是一样的,这样移植不同的IIC总线驱动和IIC设备驱动时就能大大的减小代码量。就像内核中将IIC驱动分成了IIC总线驱动和IIC设备驱动一样,在裸机驱动中我们根本看不出那部分是总线驱动,哪部分是设备驱动?二者已经融为了一体。这样的缺陷也很明显,当我们的IIC总线上挂载了不同的IIC设备时,那么我们不得不重新写IIC控制器相关的驱动代码,而如果把它抽象出来,IIC总线驱动主要负责IIC总线的数据传输,如时钟控制、发出S/P信号、中断处理等等,而IIC设备驱动从负责解析出传输的这些数据的含义,因为对于不同的IIC设备,其总线上传输的这些数据的含义不同。个人认为linux的驱动的体系也是基于这种思想产生的。当我们明白了IIC驱动框架中如此负责的构造的良苦用心自然会更加深刻将整个驱动框架铭记于心。

 

Linux内核为IIC构造的几个重要的数据结构:

struct i2c_adapter{
     struct module *owner;
     unsigned int id __deprecated;
     unsigned int class;               适配器所属的类 
     const struct i2c_algorithm *algo; 该总线上的通信方法 
     void *algo_data;                  通信方法的附加数据

 
     struct rt_mutex bus_lock;         对所有设备的锁结构

     int timeout;         超时时间,在搞总线上发送信号多久没回的超时时间 
     int retries;         重复的次数 
     struct device dev;   适配器设备

     int nr;              总线的编号 
     char name[48];       名字 
     struct completion dev_released;

     struct mutex userspace_clients_lock;
     struct list_head userspace_clients;
};

 

其中重要的成员有algo :该成员所指向的i2c_algorithm实际上就是具体的IIC控制器的通信方法,如发出S/P信号、传输数据等最底层的控制器操作。

 

struct i2c_algorithm{
 
 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);
 u32 (*functionality) (struct i2c_adapter *);  适配器所支持的功能

};

由于每种适配器所支持的功能不同、传输数据的方法也不同,所以讲这个抽象出来,在不同的适配器中再去具体的实现它。

 

struct i2c_driver{
     unsigned int class;

     int (*attach_adapter)(struct i2c_adapter *);
     int (*detach_adapter)(struct i2c_adapter *);

    标准的驱动模型 
     int (*probe)(struct i2c_client *, const struct i2c_device_id *);
     int (*remove)(struct i2c_client *);
     void (*shutdown)(struct i2c_client *);
     int (*suspend)(struct i2c_client *, pm_message_t mesg);
     int (*resume)(struct i2c_client *);

     void (*alert)(struct i2c_client *, unsigned int data);

     类似ioctl 
     int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);
    用于设备驱动模型 
    struct device_driver driver;
   列出该设备驱动所支持的设备 
    const struct i2c_device_id *id_table;

   设备探测的回调函数 
   int (*detect)(struct i2c_client *, struct i2c_board_info *);
   用于探测的i2c设备地址 
   const unsigned short *address_list;
 
   struct list_head clients;   /* 链接所有探测出的i2c设备 */
};

 


struct i2c_client{   i2c_client 代表i2c从设备
     unsigned short flags;  I2C_CLIENT_TEN表示设备使用的是10位的地址,I2C_CLIENT_PEC表示使用SMBus包用在错误检查
     unsigned short addr;   I2C设备在总线上的的地址  
   
     char name[I2C_NAME_SIZE]; 设备名
     struct i2c_adapter *adapter;   指向该I2C设备挂载的I2C适配器
     struct i2c_driver *driver;     指向支持该I2C设备的驱?
     struct device dev;             用于总线设备驱动模型
     int irq;                       该设备能产生的中断号
     struct list_head detected;
};

 


struct i2c_msg {   I2C总线上传输信息的最小单位
      __u16 addr;  i2c设备地址,可以是10位的地址,如果是10位的地址flags标志中需设置I2C_M_TEN
      __u16 flags; I2C_M_RD 读标志,所有的适配器都必须支持,其他的标志见I2C_FUNC_*
#define I2C_M_TEN  0x0010   10位的从设备的地址
#define I2C_M_RD  0x0001    从I2C设备中读数据
#define I2C_M_NOSTART  0x4000 
#define I2C_M_REV_DIR_ADDR 0x2000 
#define I2C_M_IGNORE_NAK 0x1000 
#define I2C_M_NO_RD_ACK  0x0800 
#define I2C_M_RECV_LEN  0x0400 
     __u16 len;        消息的长度(字节数)
     __u8 *buf;       指向消息数据的缓冲区
};

 


struct i2c_board_info{   创建I2C设备的模版
     char  type[I2C_NAME_SIZE];  设备类型,用于填充i2c_client.name
     unsigned short flags;       用于填充i2c_client.flags
     unsigned short addr;        用于填充i2c_client.addr
     void  *platform_data;       存储i2c_client.dev.platform_data
     struct dev_archdata *archdata; 拷贝到i2c_client.dev.archdata
#ifdef CONFIG_OF             指向打开固件的设备节点
     struct device_node *of_node;
#endif
     int  irq;                  存储到i2c_client.irq
};

i2c_board_info 被用来创建当前系统中I2C设备的列表,这些信息用来驱动模型树,对于主板会使用i2c_register_board_info来注册这些设备

接下来我们就着手分析linux提供的这些重要数据结构及IIC核心提供的这些核心函数是如何构造出整个IIC驱动框架的,耐心看下去你将对IIC体系驱动框架了如指掌!!!

0 0