上回我们说到,I2C设备是在板级代码中通过i2c_register_board_info来注册(其实我觉得理解成声明似乎更易解释)的。下面,咱们来了解这个函数:
/**
* i2c_register_board_info - statically declare I2C devices
* @busnum: identifies the bus to which these devices belong
* @info: vector of i2c device descriptors
* @len: how many descriptors in the vector; may be zero to reserve
* the specified bus number.
*
* Systems using the Linux I2C driver stack can declare tables of board info
* while they initialize. This should be done in board-specific init code
* near arch_initcall() time, or equivalent, before any I2C adapter driver is
* registered. For example, mainboard init code could define several devices,
* as could the init code for each daughtercard in a board stack.
*
* The I2C devices will be created later, after the adapter for the relevant
* bus has been registered. After that moment, standard driver model tools
* are used to bind "new style" I2C drivers to the devices. The bus number
* for any device declared using this routine is not available for dynamic
* allocation.
*
* The board info passed can safely be __initdata, but be careful of embedded
* pointers (for platform_data, functions, etc) since that won't be copied.
*/
int __init i2c_register_board_info(int busnum,struct i2c_board_info const *info, unsigned len)
{
int status;
down_write(&__i2c_board_lock);//锁写操作,在解锁前devinfo不能再被写操作
/* dynamic bus numbers will be assigned after the last static one */
if (busnum >= __i2c_first_dynamic_bus_num)
__i2c_first_dynamic_bus_num = busnum + 1;
for (status = 0; len; len--, info++) {
struct i2c_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_board_list链表中(尾部)
}
up_write(&__i2c_board_lock);//解除写操作的锁
return status;
}
由上述代码看出,i2c_register_board_info的作用就是将总线号及设备信息加入到__i2c_board_list链表中。这就完了吗,这就是设备注册了吗?说实话,我也没看明白。看看注释吧,内核解释:i2c_register_board_info,静态声明I2C设备。I2C设备信息在板级代码初始化期间,也就是arch_initcal()这个时间点附件,进行注册(声明),这个注册须在I2C适配器驱动注册前完成!
(但在此时,实际上I2C设备并未真正存在,仅仅是设备信息被声明了),而在I2C适配器驱动注册完成后,I2C device设备才真正被注册了。在这之后,如果要加入新的I2C设备,就需要新的方式来绑定I2C设备和驱动了。
走到这,你也许要问了,如果我们不使用在板级代码中注册这种方式,那么我们该如何操作呢?i2c_new_device这个函数闪耀登场了。
在gslX680_ts.c这个TP驱动文件中,有对i2c_new_device函数做了很好的调用示范。且使用了I2C_BOARD_INFO_METHOD这个宏来让你决定是使用在BOARD中注册还是使用i2c_new_device这种方式。从gslX680_ts_init函数调用中我们也了解到,i2c_register_board_info与i2c_new_device这两种方式的区别:i2c_register_board_info的形参需要的是总线号,i2c_new_device的形参需要的直接是适配器的指针。说了这么多,如果没有代码,似乎没有说服力,那么咱们就把代码贴出来吧:
static int __init gslX680_ts_init(void)
{
int gslX680_irq;
LDO_SetVoltLevel(LDO_LDO_SIM2, LDO_VOLT_LEVEL0);
LDO_TurnOnLDO(LDO_LDO_SIM2);
// sc8810_i2c_set_clk(2,400000);//add by hzy for debug gsx680,20121220
printk("%s\n", __func__);
gslX680_irq=gslX680_ts_config_pins();
gslX680_ts_setup.i2c_bus = 0;
gslX680_ts_setup.i2c_address = GSLX680_TS_ADDR;
strcpy (gslX680_ts_setup.type,GSLX680_TS_NAME);
gslX680_ts_setup.irq = gslX680_irq;
return sprd_add_i2c_device(&gslX680_ts_setup, &gslX680_ts_driver);
}
gslX680_ts_init为模块初始化函数,通过module_init(gslX680_ts_init)被系统调用。在该函数中,我们可以看到I2C设备名及设备地址,中断号等关键信息被直接定义,并最后被sprd_add_i2c_device这个函数调用来注册I2C设备。sprd_add_i2c_device函数内容不少,咱们挑关键的进行注释,你一看就明白了:
int sprd_add_i2c_device(struct sprd_i2c_setup_data *i2c_set_data, struct i2c_driver *driver)
{
struct i2c_board_info info;
struct i2c_adapter *adapter;
struct i2c_client *client;
int ret,err;
printk("%s : i2c_bus=%d; slave_address=0x%x; i2c_name=%s",__func__,i2c_set_data->i2c_bus, \
i2c_set_data->i2c_address, i2c_set_data->type);
memset(&info, 0, sizeof(struct i2c_board_info));// i2c_board_info这个结构体又出现了
info.addr = i2c_set_data->i2c_address;//传入I2C设备地址
strlcpy(info.type, i2c_set_data->type, I2C_NAME_SIZE);//I2C设备名也有了
if(i2c_set_data->irq > 0)
info.irq = i2c_set_data->irq;
adapter = i2c_get_adapter( i2c_set_data->i2c_bus);//通过总线获取到对应的适配器
if (!adapter) {
printk("%s: can't get i2c adapter %d\n",
__func__, i2c_set_data->i2c_bus);
err = -ENODEV;
goto err_driver;
}
client = i2c_new_device(adapter, &info);//根据适配器及i2c_board_info注册设备
if (!client) {
printk("%s: can't add i2c device at 0x%x\n",
__func__, (unsigned int)info.addr);
err = -ENODEV;
goto err_driver;
}
i2c_put_adapter(adapter);
ret = i2c_add_driver(driver);//加入设备驱动
if (ret != 0) {
printk("%s: can't add i2c driver\n", __func__);
err = -ENODEV;
goto err_driver;
}
return 0;
err_driver:
return err;
}
看了上面的代码,你就明白其实i2c_register_board_info与i2c_new_device都差不多,都用到了i2c_board_info。只是i2c_register_board_info用在适配器建立前,i2c_new_device用再适配器建立后。
I2C driver
再次简单总结下I2C 设备的驱动,下面是引用一位技术牛人的一段话:
I2C设备驱动。Linux内核给出的接口只有两个,一个是注册,另一个就是卸载。我们已经分析过module_i2c_driver这个宏定义,因为有它的存在,I2C设备驱动的开发可以不用在意你的I2C驱动需要如何注册以及如何卸载的,全部的精力都放在i2c_driver的完善上就可以了。
通过最开始的表单能明显察觉到,I2C子系统中I2C driver的开放接口最少,说白了就是需要驱动编写者完成完了i2c_driver放入module_i2c_driver宏中即可,而正因为如此,也恰恰说明,i2c_driver的灵活性是最高的。通常驱动会首先在意在用户空间的打开、关闭、读写等接口,但是对于i2c_driver来说,这些工作是I2C子系统已经做好的,关于常用的读写最终也是通过adapter实现的i2c_algorithm达到目的。好吧,再次说明了I2C子系统的完善程度,对于I2C设备及驱动开发来说是极其方便的。那么I2C驱动要实现什么呢?
为了让大家能够看得清楚,我们不断地重复、重复再重复这段代码,务求让大家能够重复、重复再重复地看个仔细。好了,再次回顾一下i2c_driver结构体:
static struct i2c_driver gslX680_ts_driver = {
.probe = gslX680_ts_probe,
.remove = gslX680_ts_remove,
.id_table = gslX680_ts_id,
.driver = {
.name = GSLX680_NAME,
.owner = THIS_MODULE,
},
};
说完了driver,似乎我们应该再谈一谈i2c_client与i2c_board_info的关系, 对应关系在i2c_new_device中有完整体现。
i2c_client->dev.platform_data = i2c_board_info->platform_data;
i2c_client->dev.archdata = i2c_board_info->archdata;
i2c_client->flags = i2c_board_info->flags;
i2c_client->addr = i2c_board_info->addr;
i2c_client->irq = i2c_board_info->irq;
而i2c_new_device则被i2c_scan_static_board_info所调用。至于i2c_scan_static_board_info函数,则是被i2c_register_adapter适配器注册函数所调用。调用的条件如下:
if (adap->nr < __i2c_first_dynamic_bus_num)
i2c_scan_static_board_info(adap);
如果adapter的总线号小于动态分配的总线号的最小那个,说明是板级adapter。因为通过i2c_add_adapter加入的适配器所分配的总线号一定是比__i2c_first_dynamic_bus_num大的。这也从中说明了,通过板级代码注册设备,必须要先于adapter适配器注册,否则这个条件调用就没作用了。