LinuxI2C总线驱动深入分析

                LinuxI2C总线驱动深入分析

Kernel版本:2.6.32

平台: mips

 

 

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

 

I2C 总线及device注册过程

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

 

static struct i2c_board_info i2c1_devs[]__initdata = {
         {
                   I2C_BOARD_INFO("lm75",0x48),
         },
};
 


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

 

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

 

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

int __init i2c_register_board_info(int busnum, struct i2c_board_info const *info,unsigned len)
 
                  if (busnum >=__i2c_first_dynamic_bus_num)
                   __i2c_first_dynamic_bus_num= busnum + 1;
 
         for(status = 0; len; len--, info++) {
                   structi2c_devinfo    *devinfo;
 
                   devinfo= kzalloc(sizeof(*devinfo), GFP_KERNEL);
                   if(!devinfo) {
                            pr_debug("i2c-core:can't register boardinfo!\n");
                            status= -ENOMEM;
                            break;
                   }
 
                   devinfo->busnum= busnum;
                   devinfo->board_info= *info;
                   list_add_tail(&devinfo->list,&__i2c_board_list);
         }

 

为每一个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。

 

inti2c_add_numbered_adapter(struct i2c_adapter *adap)
{
………
         if (status == 0)
                   status =i2c_register_adapter(adap);
         return status;
}

调用i2c_register_adapter来注册传入的adapter.

 

static inti2c_register_adapter(struct i2c_adapter *adap)
{
         ………
         dev_set_name(&adap->dev,"i2c-%d", adap->nr);
         adap->dev.bus = &i2c_bus_type;
         adap->dev.type =&i2c_adapter_type;
         res = device_register(&adap->dev);
         if (res)
                   goto out_list;
         ……………..
         res =class_compat_create_link(i2c_adapter_compat_class, &adap->dev,
                                            adap->dev.parent);
         if (res)
                   dev_warn(&adap->dev,
                             "Failed to create compatibility classlink\n");
         if (adap->nr <__i2c_first_dynamic_bus_num)
                   i2c_scan_static_board_info(adap);
}
 
static voidi2c_scan_static_board_info(struct i2c_adapter *adapter)
{
         struct i2c_devinfo    *devinfo;
 
         down_read(&__i2c_board_lock);
         list_for_each_entry(devinfo,&__i2c_board_list, list) {
                   if (devinfo->busnum ==adapter->nr
                                     &&!i2c_new_device(adapter,
                                                        &devinfo->board_info))
                            dev_err(&adapter->dev,
                                     "Can'tcreate device at 0x%02x\n",
                                     devinfo->board_info.addr);
         }
         up_read(&__i2c_board_lock);
}

 

首先,生成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结构。

 

int i2c_register_driver(struct module *owner, struct i2c_driver*driver)
{
         int res;
 
         /* Can't registeruntil after driver model init */
         if(unlikely(WARN_ON(!i2c_bus_type.p)))
                   return-EAGAIN;
 
         /* add the driver tothe list of i2c drivers in the driver core */
         driver->driver.owner= owner;
         driver->driver.bus= &i2c_bus_type;
 
         /* When registrationreturns, the driver core
          * will have called probe() for allmatching-but-unbound devices.
          */
         res =driver_register(&driver->driver);
         if (res)
                   return res;
 
         pr_debug("i2c-core:driver [%s] registered\n", driver->driver.name);
 
         INIT_LIST_HEAD(&driver->clients);
         /* Walk the adaptersthat are already present */
         mutex_lock(&core_lock);
         bus_for_each_dev(&i2c_bus_type,NULL, driver, __attach_adapter);
         mutex_unlock(&core_lock);
 
         return 0;
}

 

由分析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。

 

intbus_for_each_drv(struct bus_type *bus, struct device_driver *start,
                        void *data, int (*fn)(struct device_driver*, void *))
{
         struct klist_iter i;
         struct device_driver *drv;
         int error = 0;
 
         if (!bus)
                   return -EINVAL;
 
         klist_iter_init_node(&bus->p->klist_drivers,&i,
                                 start ? &start->p->knode_bus :NULL);
         while ((drv = next_driver(&i))&& !error)
                   error = fn(drv, data);
         klist_iter_exit(&i);
         return error;
}
 

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

static int i2c_do_add_adapter(structdevice_driver *d, void *data)
{
         structi2c_driver *driver = to_i2c_driver(d);
         structi2c_adapter *adap = data;
 
         /*Detect supported devices on that bus, and instantiate them */
         i2c_detect(adap,driver);
 
         /*Let legacy drivers scan this bus for matching devices */
         if(driver->attach_adapter) {
                   /*We ignore the return code; if it fails, too bad */
                   driver->attach_adapter(adap);
         }
         return0;
}

 

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

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

 

         address_data= driver->address_data;
         if(!driver->detect || !address_data)
                   return0;
 
 
staticint 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)
                   returni2c_match_id(driver->id_table, client) != NULL;
 
         return 0;
}

         至此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位和广播呼叫从地址类型 


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


 

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

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值