一、i2c设备驱动注册
i2c设备驱动注册的调用流程为:xxx_init(设备驱动里所定义)—–>i2c_add_driver—–>i2c_register_driver
下面直接看源码,xxx_init(设备驱动里所定义)源码如下:
static int egalax_i2c_ts_init(void)
{
int result;
result = misc_register(&egalax_misc_dev);
if(result)
{
EGALAX_DBG(DBG_MODULE, " misc device register failed\n");
goto fail;
}
p_char_dev = setup_chardev(); // allocate the character device
if(!p_char_dev)
{
result = -ENOMEM;
goto fail;
}
dbgProcFile = proc_create(PROC_FS_NAME, S_IRUGO|S_IWUGO, NULL, &egalax_proc_fops);
if (dbgProcFile == NULL)
{
remove_proc_entry(PROC_FS_NAME, NULL);
EGALAX_DBG(DBG_MODULE, " Could not initialize /proc/%s\n", PROC_FS_NAME);
}
EGALAX_DBG(DBG_MODULE, " Driver init done!\n");
return i2c_add_driver(&egalax_i2c_driver);//调用i2c_add_driver函数
fail:
egalax_i2c_ts_exit();
return result;
}
module_init(egalax_i2c_ts_init);//定义驱动的init函数,也是加载驱动的时候第一个执行的函数
i2c_add_driver函数又会调用i2c_register_driver函数。下面看i2c_register_driver函数的源码:
int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
{
int res;
/* Can't register until after driver model init */
if (unlikely(WARN_ON(!i2c_bus_type.p)))
return -EAGAIN;
/* add the driver to the list of i2c drivers in the driver core */
driver->driver.owner = owner;
driver->driver.bus = &i2c_bus_type;//设定这个driver说依附的总线
/* When registration returns, the driver core
* will have called probe() for all matching-but-unbound devices.
*/
res = driver_register(&driver->driver);//向i2c_bus注册driver
/*注意这里调用的driver_register函数,这个函数又会调用其他函数对driver和device进行匹配(其中的匹配过程会在下一篇中详细接收),若匹配成功,i2c_register_driver返回res,结束执行;如不成功,则会往下执行i2c_for_each_dev函数(这个函数接下来调用的其他函数会动态注册i2c设备,这个动态注册设备的过程会在下面介绍);
if (res)
return res;
/* Drivers should switch to dev_pm_ops instead. */
if (driver->suspend)
pr_warn("i2c-core: driver [%s] using legacy suspend method\n",
driver->driver.name);
if (driver->resume)
pr_warn("i2c-core: driver [%s] using legacy resume method\n",
driver->driver.name);
pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
INIT_LIST_HEAD(&driver->clients);
/* Walk the adapters that are already present */
i2c_for_each_dev(driver, __process_new_driver);//当driver_register中device和driver匹配不成功的时候,会执行此函数;
return 0;
}
至此设备驱动的注册就完成了。
二、i2c的设备注册
1.静态注册
static struct i2c_board_info i2c_ina219_devs[] __initdata = {
{ I2C_BOARD_INFO("egalax_i2c", 0x2a), },
}
然后在同一c文件里调用i2c_register_board_info函数将设备信息加入到内核的设备链表里,i2c_register_board_info源码如下(源码位于driver/i2c/i2c-boardinfo.c),
int __init i2c_register_board_info(int busnum,
struct i2c_board_info const *info, unsigned len)
{
int status;
down_write(&__i2c_board_lock);
/* 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_tail设备链表中
}
up_write(&__i2c_board_lock);
return status;
}
函数第一个参数表示添加的i2c总线的组号,第二个参数是要注册的i2c_board_info的结构体指针,第三个参数是指i2c_board_info中成员的个数。
int i2c_add_numbered_adapter(struct i2c_adapter *adap)
{
int id;
int status;
if (adap->nr == -1) /* -1 means dynamically assign bus id */i2c总线的组有动态分配和静态之分,当adap->nr == -1的时候为静态注册;
return i2c_add_adapter(adap);
if (adap->nr & ~MAX_ID_MASK)
return -EINVAL;
retry:
if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)
return -ENOMEM;
mutex_lock(&core_lock);//互斥锁
/* "above" here means "above or equal to", sigh;
* we need the "equal to" result to force the result
*/
status = idr_get_new_above(&i2c_adapter_idr, adap, adap->nr, &id);
if (status == 0 && id != adap->nr) {
status = -EBUSY;
idr_remove(&i2c_adapter_idr, id);
}
mutex_unlock(&core_lock);//释放互斥锁
if (status == -EAGAIN)
goto retry;
if (status == 0)
status = i2c_register_adapter(adap);//调用i2c_register_adapter
return status;
}
下面看i2c_register_adapter函数源码:
static int i2c_register_adapter(struct i2c_adapter *adap)
{
int res = 0;
/* Can't register until after driver model init */
if (unlikely(WARN_ON(!i2c_bus_type.p))) {
res = -EAGAIN;
goto out_list;
}
/* Sanity checks */
if (unlikely(adap->name[0] == '\0')) {
pr_err("i2c-core: Attempt to register an adapter with "
"no name!\n");
return -EINVAL;
}
if (unlikely(!adap->algo)) {
pr_err("i2c-core: Attempt to register adapter '%s' with "
"no algo!\n", adap->name);
return -EINVAL;
}
//这里的likely()指很大几率执行if分支的代码,编译时提醒编译器放在前面;unlikel指很大几率执行else分支的代码,编译时提醒编译器将else的代码放在前面。这样做为了提高cpu的运行速率;
rt_mutex_init(&adap->bus_lock);
mutex_init(&adap->userspace_clients_lock);
INIT_LIST_HEAD(&adap->userspace_clients);
/* Set default timeout to 1 second if not already set */
if (adap->timeout == 0)
adap->timeout = HZ;
dev_set_name(&adap->dev, "i2c-%d", adap->nr);//设置 adap->dev.kobj.name 为 i2c-0 ,它将出现在 sysfs 中
adap->dev.bus = &i2c_bus_type; //此设备依附的总线类型是i2c总线类型;
adap->dev.type = &i2c_adapter_type; //此设备的设备类型是i2c_adapter;
res = device_register(&adap->dev); //注册i2c_adapter设备;
if (res)
goto out_list;
dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
#ifdef CONFIG_I2C_COMPAT
res = class_compat_create_link(i2c_adapter_compat_class, &adap->dev,
adap->dev.parent);
if (res)
dev_warn(&adap->dev,
"Failed to create compatibility class link\n");
#endif
/* create pre-declared device nodes */
if (adap->nr < __i2c_first_dynamic_bus_num)
i2c_scan_static_board_info(adap);//扫描设备链表上的所有硬件设备
/* Notify drivers */
mutex_lock(&core_lock);
bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);
mutex_unlock(&core_lock);
return 0;
out_list:
mutex_lock(&core_lock);
idr_remove(&i2c_adapter_idr, adap->nr);
mutex_unlock(&core_lock);
return res;
}
i2c_register_adapter这个函数主要做两件事:
1.注册自己的i2c_adapter设备;
2.调用i2c_scan_static_board_info函数,创建与i2c_adapter总线号相同的其他设备;
下面主要看i2c_scan_static_board_info函数,源码如下:
static void i2c_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) { //遍历__i2c_board_list,并以此取出每个设备
if (devinfo->busnum == adapter->nr//adapter->nr==0,当取出设备的busnum==0时,调用i2c_new_device函数;
&& !i2c_new_device(adapter,
&devinfo->board_info))
dev_err(&adapter->dev,
"Can't create device at 0x%02x\n",
devinfo->board_info.addr);
}
up_read(&__i2c_board_lock);
}
下面来看i2c_new_device函数。源码如下:
struct i2c_client *
i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
{
printk("********************wbx:i2c_new_device begin\n");
struct i2c_client *client;
int status;
client = kzalloc(sizeof *client, GFP_KERNEL);
if (!client)
return NULL;
client->adapter = adap; //要创建的i2c_client依附到当前的i2c_adapter控制器上
client->dev.platform_data = info->platform_data;
if (info->archdata)
client->dev.archdata = *info->archdata;
client->flags = info->flags;
client->addr = info->addr;//设置设备的地址
client->irq = info->irq;//中断编号默认为0,在启动设备中通过gpio_to_irq会对irq重新赋值
strlcpy(client->name, info->type, sizeof(client->name));//对i2c_client的名字进行赋值,名字很重要,靠这个名字和驱动的id_table进行匹配
/* Check for address validity */
status = i2c_check_client_addr_validity(client);
if (status) {
dev_err(&adap->dev, "Invalid %d-bit I2C address 0x%02hx\n",
client->flags & I2C_CLIENT_TEN ? 10 : 7, client->addr);
goto out_err_silent;
}
/* Check for address business */
status = i2c_check_addr_busy(adap, client->addr);
if (status)
goto out_err;
client->dev.parent = &client->adapter->dev;//设置其父设备为:i2c_adapter设备
client->dev.bus = &i2c_bus_type; //设备其依附的总线
client->dev.type = &i2c_client_type;//其属性设置为设备属性
client->dev.of_node = info->of_node;
/* For 10-bit clients, add an arbitrary offset to avoid collisions */
dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap),
client->addr | ((client->flags & I2C_CLIENT_TEN)
? 0xa000 : 0));
status = device_register(&client->dev);//注册这个设备
if (status)
goto out_err;
printk("client [%s] registered with bus id %s\n",
client->name, dev_name(&client->dev));
return client;
out_err:
dev_err(&adap->dev, "Failed to register i2c client %s at 0x%02x "
"(%d)\n", client->name, client->addr, status);
out_err_silent:
kfree(client);
return NULL;
}
此函数主要调用device_register函数来进行设备注册;
到这里静态注册设备的分析以及完成了,通过i2c_board_info这个结构体或者dts来配置硬件信息,再通过调用i2c_register_board_info函数来向设备链表来注册硬件设备,然后系统在注册i2c_adapter完成后,取出链表中的每一个设备,当设备的i2c的编号和i2c_adapter相同时,在调用device_register对此设备进行注册;
二、动态注册(以i2c设备为例)
另外还有一种设备注册的方法是动态注册,这种动态注册方法需要配合设备驱动程序进行,如果没有第三方的的配置文件的话,要将部分硬件信息写到设备驱动中,这里以eeti公司的egalax_i2c.c触摸屏设备驱动程序移植到全志R16平台上例:
前面以及分析过了i2c_register_driver这个函数,在i2c_register_driver函数中会调用driver_register函数,若此函数不能正确的匹配dirver和device,则向下执行i2c_for_each_dev这个函数;下面就以i2c_for_each_dev这个函数为入口点,来看设备是怎么进行动态注册的。
先看i2c_register_driver源码(driver/i2c/i2c-core.c):
int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
{
int res;
printk("********************wbx:i2c_register_driver begin\n");
/* Can't register until after driver model init */
if (unlikely(WARN_ON(!i2c_bus_type.p)))
return -EAGAIN;
/* add the driver to the list of i2c drivers in the driver core */
driver->driver.owner = owner;
driver->driver.bus = &i2c_bus_type;
/* When registration returns, the driver core
* will have called probe() for all matching-but-unbound devices.
*/
res = driver_register(&driver->driver);
if (res)
return res;
/* Drivers should switch to dev_pm_ops instead. */
if (driver->suspend)
pr_warn("i2c-core: driver [%s] using legacy suspend method\n",
driver->driver.name);
if (driver->resume)
pr_warn("i2c-core: driver [%s] using legacy resume method\n",
driver->driver.name);
pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
INIT_LIST_HEAD(&driver->clients);
/* Walk the adapters that are already present */
i2c_for_each_dev(driver, __process_new_driver);//driver_register中device和driver匹配不错的时候,会调用此函数,**注意这里的__process_new_driver,这是一个函数指针**,也传递进了i2c_for_each_dev函数,下面会讲解这边函数指针的用法,这里先提醒
return 0;
}
再看i2c_for_each_dev源码:
int i2c_for_each_dev(void *data, int (*fn)(struct device *, void *))
{
//函数的形参data就是上层函数i2c_register_driver传递过来的driver
int res;
mutex_lock(&core_lock);
res = bus_for_each_dev(&i2c_bus_type, NULL, data, fn);//在调用此函数
mutex_unlock(&core_lock);
return res;
}
看bus_for_each_dev函数源码(driver/base/bus.c):
int bus_for_each_dev(struct bus_type *bus, struct device *start,
void *data, int (*fn)(struct device *, void *))
{
struct klist_iter i;
struct device *dev;
int error = 0;
if (!bus || !bus->p)
return -EINVAL;
klist_iter_init_node(&bus->p->klist_devices, &i,
(start ? &start->p->knode_bus : NULL));//遍历链表上的所有设备
//通过next_device函数将链表上的设备一样取出然后传递给fn,也就是前面提到的__process_new_driver函数
while ((dev = next_device(&i)) && !error)
error = fn(dev, data);
klist_iter_exit(&i);
return error;
}
下面再看__process_new_driver源码拿到driver和device做了什么(这部分源码在driver/i2c/i2c-core.c):
static int __process_new_driver(struct device *dev, void *data)
{
//判断拿到的设备是否是i2c总线设备,即是不是i2c_adapter,返回0,结束词函数;继续拿下一个device,在进行判断是不是i2c_adapter,如实是则执行i2c_do_add_adapter函数
if (dev->type != &i2c_adapter_type)
return 0;}
return i2c_do_add_adapter(data, to_i2c_adapter(dev));
}
下面看调用的i2c_do_add_adapter源码:
static int i2c_do_add_adapter(struct i2c_driver *driver,
struct i2c_adapter *adap)
{
/* Detect supported devices on that bus, and instantiate them */
//进入i2c_do_add_adapter函数后先调用i2c_detect函数
i2c_detect(adap, driver);
/* Let legacy drivers scan this bus for matching devices */
if (driver->attach_adapter) {
dev_warn(&adap->dev, "%s: attach_adapter method is deprecated\n",
driver->driver.name);
dev_warn(&adap->dev, "Please use another way to instantiate "
"your i2c_client\n");
/* We ignore the return code; if it fails, too bad */
driver->attach_adapter(adap);
}
return 0;
}
看i2c_detect的源码:
static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver)
{
const unsigned short *address_list;
struct i2c_client *temp_client;
int i, err = 0;
//获取i2c_adapter设备的i2c总线号
int adap_id = i2c_adapter_id(adapter);
//获取设备驱动程序中定义的address_list
address_list = driver->address_list;
if (!driver->detect || !address_list)
{
return 0;}
//这里在判断驱动程序中是定义了detect 函数和address_list,其中一个没定义,则失败,返回0;
/* Stop here if the classes do not match */
if (!(adapter->class & driver->class))
{
printk("********************wbx:2_error\n");
return 0;}
//这里在判断驱动程序中定义的class和adapter中定义的class是否相同,不相同则失败返回0;
/*我在移植egalax_i2c这个驱动程序时,驱动中没有定义address_list,也没有定义detect 函数和class,我是仿照默认驱动的gt82x.c,进行添加的。
/* Set up a temporary client to help detect callback */
temp_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
if (!temp_client)
return -ENOMEM;
temp_client->adapter = adapter;//这里定义了一个i2c_client,下面的程序会对这个进行赋值,然后再注册
for (i = 0; address_list[i] != I2C_CLIENT_END; i += 1) {
printk("found normal entry for adapter %d, "
"addr 0x%02x\n", adap_id, address_list[i]);
temp_client->addr = address_list[i];//将检测到的i2c地址赋值给i2c_client的addr
err = i2c_detect_address(temp_client, driver);//调用此函数
if (unlikely(err))
break;
}
kfree(temp_client);
return err;
}
下面看i2c_detect_address的源码:
static int i2c_detect_address(struct i2c_client *temp_client,
struct i2c_driver *driver)
{
struct i2c_board_info info;
struct i2c_adapter *adapter = temp_client->adapter;
int addr = temp_client->addr;
int err;
/* Make sure the address is valid */
err = i2c_check_addr_validity(addr);//检测i2c地址是否有效
if (err) {
printk(&adapter->dev, "Invalid probe address 0x%02x\n",
addr);
return err;
}
/* Skip if already in use */
if (i2c_check_addr_busy(adapter, addr))//检测i2c地址是否busy
return 0;
#ifndef CONFIG_ARCH_SUNXI
/* Make sure there is something at this address */
if (!i2c_default_probe(adapter, addr))
return 0;
#endif
/* Finally call the custom detection function */
memset(&info, 0, sizeof(struct i2c_board_info));
info.addr = addr;
err = driver->detect(temp_client, &info);
/*这里定义了结构体i2c_board_info info,看了静态注册设备的话,对这个结构体很熟悉了,没有使用dts的时候必须要用i2c_board_info 结构体存放硬件信息,动态注册也一样,只是定义这个结构体的位置不同而已。
这里把在i2c_detect函数中检测到的i2c地址赋值给了info这个结构体,并将temp_client和info一起传入了驱动程序中定义的detect函数,那么detect函数拿到这两个参数做了什么呢?,看下**驱动程序中**detect函数的源码:
`static int ctp_detect(struct i2c_client *client, struct i2c_board_info *info)
{
//首先定义了一个结构体i2c_adapter 保存传递进来的temp_client结构体中的adapter成员
struct i2c_adapter *adapter = client->adapter;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)){
printk("======return=====\n");
return -ENODEV;
}//检测i2c_apater(i2c控制器的驱动能力)
/*twi_id == adapter->nr这个判断语句是重点,我们都知道每一组i2c总线挂接的有自己的i2c设备这是由硬件连接决定的,那么决定了在软件上每一个i2c_driver挂载到相应的i2c_adapter,这里进行判读,传入进来的i2c_adapter的总线号是否和我这个i2c_client设备要挂载的总线号一致;
if(twi_id == adapter->nr){
strlcpy(info->type, "egalax_i2c", 11);//若总线号相同,赋值名称,这里的名称一定要和id_table当中的相同;
return 0;
}else{
return -ENODEV;
}
}`//这里的detect函数主要就是判断总线号,然后对即将注册的i2c_client的名称赋值
if (err) {
/*-ENODEV is returned if the detection fails. We catch it
here as this isn't an error. */
printk("******************error\n");
return err == -ENODEV ? 0 : err;
}
/* Consistency check */
if (info.type[0] == '\0') {
printk( "%s detection function provided "
"no name for 0x%x\n", driver->driver.name,
addr);
} else {
struct i2c_client *client;
/* Detection succeeded, instantiate the device */
printk("Creating %s at 0x%02x\n",
info.type, info.addr);
client = i2c_new_device(adapter, &info);
/*然后在调用i2c_new_device函数,i2c_new_device在静态注册中已经分析过了,主要是调用driver_register向i2c总线注册设备;
if (client)
{list_add_tail(&client->detected, &driver->clients);
printk("add_client\n");
}//注册成功后将i2c_client加到设备链表中
else
printk(&adapter->dev, "Failed creating %s at 0x%02x\n",
info.type, info.addr);
}
return 0;
}
至此动态注册分析完成。全志的R16平台是采用此种方法进行注册硬件设备的,但是这种方法需要在驱动中写入相应的硬件信息,而且在移植的时候不一目了然。我是花了好几天才跟踪到这种动态注册的方法;