linux IIC子系统分析(四)——I2c bus初始化

这里的I2C Bus 并不是通讯上的总线,而是linux系统为了管理设备和驱动而虚拟出来的,在I2C Bus用来挂载后面将会使用到的I2C 适配器(adapter)和I2C设备(client)。另外,我们即将会使用到platform device和platform driver。注意这里的i2c bus与platform bus不是属于同一个类型的总线,platform bus用来管理platform driver 和platform device。这里不要弄混淆了。.在整个linux 系统中只有一条platform bus,它在内核启动时初始化:

start_kernel ->

rest_init ->

kernel_thread(创建系统进程) -> 

kernel_init -> do_basic_setup -> 

driver_init -> platform_bus_init -> 

device_register(&platform_bus)


根据上一章我们知道linux iic子系统我们首先初始化的是i2c_init() 函数,IIC Bus 就是在该函数中初始化的。

/dricer/i2c/i2c-core.c

static int __init i2c_init(void)
{
	int retval;

	retval = bus_register(&i2c_bus_type);                                (1.0)
	if (retval)
		return retval;
#ifdef CONFIG_I2C_COMPAT                                                     (2.0)
	i2c_adapter_compat_class = class_compat_register("i2c-adapter");     
	if (!i2c_adapter_compat_class) {
		retval = -ENOMEM;
		goto bus_err;
	}
#endif
	retval = i2c_add_driver(&dummy_driver);                               (3.0)
	if (retval)
		goto class_err;
	return 0;

class_err:
#ifdef CONFIG_I2C_COMPAT
	class_compat_unregister(i2c_adapter_compat_class);
bus_err:
#endif
	bus_unregister(&i2c_bus_type);
	return retval;
}


(1.0)通过bus_register()函数注册IIC总线。我们看参数i2c_bus_type,它被定义为:

struct bus_type i2c_bus_type = {
	.name		= "i2c",
	.match		= i2c_device_match,                 (1.1)
	.probe		= i2c_device_probe,                 (1.2)
	.remove		= i2c_device_remove,
	.shutdown	= i2c_device_shutdown,
	.suspend	= i2c_device_suspend,
	.resume		= i2c_device_resume,
};

(1.1)总线提供的match方法:match方法用来进行 device 和driver 的匹配,在向总线注册设备或是驱动的的时候会调用此方法。

其函数定义为:

static int i2c_device_match(struct device *dev, struct device_driver *drv)
{
	struct i2c_client	*client = i2c_verify_client(dev);            (1.1.0)
	struct i2c_driver	*driver;

	if (!client)
		return 0;                                                    (1.1.1)

	driver = to_i2c_driver(drv);
	/* match on an id table if there is one */
	if (driver->id_table)
		return i2c_match_id(driver->id_table, client) != NULL;       (1.1.2)

	return 0;
}
(1.1.0)用struct i2c_client 来描述一个具体的IIC设备,这里指的是client device   。
(1.1.1)如果在设备树中没有搜索到设备参数就直接返回。表示匹配不成功。

(1.1.2)如果IIC驱动的id_table 存在的话,使用i2c_match_id 进行函数进行匹配。匹配的方法是拿id_table 中的每一项与client 的name 进行匹配,如果名字相同则匹配成功。从这里我们可以看出IIC总线的匹配方式与platform 总线的匹配方式是不同的:

IIC总线根据设备名字和驱动中的id_table进行匹配

platform总线根据设备名字和设备驱动名字进行匹配


(1.2)总线提供的probe方法:probe方法在完成设备和驱动的配对之后调用执行。

static int i2c_device_probe(struct device *dev)
{
	struct i2c_client	*client = i2c_verify_client(dev);
	struct i2c_driver	*driver;
	int status;

	if (!client)
		return 0;

	driver = to_i2c_driver(dev->driver);
	if (!driver->probe || !driver->id_table)
		return -ENODEV;
	client->driver = driver;
	if (!device_can_wakeup(&client->dev))                                       (1.2.0)
		device_init_wakeup(&client->dev,
					client->flags & I2C_CLIENT_WAKE);
	dev_dbg(dev, "probe\n");

	status = driver->probe(client, i2c_match_id(driver->id_table, client));     (1.2.1)
	if (status)
		client->driver = NULL;
	return status;
}
(1.2.0)IIC的电源管理
(1.2.1)调用IIC设备驱动中的Probe 函数


(2.0)CONFIG_I2C_COMPAT 这个宏不知道它具体是起什么作用,没看明白,请高人指点。在操作eeprom 的过程中,该宏是没有被定义的。


(3.0)这里是添加一个虚假的iic client 驱动,实际里面没有做任何的事情,不知为何要定义它。

你可能感兴趣的:(IIC)