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 篇原創文章 · 獲贊 65 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章