LinuxI2C总线驱动深入分析Kernel版本:2.6.32
平台: mips
本文目的: 在工作闲暇之余,写点东西,留个念想,也证明一下自己曾经年轻过,主要的内容以I2C总线注册,设备注册,驱动注册为主线,介绍了详细的注册过程及I2C传输数据的过程。欢迎大家来探讨这些技术细节,mall:.
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;
-
-
- if(unlikely(WARN_ON(!i2c_bus_type.p)))
- return-EAGAIN;
-
-
- driver->driver.owner= owner;
- driver->driver.bus= &i2c_bus_type;
-
-
-
-
- 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);
-
- 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;
-
-
- i2c_detect(adap,driver);
-
-
- if(driver->attach_adapter) {
-
- driver->attach_adapter(adap);
- }
- return0;
- }
在i2c_detect中,首先通过i2c_adapter_id(adapter);获得当前adapter的总线id,
在I2C_DETECT中, structi2c_client *temp_client 首先,检测driver 是否存在address_data数据,如果不存在直接返回。存在的现象欢迎来一起讨论,, 主要是一些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);
-
- 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位和广播呼叫从地址类型 | 不同的总线协议(快速命令、 处理呼叫等) 无总线协议 |
暂时更新到这里,后续内容以后再做更新。