03-IIC设备和驱动的匹配过程分析

 上一节分析了 平台设备和驱动的匹配过程,即 probe 函数的自动调用过程,本节来分析 IIC 总线上设备和驱动的匹配过程。

1. 驱动端probe调用过程

1.1 i2c_driver 结构体

struct i2c_driver {
    struct device_driver driver;
    const struct i2c_device_id *id_table;
    int (*probe)(struct i2c_client *, const struct i2c_device_id *);
    int (*remove)(struct i2c_client *);

    unsigned int class;
    int (*attach_adapter)(struct i2c_adapter *) __deprecated;
    void (*shutdown)(struct i2c_client *);
    void (*alert)(struct i2c_client *, enum i2c_alert_protocol protocol, unsigned int data);
    int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);
    int (*detect)(struct i2c_client *, struct i2c_board_info *);
    const unsigned short *address_list;
    struct list_head clients;
};

1.2 i2c_driver 的实现样例

struct i2c_device_id mpu6050_id[] = {
	{.name = "mpu6050"},
	{}
};

struct i2c_driver mpu6050_driver = {
	.probe  = mpu6050_probe,	// probe  函数
	.remove = mpu6050_remove,	// remove 函数
	.driver = {
		.name  = "my_i2cdrv",	// 驱动的名字
		.owner = THIS_MODULE, 
	},
	.id_table = mpu6050_id,		// 用于和设备匹配的 id_table
};

1.3 probe的调用过程

 IIC驱动probe的调用过程和平台驱动类似,只是i2c_bus_type结构体中的变量不太一致,整体调用过程类似,详细的过程分析如下:

#define i2c_add_driver(driver) i2c_register_driver(THIS_MODULE, driver) (include\linux\i2c.h)
    |-> driver->driver.bus = &i2c_bus_type; (drivers\i2c\i2c-core.c)	// i2c总线类型
		|-> i2c_bus_type.name   = "i2c",				// 名字是i2c	
			i2c_bus_type.match	= i2c_device_match,		// match 函数
			i2c_bus_type.probe	= i2c_device_probe,		// probe 函数
			i2c_bus_type.remove	= i2c_device_remove,	// remove函数
		|-> driver_register(&driver->driver)
			|-> bus_add_driver(struct device_driver *drv) (drivers\base\bus.c)	// 添加驱动到总线上
				|-> driver_attach(struct device_driver *drv) (drivers\base\dd.c)
					|-> bus_for_each_dev(drv->bus, NULL, drv, __driver_attach) (drivers\base\bus.c)
						|-> __driver_attach(struct device *dev, void *data) (drivers\base\dd.c)
							|-> driver_match_device(struct device_driver *drv, struct device *dev) (drivers\base\base.h)	// 驱动和设备匹配
								|-> return drv->bus->match ? drv->bus->match(dev, drv) : 1
									|-> if (of_driver_match_device(dev, drv))	// 设备树风格
											return 1;
										if (acpi_driver_match_device(dev, drv))	// ACPI风格
											return 1;
										driver = to_i2c_driver(drv);
										if (driver->id_table)					// 匹配ID表
											return i2c_match_id(driver->id_table, client) != NULL;
							|-> driver_probe_device(drv, dev) (drivers\base\dd.c)		// 驱动和设备匹配成功后,执行probe函数		
								|-> really_probe(drv, dev) (drivers\base\dd.c)			// 执行真正的 probe 函数
									|->	if (dev->bus->probe) {				// 没有定义
											ret = dev->bus->probe(dev);
											if (ret)
												goto probe_failed;
										} else if (drv->probe) {			// 执行 device_driver 里面的 probe 函数
											ret = drv->probe(dev);
											if (ret)
												goto probe_failed;
										}
									|-> if (dev->bus->remove)				// remove 函数
											dev->bus->remove(dev);
										else if (drv->remove)				// 在这里调用真正的自己定义的remove函数
											drv->remove(dev);
										|-> platform_drv_probe(struct device *_dev) (drivers\base\platform.c)
											|-> struct platform_driver *drv = to_platform_driver(_dev->driver)	// 找到 platform_driver 结构体
												|-> #define to_platform_driver(drv)	(container_of((drv), struct platform_driver, driver)) (include\linux\platform_device.h)
											|-> struct platform_device *dev = to_platform_device(_dev)
												|-> #define to_platform_device(x) container_of((x), struct platform_device, dev)
											|-> if (drv->probe) {
													ret = drv->probe(dev);	// 执行真正的probe函数,也就是在 platform_driver 中自己定义的,并将 pdev 传入进去
													if (ret)
														dev_pm_domain_detach(_dev, true);
												} else {
													/* don't fail if just dev_pm_domain_attach failed */
													ret = 0;
												}

2. 设备端

2.1 i2c_client 结构体

 设备端用 struct i2c_client 结构体描述,结构体定义如下:

struct i2c_client {
	unsigned short flags;		/* div., see below		*/
	unsigned short addr;		/* chip address - NOTE: 7bit	*/
					/* addresses are stored in the	*/
					/* _LOWER_ 7 bits		*/
	char name[I2C_NAME_SIZE];
	struct i2c_adapter *adapter;	/* the adapter we sit on	*/
	struct device dev;		/* the device structure		*/
	int irq;			/* irq issued by device		*/
	struct list_head detected;
#if IS_ENABLED(CONFIG_I2C_SLAVE)
	i2c_slave_cb_t slave_cb;	/* callback for slave mode	*/
#endif
};

2.2 IIC设备向内核的注册

 IIC设备向内核的注册使用 i2c_register_board_info 函数,随着设备树的出现这种方法基本被淘汰,现在大多采用设备树的方法来对IIC设备进行描述。
 关于设备树的解析将在下一节进行分析。

将i2c设备添加到 busnum 号i2c总线上	
struct i2c_board_info {
	char		type[I2C_NAME_SIZE];
	unsigned short	flags;
	unsigned short	addr;
	void		*platform_data;
	struct dev_archdata	*archdata;
	struct device_node *of_node;
	struct fwnode_handle *fwnode;
	int		irq;
};											
int i2c_register_board_info(int busnum, struct i2c_board_info const * info, unsigned len)   (drivers\i2c\i2c-boardinfo.c)
发布了57 篇原创文章 · 获赞 64 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_36310253/article/details/103563617