Linux I2C设备驱动编写 - 图文(3)

2019-04-15 23:11

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; } 看完后相信都会产生个疑问?怎么将相关信息放到链表中就算完事了吗?不着急,来看下内核中已经给出的解释:

* 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 \style\I2C drivers to the devices. The bus number * for any device declared using this routine is not available for dynamic * allocation. 核心内容就是说关于集成的I2C设备注册过程应该在板级代码初始化期间,也就是arch_initcall前后的时间,或者就在这个时候(board-xxx-yyy.c中),切记切记!!!一定要在I2C适配器驱动注册前完成!!!为什么说是静态注册,是因为真实的I2C设备是在适配器成功注册后才被生成的。如果在I2C适配器注册完后还想要添加I2C设备的话,就要通过新方式!(即i2c_new_device)

小弟永远要挡在老大前边嘛!老大还没出来前,小弟们赶紧前排列阵好,老大到了可不等你,你列阵也没用了。而对于迟到的小弟,自己想办法追上去吧,在原地自己列阵是白费工夫了。

对于__i2c_board_list链表中的信息是如何变成实际的i2c设备信息的过程放在之后adapter注册过程的分析中。记得,重点是i2c_register_board_info方式一定要赶在I2C适配器的注册前,这样就没有问题。

i2c_new_device

struct i2c_client * i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) { struct i2c_client *client; int status; client = kzalloc(sizeof *client, GFP_KERNEL); //为即将注册的client申请内存 if (!client) return NULL; client->adapter = adap; //绑定指定的adapter适配器 client->dev.platform_data = info->platform_data; //保存设备数据 if (info->archdata) //代码上看是DMA相关操作数据 client->dev.archdata = *info->archdata; client->flags = info->flags; //类型,(一)中说过,或是10位地址,或是使用SMBus检错 client->addr = info->addr; //设备从地址 client->irq = info->irq; //设备终端 strlcpy(client->name, info->type, sizeof(client->name)); //从设备名 //瞧!(一)中说过i2c_board_info中的信息是与i2c_client有对应关系的,灵验了吧! /* Check for address validity */ status = i2c_check_client_addr_validity(client); //检测地址是否有效,10位地址是否大于0x3ff,7位地址是否大于0x7f或为0 if (status) { //非零(实际上为-22,无效参数Invalid argument dev_err(&adap->dev, \ 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; //建立从设备与适配器的父子关系 client->dev.bus = &i2c_bus_type; client->dev.type = &i2c_client_type; client->dev.of_node = info->of_node; ACPI_HANDLE_SET(&client->dev, info->acpi_node.handle); /* For 10-bit clients, add an arbitrary offset to avoid collisions */ dev_set_name(&client->dev, \ client->addr | ((client->flags & I2C_CLIENT_TEN) ? 0xa000 : 0)); //如果是10位地址设备,那名字格式与7bit的会有不同 status = device_register(&client->dev); //注册了!注册了!!! if (status) goto out_err; dev_dbg(&adap->dev, \ client->name, dev_name(&client->dev)); return client; out_err: dev_err(&adap->dev, \ \out_err_silent: kfree(client); return NULL; } i2d_new_device没什么好多说的,由于有i2c_register_board_info的铺垫,相信也很好理解了。而i2c_new_device不但印证了i2c_client与i2c_board_info的对应关系,还顺便体现了10bit地址

设备与7bit地址设备的略微不同。通过两者的对比,可以再总结出几点区别,从而更好的理解I2C设备的注册方法:

? ?

i2c_register_board_info的形参需要的是总线号 i2c_new_device的形参需要的直接是适配器的指针

我想这也正好能完美的说明两者的根本区别,对于板级设备更在乎适配器的总线号,因为这是固定的,没有异议的。而对于可插拔设备,因为其适配器可能非板级集成的,所以不能在乎其总线号,反而只要寻求其适配器指针进行绑定即可。后边adapter注册的分析能更好的证明这一点。

? ?

i2c_register_board_info可以同时注册多个I2C设备 i2c_new_device只能一次注册一个I2C设备

这也是其根本区别决定的,板级代码中常包含有许多I2C设备,所以i2c_register_board_info需要有同时注册多个I2C设备的能力也可以说是刚需。而i2c_new_device既然是用来给可插拔设备用的,想必设备数量并不多,而常可能只是一个两个而已,所以一次一个就够了,需求量并不大。

I2C driver

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结构体,不过现在要剔除一些不常用的成员:

struct i2c_driver { int (*probe)(struct i2c_client *, const struct i2c_device_id *); //现行通用的与对应设备进行绑定的接口函数 int (*remove)(struct i2c_client *); //现行通用与对应设备进行解绑的接口函数 void (*shutdown)(struct i2c_client *); //关闭设备 int (*suspend)(struct i2c_client *, pm_message_t mesg); //挂起设备,与电源管理有关,为省电 int (*resume)(struct i2c_client *); //从挂起状态恢复 struct device_driver driver; //I2C设备的驱动模型 const struct i2c_device_id *id_table; //匹配设备列表 ... }; 如果有可能的话,我还想再精简一下:

struct i2c_driver { int (*probe)(struct i2c_client *, const struct i2c_device_id *); //现行通用的与对应设备进行绑定的接口函数 int (*remove)(struct i2c_client *); //现行通用与对应设备进行解绑的接口函数 struct device_driver driver; //I2C设备的驱动模型 const struct i2c_device_id *id_table; //匹配设备列表 ... }; 好了,精简到这种程度,为什么把电源管理相关也干掉了呢?实际上没有,通常实际的I2C驱动喜欢在drivers中完成这个动作(以mpu3050为例):

static UNIVERSAL_DEV_PM_OPS(mpu3050_pm, mpu3050_suspend, mpu3050_resume, NULL); static const struct i2c_device_id mpu3050_ids[] = {


Linux I2C设备驱动编写 - 图文(3).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:点焊

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: