Chinaunix首页 | 论坛 | 博客
  • 博客访问: 21917
  • 博文数量: 6
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 30
  • 用 户 组: 普通用户
  • 注册时间: 2011-04-28 16:21
文章分类
文章存档

2013年(5)

2012年(1)

我的朋友

分类: Android平台

2013-03-08 17:59:54

原文地址:Linux kernel I2C设备总结 作者:any_wind

在系统开机时,首先装载的是I2C总线驱动。一个总线驱动用于支持一条特定的I2C总线的读写。这部分主要定义i2c_adapter和i2c_algorithm数据结构,前者用来描述具体的 i2c 总线适配器,后者则描述i2c 总线的通信方法.
设备驱动则是与挂在I2C总线上的具体的设备通讯的驱动。通过I2C总线驱动提供的函数,设备驱动可以忽略不同总线控制器的差异,不考虑其实现细节地与硬件设备通讯。


Client很有可能是一个cdev在probe中实现


init->i2c_add_driver->i2c_register_driver
在i2c_register_driver中
driver->driver.owner = owner;
driver->driver.bus = &i2c_bus_type;
res = driver_register(&driver->driver);
i2c_for_each_dev(driver, __process_new_driver);//对每一个adapter执行__process_new_driver函数,以前一直以为实在这里将driver和algorithm联系起来
后来发现是在driver_register中,最后调用到i2c-core.c中的i2c_device_probe中client回传联系起来的,这里回传的client即是adapter


并在这里创建相应的kobject,并触发相应的kevent




仔细分析一下driver_register函数


在注册的时候注册了一个i2c_driver的结构体


例如adv7170.c
static struct i2c_driver adv7170_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "adv7170",
},
.probe = adv7170_probe,
.remove = adv7170_remove,
.id_table = adv7170_id,
};


static __init int init_adv7170(void)
{
return i2c_add_driver(&adv7170_driver);
}
在driver_register中首先调用other = driver_find(drv->name, drv->bus);
看dirver是否已经在bus中,没有则调用bus_add_driver
中调用了error = driver_attach(drv);因为i2c_bus中的driver_autoprobe不为0


int driver_attach(struct device_driver *drv)
{
return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}
中对每一个bus上的device去匹配driver,并调用__driver_attach函数
这里可以看出adataper在bus中充当的是device角色,master在bus中充当的是driver角色
等一下看看adapter的注册就可以得到证实
if (!dev->driver)
driver_probe_device(drv, dev);//此时的adapter即device的driver还为空
__driver_attach->driver_probe_device->really_probe->ret = dev->bus->probe(dev);




这里调用到了i2c-core里边bus的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))
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));//这里回调给driver并把adapter作为client回传
if (status) {
client->driver = NULL;
i2c_set_clientdata(client, NULL);
}
return status;
}
其中i2c_register_adapter中调用了
int device_register(struct device *dev)
{
device_initialize(dev);
return device_add(dev);
}
创建了sys文件并把device放到bus private的device链表的结尾部分


一般是在arch目录设置i2c的设备信息,包括相应的地址和中断
是一个平台设备
然后在i2c/buss/中添加相应的adapter,中是相应的驱动
中用软件设置了相应的传输操作,初始化操作
然后driver中则通过core对apdataer的传输操作进行调用
其中adapter中重要的实现了algorithm结构体,定义了
static const struct i2c_algorithm omap_i2c_algo = {
.master_xfer = omap_i2c_xfer,
.functionality = omap_i2c_func,
};


I2C设备至此清晰了~~

阅读(1337) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~