Linux驱动子系统之I2C(2)

2  I2C子系统


2.1 LinuxI2C子系统架构

在内核中已经提供I2C子系统,所以在做I2C驱动之前,就必须要熟悉该子系统。

Linux驱动子系统之I2C(2)_第1张图片

2.2 三大组成部分

1、I2C核心(i2c-core)

I2C核心提供了I2C总线驱动和设备驱动的注册、注销方法,I2C通信方法(algorithm)上层的、与具体适配器无关的代码以及探测设备、检测设备地址的上层代码等。


2、I2C总线驱动(I2Cadapter/Algo driver)

I2C总线驱动是I2C适配器的软件实现,提供I2C适配器与从设备间完成数据通信的能力。

I2C总线驱动由i2c_adapter和i2c_algorithm来描述


3、I2C客户驱动程序(I2Cclient driver)

I2C客户驱动是对I2C从设备的软件实现,一个具体的I2C客户驱动包括两个部分:一部分是i2c_driver,用于将设备挂接于i2c总线;另一部分是设备本身的驱动。

I2C客户驱动程序由i2c_driver和i2c_client来描述


2.3 所有的I2C驱动代码位于drivers/i2c目录下

I2c-core.c    实现I2C核心的功能

I2c-dev.c     通用的从设备驱动

Chips       特定的I2C设备驱动

Busses      I2C适配器的驱动

Algos       实现了一些I2C总线适配器的algorithm


2.4 I2C驱动编写的两种方法

从上面的图我们可以看到两种编写驱动方法,一种是利用系统提供的i2c-dev.c来实现一个i2c适配器的设备文件,然后通过在应用层操作I2C适配器来控制I2C设备;另一种是为I2C从设备独立编写一个设备驱动,不需要i2c-dev.c文件。


2.5 重要的数据结构

每次分析子系统免不了分析它的数据结构,OK我们先来分析一下。

I2c_adapter结构体代表I2C总线控制器


[cpp] view plain copy print ?
  1. struct i2c_adapter { 
  2.    struct module *owner; 
  3.    unsigned int class;       /*classes to allow probing for */ 
  4.     const struct i2c_algorithm*algo; /* 总线上数据传输的算法*/ 
  5.    void *algo_data;              /* algorithm 数据 */ 
  6.   
  7.    int timeout;            /* injiffies */ 
  8.    int retries;             /* 重试次数 */ 
  9.     struct device dev;      /* the adapter device */ 
  10.   
  11.    int nr; 
  12.    char name[48];                 /* 适配器名字 */ 
  13.    struct completion dev_released;   /* 用于同步 */ 
  14. }; 

struct i2c_adapter {
   struct module *owner;
   unsigned int class;       /*classes to allow probing for */
    const struct i2c_algorithm*algo; /* 总线上数据传输的算法*/
   void *algo_data;              /* algorithm 数据 */
 
   int timeout;            /* injiffies */
   int retries;             /* 重试次数 */
    struct device dev;      /* the adapter device */
 
   int nr;
   char name[48];                 /* 适配器名字 */
   struct completion dev_released;   /* 用于同步 */
};


I2c_algorithm对应一套通信方法


[cpp] view plain copy print ?
  1. struct i2c_algorithm { 
  2.     int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs, intnum); 
  3.    int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr, 
  4.                unsigned short flags, charread_write, 
  5.                u8 command, int size, unioni2c_smbus_data *data); 
  6.     u32 (*functionality) (structi2c_adapter *); 
  7. }; 

struct i2c_algorithm {
    int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs, intnum);
   int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,
               unsigned short flags, charread_write,
               u8 command, int size, unioni2c_smbus_data *data);
    u32 (*functionality) (structi2c_adapter *);
};


Functionality 函数用于返回algorithm所支持的通信协议,比如I2C_FUNC_I2C,I2C_FUNC_10BIT_ADDR等。

Master_xfer   函数实现总线上数据传输,与具体的适配器有关


Master_xfer函数实现模板


[cpp] view plain copy print ?
  1. static int i2c_adapter_xxx_xfer(structi2c_adapter *adap, struct i2c_msg *msgs, int num) 
  2.    ...... 
  3.    for (i = 0; i < num; i++) { 
  4.        i2c_adapter_xxx_start();         /*产生起始位*/ 
  5.        if (msgs[i]->flags & I2C_M_RD) {    /*读取*/ 
  6.            i2c_adapter_xxx_setaddr((msg->addr << 1) | 1);  /*发送从设备地址*/ 
  7.            i2c_adapter_xxx_wait_ack();   /*获得从设备的ACK*/ 
  8. i2c_adapter_xxx_readbytes(msgs[i]->buf,msgs[i]->len);  /*读取len长度的数据到buf中*/ 
  9.        } else
  10.            i2c_adapter_xxx_setaddr(msg->addr << 1); 
  11.            i2c_adapter_xxx_wait_ack(); 
  12.            i2c_adapter_xxx_writebytes(msgs[i]->buf, msgs[i]->len); 
  13.        } 
  14.     } 
  15.    i2c_adapter_xxx_stop(); /*产生停止位*/ 

static int i2c_adapter_xxx_xfer(structi2c_adapter *adap, struct i2c_msg *msgs, int num)
{
   ......
   for (i = 0; i < num; i++) {
       i2c_adapter_xxx_start();         /*产生起始位*/
       if (msgs[i]->flags & I2C_M_RD) {    /*读取*/
           i2c_adapter_xxx_setaddr((msg->addr << 1) | 1);  /*发送从设备地址*/
           i2c_adapter_xxx_wait_ack();   /*获得从设备的ACK*/
i2c_adapter_xxx_readbytes(msgs[i]->buf,msgs[i]->len);  /*读取len长度的数据到buf中*/
       } else {
           i2c_adapter_xxx_setaddr(msg->addr << 1);
           i2c_adapter_xxx_wait_ack();
           i2c_adapter_xxx_writebytes(msgs[i]->buf, msgs[i]->len);
       }
    }
   i2c_adapter_xxx_stop(); /*产生停止位*/
}


上面调用的函数用于完成适配器的底层硬件操作,与I2C适配器和CPU的具体硬件直接相关,需要由工程师根据芯片的数据手册来实现。在内核源码中,针对不同的I2C适配器都有master_xfer的实现,风格与模板不尽相同,但是可以用该模板作为参考来看源代码,受益匪浅。


I2c_driver代表I2C从设备驱动


[cpp] view plain copy print ?
  1. struct i2c_driver { 
  2.          unsignedint class
  3.   
  4.          int(*attach_adapter)(struct i2c_adapter *) __deprecated; /*依附i2c适配器函数指针*/ 
  5.          int(*detach_adapter)(struct i2c_adapter *) __deprecated;/*脱离i2c适配器函数指针*/ 
  6.   
  7.          int (*probe)(struct i2c_client*, const struct i2c_device_id *); 
  8.          int (*remove)(struct i2c_client*); 
  9.   
  10.          int(*suspend)(struct i2c_client *, pm_message_t mesg); 
  11.          int(*resume)(struct i2c_client *); 
  12.          void(*alert)(struct i2c_client *, unsigned int data); 
  13.          int(*command)(struct i2c_client *client, unsigned int cmd, void *arg); 
  14.   
  15.          struct device_driver driver; 
  16.          const struct i2c_device_id*id_table;  /* 该驱动所支持的设备ID表 */ 
  17.   
  18.          /*Device detection callback for automatic device creation */ 
  19.          int(*detect)(struct i2c_client *, struct i2c_board_info *); 
  20.          constunsigned short *address_list; 
  21.          structlist_head clients; 
  22. }; 

struct i2c_driver {
         unsignedint class;
 
         int(*attach_adapter)(struct i2c_adapter *) __deprecated; /*依附i2c适配器函数指针*/
         int(*detach_adapter)(struct i2c_adapter *) __deprecated;/*脱离i2c适配器函数指针*/
 
         int (*probe)(struct i2c_client*, const struct i2c_device_id *);
         int (*remove)(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);
         int(*command)(struct i2c_client *client, unsigned int cmd, void *arg);
 
         struct device_driver driver;
         const struct i2c_device_id*id_table;  /* 该驱动所支持的设备ID表 */
 
         /*Device detection callback for automatic device creation */
         int(*detect)(struct i2c_client *, struct i2c_board_info *);
         constunsigned short *address_list;
         structlist_head clients;
};


在新内核中,attach_adapter和detach_adapter已经被probe和remove取代

Id_table用于i2c_driver和i2c_client的匹配


I2c_client代表I2C从设备


[cpp] view plain copy print ?
  1. struct i2c_client { 
  2. unsigned short flags;                 /*I2C_CLIENT_TEN:使用10位从地址,I2C_CLIENT_PEC:使用SMBus包错误检测*/ 
  3.          unsignedshort addr;                 /* chipaddress - NOTE: 7bit    */ 
  4.          charname[I2C_NAME_SIZE]; 
  5.          struct i2c_adapter *adapter; /* 依附的i2c_adapter   */ 
  6.          struct i2c_driver *driver;         /* 依附的i2c_driver*/ 
  7.          structdevice dev;             /* the devicestructure             */ 
  8.          intirq;                         /* irq issuedby device               */ 
  9.          structlist_head detected; 
  10. }; 

struct i2c_client {
unsigned short flags;                 /*I2C_CLIENT_TEN:使用10位从地址,I2C_CLIENT_PEC:使用SMBus包错误检测*/
         unsignedshort addr;                 /* chipaddress - NOTE: 7bit    */
         charname[I2C_NAME_SIZE];
         struct i2c_adapter *adapter; /* 依附的i2c_adapter   */
         struct i2c_driver *driver;         /* 依附的i2c_driver*/
         structdevice dev;             /* the devicestructure             */
         intirq;                         /* irq issuedby device               */
         structlist_head detected;
};



2.6 核心层提供的接口函数

1、  增加/删除I2C适配器

int i2c_add_adapter(struct i2c_adapter *adapter)

int i2c_del_adapter(struct i2c_adapter *adap)


[cpp] view plain copy print ?
  1.   
  2. static int i2c_register_adapter(struct i2c_adapter *adap) 
  3. res = device_register(&adap->dev); 
  4.   
  5. if (adap->nr <__i2c_first_dynamic_bus_num) 
  6.            i2c_scan_static_board_info(adap); 
  7.   
  8. bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter); 

 
static int i2c_register_adapter(struct i2c_adapter *adap)
{
res = device_register(&adap->dev);
 
if (adap->nr <__i2c_first_dynamic_bus_num)
           i2c_scan_static_board_info(adap);
 
bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);
}


Device_register(&adap->dev)  向I2C总线注册一个adapter设备

i2c_scan_static_board_info(adap)   注册所有已知的i2c_client


2、  增加/删除I2C从设备驱动


[cpp] view plain copy print ?
  1. int i2c_add_driver(struct i2c_driver *driver) 
  2. void i2c_del_driver(struct i2c_driver *driver) 
  3.   
  4. inti2c_register_driver(struct module *owner, struct i2c_driver *driver) 
  5.   
  6. /* add the driver to the list of i2c drivers inthe driver core */ 
  7. driver->driver.owner = owner; 
  8. driver->driver.bus = &i2c_bus_type; 
  9.   
  10. res = driver_register(&driver->driver); 
  11.   
  12. /* Walk the adapters that are already present*/ 
  13. i2c_for_each_dev(driver, __process_new_driver); 

int i2c_add_driver(struct i2c_driver *driver)
void i2c_del_driver(struct i2c_driver *driver)
 
inti2c_register_driver(struct module *owner, struct i2c_driver *driver)
{
 
/* add the driver to the list of i2c drivers inthe driver core */
driver->driver.owner = owner;
driver->driver.bus = &i2c_bus_type;
 
res = driver_register(&driver->driver);
 
/* Walk the adapters that are already present*/
i2c_for_each_dev(driver, __process_new_driver);
}


driver_register(&driver->driver)   向I2C总线注册一个i2c_driver



3、  i2c传输,发送和接收


[cpp] view plain copy print ?
  1. int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg*msgs, int num) 
  2. int i2c_master_send(const struct i2c_client *client, constchar *buf, int count) 
  3. int i2c_master_recv(const struct i2c_client *client, char*buf, int count) 
  4.   
  5. int i2c_transfer(structi2c_adapter *adap, struct i2c_msg *msgs, int num) 
  6. if (adap->algo->master_xfer) { 
  7.            for (ret = 0, try = 0; try <=adap->retries; try++) { 
  8.                     ret = adap->algo->master_xfer(adap, msgs,num); 
  9.            } 

int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg*msgs, int num)
int i2c_master_send(const struct i2c_client *client, constchar *buf, int count)
int i2c_master_recv(const struct i2c_client *client, char*buf, int count)
 
int i2c_transfer(structi2c_adapter *adap, struct i2c_msg *msgs, int num)
{
if (adap->algo->master_xfer) {
           for (ret = 0, try = 0; try <=adap->retries; try++) {
                    ret = adap->algo->master_xfer(adap, msgs,num);
           }
}
}


最终会调用到适配器实现的master_xfer函数来完成数据传输工作


参考资料:《essential Linux device drivers》

                     《linux设备驱动开发详解》


你可能感兴趣的:(Linux驱动子系统之I2C(2))