上一章我们对I2C模块做了总体框架的分析,本章我们主要分析下I2C模块的总线部分,主要涉
及总线初始化、总线相关属性、总线相关接口函数处理等几部分
I2c bus的定义
I2c bus的定义如下,主要定义了i2c总线的匹配检测接口、探测接口、移除接口以及电源管理相关的接口。
struct bus_type i2c_bus_type = {
/*总线的名称,同时也是在sysfs目录下创建子目录的名称*/
.name = "i2c",
/
/*该接口用于验证i2c device与i2c driver是否匹配*/
.match = i2c_device_match,
/*当device与driver匹配后,则调用该总线的probe接口对设备进行探测*/
.probe = i2c_device_probe,
/*当设备或驱动注销时(调用device_unregister、driver_unregister),调用该接口
进行注销操作*/
.remove = i2c_device_remove,
/*以下两个变量,为电源管理相关的接口*/
.shutdown = i2c_device_shutdown,
.pm = &i2c_device_pm_ops,
};
i2c_device_match接口分析
该接口主要实现i2c device与i2c driver匹配检测,该接口的实现流程如下
- 首先是调用of_driver_match_device进行匹配,当系统中支持设备树时,则可以通过该接口进行匹配检测,主要是对drv->of_match_table与dev->of_node间变量的匹配;
若需要让我们的i2c driver支持OF(也即设备树),则只需设置i2c_driver->driver->of_match_table即可。我们以一个例 子说明,如下即为支持OF模块的i2c驱动,只要完成了这个操作,即可支持OF模块的匹配操作(当然了若要支持设备 树,在probe接口中,同样需要调用设备树节点相关的接口,去获取该设备相关的资源,然后进行探测(这也是我们在 platform模块所说的资源与驱动的抽离))
static const struct of_device_id i2c_imx_dt_ids[] = {
{ .compatible = "fsl,imx1-i2c", .data = &imx1_i2c_hwdata, },
{ .compatible = "fsl,imx21-i2c", .data = &imx21_i2c_hwdata, },
{ .compatible = "fsl,vf610-i2c", .data = &vf610_i2c_hwdata, },
{ /* sentinel */ }
static struct platform_driver i2c_imx_driver = {
.probe = i2c_imx_probe,
.remove = i2c_imx_remove,
.driver = {
.name = DRIVER_NAME,
.pm = I2C_IMX_PM_OPS,
.of_match_table = i2c_imx_dt_ids,
},
.id_table = imx_i2c_devtype,
};
- 当第一种匹配不成功时,则调用acpi_driver_match_devuce针对支持acpi的设备与驱动,调用该接口继续进行匹配(对acpi不熟悉,此处先跳过);
- 当以上两种方式均没有匹配时,则调用i2c_match_id进行设备与驱动的匹配,主要是将i2c_client->name与i2c_driver->id_table中所支持的设备名称进行匹配。
i2c_device_probe接口分析
该接口为i2c总线的probe,该接口一般也就是调用driver的probe接口,实现探测操作。
该接口的流程图如下,相对来说还是比较简单的,我们主要说些i2c模块相关的实现:
- 首先根据dev->type是否为i2c_client_type来确定是否需要进行设备与驱动的绑定操作,这主要是因为i2c_adapter、i2c_client均会注册到i2c总线上,此处即为区分i2c_clinet、i2c_adapter。
- 当区分i2c_client后,则直接调用i2c_driver->probe,而不是直接调用device_driver->probe,其实大多数模块device_driver->probe与其xxx_driver->probe是相同的。
i2c_device_remove接口分析
该接口的调用流程与i2c_device_probe接口类似,首先也要确认该device是否为i2c_adapter,若为i2c_adapter,则不需要进行设备与驱动的解绑操作。
针对i2c_client,则直接调用其绑定i2c_driver->remove接口进行移除操作,并完成设备与驱动的解绑定操作。
i2c_device_match、i2c_device_remove、i2c_device_probe何时调用
上面介绍了这三个函数,下面来说明下这三个函数的调用关系及何时调用。
针对i2c_device_probe、i2c_device_match接口,在i2c_client、i2c_adapte、i2c driver注册时(通过调用device_register、driver_register接口)而实现调用,函数调用关系图如下:
其中绿色箭头相关的流程图,为i2c_device_probe接口的调用路径。i2c模块借助设备驱动模型中设备与驱动的注册接口,完成了针对i2c设备和驱动的绑定及探测操作。
针对i2c_device_remove接口,当从i2c总线上注销i2c设备或i2c驱动时,会执行到i2c_device_remove接口。借助设备驱动模型的设备注销与驱动注销接口,完成i2c设备或者i2c驱动的注销以及设备与驱动间的解绑定操作。
以上即是i2c总线变量的定义、操作接口分析以及接口间的调用关系。
I2c bus的注册
在i2c_init接口中通过调用bus_register,进行i2c总线的注册。当完成i2c bus的注册后,则i2c_bus_type以及其关联的kset、kobject、sysfs_dirent、i2c bus的属性文件、i2c属性文件的操作方式的关联,就已经建立完成,这些结构体类型的变量关联图如下图所示(这张图在之前介绍设备驱动模型时已经给出过,此处为了让不熟悉的朋友也能快速了解,又放在此处,加深记忆)。
此处不再细说bus_register,想了解的朋友,请查看以前的分析文档。此处就说下如下这张图。
- 将i2c_bus_type对应的kobject链接至系统的bus_kset,同时将bus_kset对应的kobject作为其父kobject(通过这种父子关系,以及kobject对应sysf的目录,实现在/sys/bus/目录下创建i2c子目录,即/sys/bus/i2c)。
- 为i2c_bus_type创建device与driver对应的kset,且devices_kset、drivers_kset对应的kobject,其父对象即为i2c_bus_type对应的kobject,因此完成/sys/bus/i2c/devices、/sys/bus/i2c/drivers目录的创建;
- 针对i2c_bus_type来说,没有定义特定的属性,只有通用的属性bus_attr_uevent、bus_attr_drivers_probe、bus_attr_drivers_probe,而根据这三个属性在sysfs下创建对应的文件drivers_autoprobe drivers_probe uevent(/sys/bus/i2c/目录下),而针对这三个文件的读写接口,通过i2c_bus_type的kobj_type的sysfs_ops->bus_attr_show、sysfs_ops->bus_attr_store接口,然后再调用者三个属性所定义的show/store接口。
以上便是i2c总线的介绍,内容相对来说也不是很难,大部分内容都和之前分析的LINUX内核设备驱动总线模型的内容是相似的。下一篇将i2c device、i2c driver放在一起分析,因为我们在熟悉LINUX内核设备驱动模型的基础上,分析i2c device、i2c driver则会游刃有余。