参考http://www.100ask.net/forum/showtopic-3842.aspx
自己也做了一下分析,对Linux2.6.32内核下I2C驱动的大致框架有了更加深入的了解
static struct platform_driver s3c24xx_i2c_driver = {
.probe = s3c24xx_i2c_probe,
.remove = s3c24xx_i2c_remove,
.id_table = s3c24xx_driver_ids,
.driver = {
.owner = THIS_MODULE,
.name = "s3c-i2c",
.pm = S3C24XX_DEV_PM_OPS,
},
};
platform_driver_register(&s3c24xx_i2c_driver); //i2c-s3c24xx.c
drv->driver.bus = &platform_bus_type;
driver_register(&drv->driver);
ret = bus_add_driver(drv);
driver_attach(drv);
bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
error = fn(dev, data); //fn = __driver_attach
driver_match_device(drv, dev) //调用platform 总线的mach 函数即plat_form_mach
drv->bus->match //bus 为plat_form_bus
driver_probe_device(drv, dev);
really_probe(dev, drv);
if (dev->bus->probe) {
ret = dev->bus->probe(dev); //如果总线的probe函数存在,则调用总线的probe函数
} else if (drv->probe) {
ret = drv->probe(dev); //否则,如果驱动的probe函数存在,则调用驱动的probe
}
该probe函数即为平台驱动s3c24xx_i2c_driver的probe函数s3c24xx_i2c_probe
platform_driver_register(&s3c24xx_i2c_driver); //i2c-s3c24xx.c
s3c24xx_i2c_probe
i2c_add_numbered_adapter(&i2c->adap);
i2c_register_adapter(adap);
dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap,i2c_do_add_adapter);
error = fn(drv, data); //= i2c_do_add_adapter
i2c_do_add_adapter
i2c_detect(adap, driver); //driver 为i2c bus上的i2c_driver
const struct i2c_client_address_data *address_data;
address_data = driver->address_data;
if (!driver->detect || !address_data) //如果i2c_driver中没有address_data 和 detect函数就立马返回
return 0;
if (driver->attach_adapter) { //为了兼容以前的版本
driver->attach_adapter(adap);
}
i2c_add_driver
i2c_register_driver(THIS_MODULE, driver);
driver->driver.bus = &i2c_bus_type; //这个驱动所属的总线为i2c_bus
driver_register(&driver->driver); //注册i2c driver中的driver,不管,跟我没关系,我关心的知识i2c
bus_for_each_dev(&i2c_bus_type, NULL, driver, __attach_adapter);
__attach_adapter
i2c_detect(adapter, driver); //driver 为注册进来的i2c_driver
address_data = driver->address_data;
if (!driver->detect || !address_data)
return 0;
if (address_data->forces) {
}
if (!(adapter->class & driver->class))// ( s3c24xx_i2c_probe中)i2c->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
goto exit_free;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK)) {
}
//检查i2c_algorithm里的functionality
//在i2c-s3c2410.c已经设置,
for (i = 0; address_data->probe != I2C_CLIENT_END; i += 2) { //ignore
...
}
/* Normal entries are done last, unless shadowed by an ignore entry */ //Normal地址的处理
for (i = 0; address_data->normal_i2c[i] != I2C_CLIENT_END; i += 1) {
//struct i2c_client *temp_client;
//temp_client->adapter = adapter;
//temp_client->addr = address_data->normal_i2c[i];
i2c_detect_address(temp_client, -1, driver); //这里发出start信号,发出设备地址(确认该设备在总线上存在),在linux-2.6.22中为i2c_probe_address
if i2c_smbus_xfer(adapter, addr, 0, 0, 0,I2C_SMBUS_QUICK, NULL) < 0) //如果存在该设备
if (adapter->algo->smbus_xfer) {//我们在算法中如果设置的smbus_xfer
res = adapter->algo->smbus_xfer(adapter, addr, flags,read_write, command,protocol, data);
else
i2c_smbus_xfer_emulated(adapter,addr,flags,read_write, command, protocol, data);
i2c_transfer(adapter, msg, num);
if (adap->algo->master_xfer) { //如果我们的算法中设置了master_xfer函数
.master_xfer = s3c24xx_i2c_xfer //最终传递消息的是mater_xfer函数
ret = s3c24xx_i2c_doxfer(i2c, msgs, num);
i2c->msg = msgs;
i2c->state = STATE_START;
s3c24xx_i2c_message_start(i2c, msgs);
timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);
else
返回错误
driver->detect(temp_client, kind, &info); //调用i2c_driver的detect 函数,我们要实现
if (info.type[0] == '\0') { //这个type数组用来以后制作出client的name ,再用其匹配 i2c_driver中的id_table
出错返回,我们要在detect函数中设置info结构体
}
else
struct i2c_client *client;
client = i2c_new_device(adapter, &info);
client->adapter = adap;
client->addr = info->addr;
client->irq = info->irq;
client->dev.bus = &i2c_bus_type;
strlcpy(client->name, info->type, sizeof(client->name)); //设置client的name 为以后匹配i2c_driver做准备
status = device_register(&client->dev);
device_add(dev);
bus_probe_device(dev);
device_attach(dev);
if (dev->driver) { //如果其驱动已连接
device_bind_driver(dev);
else
<font color="#000000"></font> bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
__device_attach
driver_match_device(drv, dev) //调用bus的match,这里的bus为i2c_bus_type!!
i2c_device_match
if (driver->id_table) //匹配i2c_driver中的id_table了
return i2c_match_id(driver->id_table, client) != NULL;
if (strcmp(client->name, id->name) == 0)//比较clint的名字和id_table中的名字。一定要成功!!
//如果mach成功
driver_probe_device(drv, dev);
really_probe(dev, drv);
drv->probe(dev); //调用i2c_driver的probe函数,这是自己定义的
list_add_tail(&client->detected, &driver->clients); //将新探测建立的client加入i2c_driver的client链表中
}
/* Legacy drivers scan i2c busses directly */
if (driver->attach_adapter)
driver->attach_adapter(adapter);