Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2132141
  • 博文数量: 288
  • 博客积分: 10594
  • 博客等级: 上将
  • 技术积分: 3469
  • 用 户 组: 普通用户
  • 注册时间: 2006-10-27 19:27
文章分类

全部博文(288)

文章存档

2012年(4)

2011年(30)

2010年(40)

2009年(32)

2008年(71)

2007年(79)

2006年(32)

分类: LINUX

2011-12-12 16:38:24

LinuxI2C总线驱动深入分析

Kernel版本:2.6.32

平台: mips

 

 

本文目的: 在工作闲暇之余,写点东西,留个念想,也证明一下自己曾经年轻过,主要的内容以I2C总线注册,设备注册,驱动注册为主线,介绍了详细的注册过程及I2C传输数据的过程。欢迎大家来探讨这些技术细节,mall:.

 

I2C 总线及device注册过程

首先,I2C注册过程为创建board_info 结构体。

 

  1. static struct i2c_board_info i2c1_devs[]__initdata = {  
  2.          {  
  3.                    I2C_BOARD_INFO("lm75",0x48),  
  4.          },  
  5. };  
  6.    


通过i2c_register_board_info, 将i2c_board_info设备结构注册进系统中去,

 

  1. i2c_register_board_info(1, i2c1_devs, ARRAY_SIZE(i2c1_devs));  

 

         i2c_register_board_info 传入的参数,busnum为总线地址,info为总线上设备描述,len为总线描述结构的大小。

  1. int __init i2c_register_board_info(int busnum, struct i2c_board_info const *info,unsigned len)  
  2.    
  3.                   if (busnum >=__i2c_first_dynamic_bus_num)  
  4.                    __i2c_first_dynamic_bus_num= busnum + 1;  
  5.    
  6.          for(status = 0; len; len--, info++) {  
  7.                    structi2c_devinfo    *devinfo;  
  8.    
  9.                    devinfo= kzalloc(sizeof(*devinfo), GFP_KERNEL);  
  10.                    if(!devinfo) {  
  11.                             pr_debug("i2c-core:can't register boardinfo!\n");  
  12.                             status= -ENOMEM;  
  13.                             break;  
  14.                    }  
  15.    
  16.                    devinfo->busnum= busnum;  
  17.                    devinfo->board_info= *info;  
  18.                    list_add_tail(&devinfo->list,&__i2c_board_list);  
  19.          }  

 

为每一个I2C设备分配i2c_devinfo结构体, 并注册到__i2c_board_list链表上,这里需要注意的一点是,设备列表上并没有出现按总线区分的现象,而是将所有总线的设备注册到一个统一的列表上。

 

经过以上这几步,I2C的board_info设备就注册好了,现在分析设备的adapter注册过程,一般设备的总线注册是由SOC厂商提供的,在SOC厂商提供的busses注册时,会遍历设备结点,下面具体分析。

         一般在设备注册的probe中,会调用i2c_add_numbered_adapter或者i2c_add_adapter的接口,注册I2C的adapter, 其中就初始化了I2C总线中的设备, 以分析i2c_add_numbered_adapter为例。

i2c_add_numbered_adapter使用静态的总线ID, i2c_add_adapter使用动态的总线ID。

 

  1. inti2c_add_numbered_adapter(struct i2c_adapter *adap)  
  2. {  
  3. ………  
  4.          if (status == 0)  
  5.                    status =i2c_register_adapter(adap);  
  6.          return status;  
  7. }  

调用i2c_register_adapter来注册传入的adapter.

 

  1. static inti2c_register_adapter(struct i2c_adapter *adap)  
  2. {  
  3.          ………  
  4.          dev_set_name(&adap->dev,"i2c-%d", adap->nr);  
  5.          adap->dev.bus = &i2c_bus_type;  
  6.          adap->dev.type =&i2c_adapter_type;  
  7.          res = device_register(&adap->dev);  
  8.          if (res)  
  9.                    goto out_list;  
  10.          ……………..  
  11.          res =class_compat_create_link(i2c_adapter_compat_class, &adap->dev,  
  12.                                             adap->dev.parent);  
  13.          if (res)  
  14.                    dev_warn(&adap->dev,  
  15.                              "Failed to create compatibility classlink\n");  
  16.          if (adap->nr <__i2c_first_dynamic_bus_num)  
  17.                    i2c_scan_static_board_info(adap);  
  18. }  
  19.    
  20. static voidi2c_scan_static_board_info(struct i2c_adapter *adapter)  
  21. {  
  22.          struct i2c_devinfo    *devinfo;  
  23.    
  24.          down_read(&__i2c_board_lock);  
  25.          list_for_each_entry(devinfo,&__i2c_board_list, list) {  
  26.                    if (devinfo->busnum ==adapter->nr  
  27.                                      &&!i2c_new_device(adapter,  
  28.                                                         &devinfo->board_info))  
  29.                             dev_err(&adapter->dev,  
  30.                                      "Can'tcreate device at 0x%02x\n",  
  31.                                      devinfo->board_info.addr);  
  32.          }  
  33.          up_read(&__i2c_board_lock);  
  34. }  

 

首先,生成bus-device, 设备device的总线ID与adapter类型, 并接着创建class接口, 如果是静态创建的总线设备,就在已注册的I2C设备链表(__i2c_board_list)中进行查找匹配,并通过查找相同的总线ID,找到相匹配的设备ID,生成client端并注册device到系统中去。

 

以上就是整个I2C总线及总线上的device注册过程。

 

I2C driver注册过程

I2C驱动注册是通过i2c_add_driver接口进行的, i2c_add_driver调用i2c_register_driver, 传入i2c_driver结构。

 

  1. int i2c_register_driver(struct module *owner, struct i2c_driver*driver)  
  2. {  
  3.          int res;  
  4.    
  5.          /* Can't registeruntil after driver model init */  
  6.          if(unlikely(WARN_ON(!i2c_bus_type.p)))  
  7.                    return-EAGAIN;  
  8.    
  9.          /* add the driver tothe list of i2c drivers in the driver core */  
  10.          driver->driver.owner= owner;  
  11.          driver->driver.bus= &i2c_bus_type;  
  12.    
  13.          /* When registrationreturns, the driver core 
  14.           * will have called probe() for allmatching-but-unbound devices. 
  15.           */  
  16.          res =driver_register(&driver->driver);  
  17.          if (res)  
  18.                    return res;  
  19.    
  20.          pr_debug("i2c-core:driver [%s] registered\n", driver->driver.name);  
  21.    
  22.          INIT_LIST_HEAD(&driver->clients);  
  23.          /* Walk the adaptersthat are already present */  
  24.          mutex_lock(&core_lock);  
  25.          bus_for_each_dev(&i2c_bus_type,NULL, driver, __attach_adapter);  
  26.          mutex_unlock(&core_lock);  
  27.    
  28.          return 0;  
  29. }  

 

由分析i2c_register_driver中得知, driver的注册相对简单, 在函数中填充总线的类型,然后通过driver_register注册进了系统。

 

通过bus_for_each_dev(&i2c_bus_type,NULL, driver, __attach_adapter);来attach adapter, 相对的,如果先注册驱动程序,也会有attach driver的过程。在这里分析device attach driver的过程,相对attach adapter比较复杂。

 

接着回到i2c_register_adapter中的bus_for_each_drv中去,查找机应的driver。

 

  1. intbus_for_each_drv(struct bus_type *bus, struct device_driver *start,  
  2.                         void *data, int (*fn)(struct device_driver*, void *))  
  3. {  
  4.          struct klist_iter i;  
  5.          struct device_driver *drv;  
  6.          int error = 0;  
  7.    
  8.          if (!bus)  
  9.                    return -EINVAL;  
  10.    
  11.          klist_iter_init_node(&bus->p->klist_drivers,&i,  
  12.                                  start ? &start->p->knode_bus :NULL);  
  13.          while ((drv = next_driver(&i))&& !error)  
  14.                    error = fn(drv, data);  
  15.          klist_iter_exit(&i);  
  16.          return error;  
  17. }  
  18.    

在bus_for_each_drv中,通过回调fn,进行drv和data的匹配, data就是我们的adapter, fn是传入的i2c_do_add_adapter。

  1. static int i2c_do_add_adapter(structdevice_driver *d, void *data)  
  2. {  
  3.          structi2c_driver *driver = to_i2c_driver(d);  
  4.          structi2c_adapter *adap = data;  
  5.    
  6.          /*Detect supported devices on that bus, and instantiate them */  
  7.          i2c_detect(adap,driver);  
  8.    
  9.          /*Let legacy drivers scan this bus for matching devices */  
  10.          if(driver->attach_adapter) {  
  11.                    /*We ignore the return code; if it fails, too bad */  
  12.                    driver->attach_adapter(adap);  
  13.          }  
  14.          return0;  
  15. }  

 

在i2c_detect中,首先通过i2c_adapter_id(adapter);获得当前adapter的总线id,

在I2C_DETECT中, structi2c_client *temp_client 首先,检测driver 是否存在address_data数据,如果不存在直接返回。存在的现象欢迎来一起讨论,, 主要是一些i2c设备的自动探测功能,目前kernel都采用静态注册在i2c_board_info中了.

 

  1.          address_data= driver->address_data;  
  2.          if(!driver->detect || !address_data)  
  3.                    return0;  
  4.    
  5.    
  6. staticint i2c_device_match(struct device *dev, struct device_driver *drv)  
  7. {  
  8.          struct i2c_client       *client = i2c_verify_client(dev);  
  9.          struct i2c_driver      *driver;  
  10.    
  11.          if (!client)  
  12.                    return 0;  
  13.    
  14.          driver = to_i2c_driver(drv);  
  15.          /* match on an id table if there is one*/  
  16.          if (driver->id_table)  
  17.                    returni2c_match_id(driver->id_table, client) != NULL;  
  18.    
  19.          return 0;  
  20. }  

         至此i2c_driver就与i2c_adapter匹配成功。 I2c 的bus match就会调用驱动程序中的probe函数。

 

      I2C的数据传输分析

         I2c 的数据传输接口主要有 i2c_smbus_read_byte_data, i2c_smbus_write_byte, i2c_smbus_read_word_data, i2c_master_send, i2c_master_recv等等接口,各传入的参数不同,但最终调用的只有两种接口,一种是i2c_smbus_xfer, 一种是i2c_transfer.

 

         这主要的区分在于smbus与i2c, SMBus与I2C的比较.

SMBus 

I2C 


最大传输速度 100kHz

最大传输速度400kHz 


最小传输速度 10kHz 

无最小传输速度 


35ms时钟低超时 

无时钟超时 


固定的逻辑电平 

逻辑电平由VDD决定 


不同的地址类型(保留、动态等) 7位、 
10位和广播呼叫从地址类型 


不同的总线协议(快速命令、 
处理呼叫等) 无总线协议 


 

         暂时更新到这里,后续内容以后再做更新。

阅读(3770) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~