【Linux高級驅動】I2C驅動框架分析

1.i2c-dev.c(i2c設備驅動組件層)

    功能:1)給用戶提供接口app

i2c_dev_init  //入口函數
 /*申請主設備號*/函數

register_chrdev(I2C_MAJOR( 89), "i2c", &i2cdev_fops);
  /*建立一個設備類*/
 i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");
  /*註冊一個i2c驅動*/
 i2c_add_driver( &i2cdev_driver);
  i2c_register_driver(THIS_MODULE, driver);
    /*指定總線類型*/
   driver - >driver.bus = &i2c_bus_type;
    /*驅動註冊
    *1.將i2c驅動加入i2c總線的驅動鏈表
    *2.搜索設備鏈表,實現匹配,根據i2c總線的匹配原理:必需要求i2c驅動結構體中實現id_table
    *  可是,i2c驅動結構體中並無實現id_table,因此永遠都匹配失敗
    */

   driver_register( &driver - >driver);
    
    /*搜索適配器鏈表,每搜索一個適配器,都會調用__process_new_driver函數
    *在此函數中,又會調用i2c驅動中的,attach_adapter函數
    */

   bus_for_each_dev( &i2c_bus_type, NULL, driver, __process_new_driver);
   __process_new_driver   //此函數可能會被調用屢次
    i2c_do_add_adapter(data, to_i2c_adapter(dev));
      if (driver - >attach_adapter) {
       /* We ignore the return code; if it fails, too bad */
      driver - >attach_adapter(adap);     //i2cdev_attach_adapter
     }

static const struct file_operations i2cdev_fops = {
 .owner   = THIS_MODULE,
 .llseek   = no_llseek,
 .read   = i2cdev_read,
 .write   = i2cdev_write,
 .unlocked_ioctl = i2cdev_ioctl,
 .open   = i2cdev_open,
 .release = i2cdev_release,
};
static struct i2c_driver i2cdev_driver = {
 .driver = {
  .name = "dev_driver",
 },
 .attach_adapter = i2cdev_attach_adapter,
 .detach_adapter = i2cdev_detach_adapter,
};

 

2.i2c-core.c(i2c核心層組件)

    功能:1)註冊一條i2c總線
         2)提供基本的接口函數,用來創建上層與下層的鏈接this

i2c_init   //入口函數
  /*註冊I2C總線*/
 bus_register( &i2c_bus_type);
   
struct bus_type i2c_bus_type = {   //實際的物理總線,I2C總線
 .name   = "i2c",
 .match   = i2c_device_match,   //匹配函數
 .probe   = i2c_device_probe,
 .remove   = i2c_device_remove,
 .shutdown = i2c_device_shutdown,
 .pm   = &i2c_device_pm_ops,
};
static int i2c_device_match( struct device *dev, struct device_driver *drv)
{
  struct i2c_client *client = i2c_verify_client(dev);
  struct i2c_driver *driver;
  if ( !client)
   return 0;
 driver = to_i2c_driver(drv);
  /* match on an id table if there is one */
  if (driver - >id_table)
   return i2c_match_id(driver - >id_table, client) != NULL;
     while (id - >name[ 0]) {
      if (strcmp(client - >name, id - >name) == 0)
       return id;
     id ++;
    }
  return 0;
}

涉及的重要結構體:

struct i2c_client {      //表示一個i2c設備
  unsigned short flags;    /* div., see below  */
  unsigned short addr;    /*器件地址*/
  char name[I2C_NAME_SIZE];   /*名字*/
  struct i2c_adapter *adapter; /*所屬適配器,所屬控制器*/
  struct i2c_driver *driver;   /*設備驅動*/
  struct device dev;     /* the device structure  */
  int irq;       /* irq issued by device  */
  struct list_head detected;
};
struct i2c_driver {      //用來表示i2c驅動
  unsigned int class;
  /* Notifies the driver that a new bus has appeared or is about to be
  * removed. You should avoid using this if you can, it will probably
  * be removed in a near future.
  */

  int ( *attach_adapter)( struct i2c_adapter *);
  int ( *detach_adapter)( struct i2c_adapter *);
  /*probe函數:初始化工做,設備檢測,*/
  int ( *probe)( struct i2c_client *, const struct i2c_device_id *);
  int ( *remove)( struct i2c_client *);
  struct device_driver driver;     //設備驅動
  const struct i2c_device_id *id_table;   //指定此驅動能爲哪些設備服務
 ...
 ...
};
struct i2c_adapter {     //表示一個i2c適配器/i2c控制器
  const struct i2c_algorithm *algo; /* the algorithm to access the bus */
   /*操做方法*/
   int ( *master_xfer)( struct i2c_adapter *adap, struct i2c_msg *msgs, int num);
  int nr;      /*適配器的號碼*/
 ...
 ...
};
struct i2c_msg {      //表示一個i2c數據包
 __u16 addr;       /*設備地址*/
 __u16 flags;      /*表示:1-表示讀包 0-表示寫包*/
 __u16 len;       /*數據包的長度*/
 __u8 *buf;       /*真正的數據*/
 ...
 ...
};

涉及的重要函數接口:

/*註冊一個i2c控制器*/
int i2c_add_adapter( struct i2c_adapter *adapter)
int i2c_del_adapter( struct i2c_adapter *adap)
/*註冊i2c驅動*/
int i2c_add_driver( struct i2c_driver *driver)
int i2c_add_numbered_adapter( struct i2c_adapter *adap)
int i2c_del_numbered_adapter( struct i2c_adapter *adap)
extern int i2c_del_driver( struct i2c_driver *driver);
/*接收i2c數據包*/
int i2c_master_recv( struct i2c_client *client, char *buf, int count)
/*發送i2c數據包*/
int i2c_master_send( struct i2c_client *client, const char *buf, int count)
/*提交i2c數據包到總線驅動層*/
int i2c_transfer( struct i2c_adapter *adap, struct i2c_msg *msgs, int num)

 

3.busses目錄:i2c總線驅動/i2c控制器驅動/i2c適配器驅動

    i2c-s3c2410.cspa

    功能:1)實現對i2c控制器的初始化
         2)實現操做方法(實現i2c協議,完成數據的發送)
code

 

如何用通用接口驅動來操做i2c設備

open

app :  open( "/dev/i2c-0", O_RDWR);
== == == == == == == == == == == == == == == == == == =
sys :  sys_open
   ...
   ...
i2c -dev.c struct file_operations i2cdev_fops
    .open   = i2cdev_open,
      /*構建一個i2c_client*/
      struct i2c_client *client; 
      struct i2c_adapter *adap;  
      /*獲取適配器*/
     adap = i2c_get_adapter(i2c_dev - >adap - >nr);
     client = kzalloc( sizeof( *client), GFP_KERNEL);
     client - >driver = &i2cdev_driver;   //指定i2c設備驅動
     client - >adapter = adap;      //指定適配器
     file - >private_data = client;

ioctl

app :  ioctl(fd, I2C_SLAVE, 0x48)
== == == == == == == == == == == == == == == == == == == == == == ==
sys :  sys_ioctl
   ...
   ...
i2c -dev.c struct file_operations i2cdev_fops
    .unlocked_ioctl = i2cdev_ioctl,
      /*獲取i2c_client*/
      struct i2c_client *client = file - >private_data;
      switch (cmd) {
       case I2C_SLAVE :    I2C_M_TEN :是否爲 10位尋址的設備
        if ((arg > 0x3ff) ||(((client - >flags & I2C_M_TEN) == 0) && arg > 0x7f))
         return -EINVAL;
       client - >addr = arg;   //0x48
     }

write

app :  write(fd, wbuf, 1)
== == == == == == == == == == == == == == == == == == == == == == == =
sys :  sys_write
   ...
   ...
i2c -dev.c struct file_operations i2cdev_fops
    .write   = i2cdev_write,
      /*獲取i2c_client*/
      struct i2c_client *client = file - >private_data;
      char *tmp;
     tmp = kmalloc(count, GFP_KERNEL);
     copy_from_user(tmp, buf, count)
     
      /*發送數據到核心層*/
i2c -core.c   i2c_master_send(client, tmp, count);
       struct i2c_msg msg;    //表示i2c數據包
       /*填充數據包*/
      msg.addr = client - >addr;     //0x48
      msg.flags = client - >flags & I2C_M_TEN; //寫
      msg.len = count;       //1
      msg.buf = ( char *)buf;      //wbuf 0x0
       /*提交數據給總線驅動層*/
      i2c_transfer(adap, &msg, 1);
        if (adap - >algo - >master_xfer) 
i2c_s3c2410.c      adap - >algo - >master_xfer(adap, msgs, num);    //s3c24xx_i2c_xfer
         s3c24xx_i2c_xfer
          

 

@成鵬致遠blog

(blogs:http://lcw.cnblogs.com接口

(emailwwwlllll@126.com)rem

(qq552158509get



相關文章
相關標籤/搜索