您的位置:首页 > 运维架构 > Linux

Linux 2.6.32 下i2c 之 内核源码驱动分析

2012-05-30 10:29 357 查看
参考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);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: