msm7227平台Linux I2C驱动分析(2.6.29)(2)

Linux内核的所有适配器驱动程序都在driver/i2c/busses/目录下,当前高通的驱动是i2c-msm.c,适配器驱动的注册过程如下:


在kernel中提供了两个adapter注册接口,分别为i2c_add_adapter()和i2c_add_numbered_adapter().由于在系统中可能存在多个adapter,因为将每一条I2C总线对应一个编号,下文中称为I2C总线号。对于i2c_add_adapter()而言,它使用的是动态总线号,即由系统给其分配一个总线号,而i2c_add_numbered_adapter()则是自己指定总线号,如果这个总线号非法或者是被占用,就会注册失败。高通的adapter驱动使用了i2c_add_numbered_adapter()注册,总线号最初保存在platform_data中。
I2C adapter以platform_device方式注册进系统,在proble函数中初始化了struct i2c_adapter结构:


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;  
 
 /* --- administration stuff. */ 
 int (*client_register)(struct i2c_client *);  
 int (*client_unregister)(struct i2c_client *);  
 
 /* data fields that are valid for all devices */ 
 u8 level;    /* nesting level for lockdep */ 
 struct mutex bus_lock;  
 struct mutex clist_lock;  
 
 int timeout;   /* in jiffies */ 
 int retries;  
 struct device dev;  /* the adapter device */ 
 
 int nr; /*该成员描述了总线号*/ 
 struct list_head clients; /* i2c_client结构链表,该结构包含device,driver和 
adapter结构*/ 
 char name[48];  
 struct completion dev_released;  
}; 
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;

/* --- administration stuff. */
 int (*client_register)(struct i2c_client *);
 int (*client_unregister)(struct i2c_client *);

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

int timeout;   /* in jiffies */
 int retries;
 struct device dev;  /* the adapter device */

int nr; /*该成员描述了总线号*/
 struct list_head clients; /* i2c_client结构链表,该结构包含device,driver和
adapter结构*/
 char name[48];
 struct completion dev_released;
};

其中nr的值是在arch\arm\mach-msm\devices.c中定义的:
struct platform_device msm_device_i2c = {  
 .name  = "msm_i2c",  
 .id  = 0,  
 .num_resources = ARRAY_SIZE(resources_i2c),  
 .resource = resources_i2c,  
};  
struct platform_device msm_device_i2c_2 = {  
 .name  = "msm_i2c",  
 .id  = 2,  
 .num_resources = ARRAY_SIZE(resources_i2c_2),  
 .resource = resources_i2c_2,  
}; 
struct platform_device msm_device_i2c = {
 .name  = "msm_i2c",
 .id  = 0,
 .num_resources = ARRAY_SIZE(resources_i2c),
 .resource = resources_i2c,
};
struct platform_device msm_device_i2c_2 = {
 .name  = "msm_i2c",
 .id  = 2,
 .num_resources = ARRAY_SIZE(resources_i2c_2),
 .resource = resources_i2c_2,
};

该结构以参数形式传进i2c_add_numbered_adapter(),下一步将进入


static int i2c_register_adapter(struct i2c_adapter *adap)  
{  
 int res = 0, dummy;  
 
 /* Can't register until after driver model init */ 
 if (unlikely(WARN_ON(!i2c_bus_type.p)))  
  return -EAGAIN;  
 
 mutex_init(&adap->bus_lock);  
 mutex_init(&adap->clist_lock);  
 INIT_LIST_HEAD(&adap->clients);/*初始化设备链表*/ 
 
 mutex_lock(&core_lock);  
 
 /* Add the adapter to the driver core. 
  * If the parent pointer is not set up, 
  * we add this adapter to the host bus. 
  */ 
 if (adap->dev.parent == NULL) {  
  adap->dev.parent = &platform_bus;/*父设备是platform_bus*/ 
  pr_debug("I2C adapter driver [%s] forgot to specify " 
    "physical device\n", adap->name);  
 }  
 dev_set_name(&adap->dev, "i2c-%d", adap->nr);/*设备节点名字*/ 
 adap->dev.release = &i2c_adapter_dev_release;  
 adap->dev.class = &i2c_adapter_class;  
 res = device_register(&adap->dev); /*注册adapter这个设备本身*/ 
 if (res)  
  goto out_list;  
 
 dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);  
 
 /*以下部分完成i2c设备和驱动的注册*/ 
 if (adap->nr < __i2c_first_dynamic_bus_num)/*主板初始化时的动态总线号,该值已导出符号表*/ 
  i2c_scan_static_board_info(adap);/*完成新类型i2c设备的注册,一般只在主板初始化时*/ 
 
 /* Notify drivers */ 
 dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap,  
     i2c_do_add_adapter);  /*探测总线上的所有i2c设备驱动,同时完成client、driver、device、adapter的绑定,但driver->address_data非空的情况下有用,而这又意味着只对旧的i2c机制有效*/ 
 
out_unlock:  
 mutex_unlock(&core_lock);  
 return res;  
 
out_list:  
 idr_remove(&i2c_adapter_idr, adap->nr);  
 goto out_unlock;  

static int i2c_register_adapter(struct i2c_adapter *adap)
{
 int res = 0, dummy;

/* Can't register until after driver model init */
 if (unlikely(WARN_ON(!i2c_bus_type.p)))
  return -EAGAIN;

mutex_init(&adap->bus_lock);
 mutex_init(&adap->clist_lock);
 INIT_LIST_HEAD(&adap->clients);/*初始化设备链表*/

mutex_lock(&core_lock);

/* Add the adapter to the driver core.
  * If the parent pointer is not set up,
  * we add this adapter to the host bus.
  */
 if (adap->dev.parent == NULL) {
  adap->dev.parent = &platform_bus;/*父设备是platform_bus*/
  pr_debug("I2C adapter driver [%s] forgot to specify "
    "physical device\n", adap->name);
 }
 dev_set_name(&adap->dev, "i2c-%d", adap->nr);/*设备节点名字*/
 adap->dev.release = &i2c_adapter_dev_release;
 adap->dev.class = &i2c_adapter_class;
 res = device_register(&adap->dev); /*注册adapter这个设备本身*/
 if (res)
  goto out_list;

dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);

/*以下部分完成i2c设备和驱动的注册*/
 if (adap->nr < __i2c_first_dynamic_bus_num)/*主板初始化时的动态总线号,该值已导出符号表*/
  i2c_scan_static_board_info(adap);/*完成新类型i2c设备的注册,一般只在主板初始化时*/

/* Notify drivers */
 dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap,
     i2c_do_add_adapter);  /*探测总线上的所有i2c设备驱动,同时完成client、driver、device、adapter的绑定,但driver->address_data非空的情况下有用,而这又意味着只对旧的i2c机制有效*/

out_unlock:
 mutex_unlock(&core_lock);
 return res;

out_list:
 idr_remove(&i2c_adapter_idr, adap->nr);
 goto out_unlock;
}

i2c_scan_static_board_info对应的初始化过程在board-msm7x27.c中完成,
i2c_register_board_info(0, i2c_devices, ARRAY_SIZE(i2c_devices));
6. I2C设备7. 驱动
驱动的编写方法已在《msm7227-I2C设备驱动实现要点.doc》中介绍,此节分析驱动和设备的注册过程。

msm7227平台Linux I2C驱动分析(2.6.29)

linux

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wwswys.html