这里的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;
}
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.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的电源管理(2.0)CONFIG_I2C_COMPAT 这个宏不知道它具体是起什么作用,没看明白,请高人指点。在操作eeprom 的过程中,该宏是没有被定义的。
(3.0)这里是添加一个虚假的iic client 驱动,实际里面没有做任何的事情,不知为何要定义它。