Linux 2.6.32 下i2c 之 内核源码驱动分析
2012-05-30 10:29
357 查看
参考http://www.100ask.net/forum/showtopic-3842.aspx
自己也做了一下分析,对Linux2.6.32内核下I2C驱动的大致框架有了更加深入的了解
自己也做了一下分析,对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);
相关文章推荐
- Linux I2C设备驱动分析 基于2440 2.6.32内核
- Linux I2C驱动源码分析
- 基于ARM9处理器的linux-2.6.32.2操作系统内核移植手记part5.2(LCD驱动源码分析及移植之platform driver)
- s3c2410 RTC驱动框架linux内核源码分析
- s3c2410 RTC驱动框架linux内核源码分析
- Linux I2C驱动源码分析(一)
- Linux I2C驱动源码分析(一)
- Linux I2C驱动源码分析(二)
- Linux内核---32.I2C设备驱动分析
- Linux I2C驱动源码分析(一)
- Linux I2C驱动源码分析(一)
- linux内核杂项设备驱动源码分析
- Linux I2C驱动源码分析(二)
- Linux I2C驱动源码分析(二)
- Linux I2C驱动源码分析(二)
- Linux I2C驱动源码分析
- 关于linux2.6.32-2内核源码分析
- OMAP3630 Linux I2C总线驱动分析
- linux-2.6.22.6 i2c总线驱动分析
- Linux I2C驱动分析与实现(一)