一. I2C自动检测设备的方式简介
I2C可以通过设备树的方式添加设备,添加后,设备的信息可以查询到,这是一种静态的方式添加设备,也就是不管I2C总线下有没有挂接这个设备。而自动探测的方式是驱动首先给出一个地址列表和探测函数,并且驱动在注册的时候,会逐一通过探测函数检查地址列表中设备是否挂接在I2C总线下。
二. 驱动代码实现
1. 初始化i2c_driver结构体
static struct i2c_driver i2c_drv = {
.class = I2C_CLASS_HWMON,
.probe = i2c_drv_probe,
.remove = i2c_drv_remove,
.id_table = i2c_dev_id,
.driver = {
.name = "oled",
.owner = THIS_MODULE,
},
.detect = i2c_drv_detect,
.address_list = addr_list,
};
class :指定该设备是在哪一类的适配器下,适配器初始化时,也会初始化class,驱动在探测设备时,会将适配器的class和i2c_driver结构体的class比较。
probe :当I2C设备和I2C驱动匹配时,调用该函数。
remove :当I2C设备移除时,调用该函数。
id_table :该驱动支持的I2C设备列表
detect :探测设备是否真实存在的函数。
address_list :探测函数探测的地址列表
2.I2C驱动添加和移除
I2C驱动添加:
static int i2c_driver_init(void)
{
i2c_add_driver(&i2c_drv);
return 0;
}
I2C驱动移除:
void i2c_driver_exit(void)
{
i2c_del_driver(&i2c_drv);
return;
}
3. 驱动支持的I2C设备列表
static const struct i2c_device_id i2c_dev_id[] = {
{ "oled0.98", 0x3c },
{}
};
4. 探测函数探测的地址列表
unsigned short addr_list[] = {0x50, 0x60, 0x3c, I2C_CLIENT_END};
探测函数将会逐一检查0x50,0x60,0x3c地址,直到遇到I2C_CLIENT_END停止。
5. 探测函数
int i2c_drv_detect(struct i2c_client *client, struct i2c_board_info *info)
{
printk("client addr = 0x%04x\n", client->addr);
if (0x3c == client->addr)
{
// 假设oled0.98设备已经存在
strncpy(info->type, "oled0.98", I2C_NAME_SIZE);
return 0;
}
return -ENODEV;
}
该探测函数没有实现探测的功能,只是假设oled0.98设备已经存在,直接将"oled0.98"赋值到i2c_board_info的type成员,表示I2C总线支持了该设备。详细的实现的参考案例可以看linux-3.18.45/drivers/hwmon/lm90.c的detect函数。
6. 驱动的probe函数
static int i2c_drv_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
printk("i2c client %s, id %ld probed\n", client->name, id->driver_data);
at24c02_client = client;
major = register_chrdev(0, "oled0.98", &i2c_fops);
if (major > 0)
{
class = class_create(THIS_MODULE, "oled0.98");
if (class)
{
device_create(class, NULL, MKDEV(major, 0), NULL, "oled0.98");
}
}
return 0;
}
在probe函数中,注册oled0.98字符设备和class,会在/dev下生成oled0.98设备,用于应用层访问。
三. 总结
I2C驱动可以探测函数检测(通过看读取设备的信息是否成功)某一设备是否挂接在I2C总线下,如果存在,则将设备添加到i2c_board_info结构中。这种方式的优点是动态添加设备,不需要修改驱动,只需要将address list的地址的检测函数实现好,以及probe的后的功能实现好即可,非常的方便。