从传统模式到新绑定模型的转变
在Linux内核的早期版本中,I2C设备驱动的编写方式相对简单直接。开发者通常会使用类似以下的代码来声明设备地址:
static unsigned short normal_i2c[] = { 0x67, I2C_CLIENT_END };
I2C_CLIENT_INSMOD;
但随着内核的发展,这种直接指定地址的方式已被更现代化的设备树(DTS)和ACPI绑定模型所取代。这种变化带来了更好的硬件抽象和配置灵活性,但也让不少习惯了旧方式的开发者感到困惑。
新模型下的地址指定方法
在新绑定模型中,设备地址主要通过以下几种方式指定:
1. 设备树(DTS)绑定方式
对于支持设备树的平台,最推荐的方式是通过.dts文件配置:
i2c1 {
compatible = "vendor,i2c-controller";
#address-cells = <1>;
#size-cells = <0>;
mydevice@67 {
compatible = "vendor,mydevice";
reg = <0x67>;
};
};
2. ACPI绑定方式
对于使用ACPI的系统,可以在驱动中这样定义:
static struct i2c_device_id mydevice_id[] = {
{ "MYDEV", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, mydevice_id);
3. 平台数据方式
如果设备不支持自动检测,也可以通过平台数据指定:
static struct i2c_board_info mydevice_info = {
I2C_BOARD_INFO("mydevice", 0x67),
};
static struct i2c_client *client;
client = i2c_new_device(adapter, &mydevice_info);
实际驱动代码示例
下面是一个完整的新模型驱动示例:
#include
#include
#include
static int mydevice_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
/* 驱动初始化代码 */
return 0;
}
static int mydevice_remove(struct i2c_client *client)
{
/* 驱动卸载代码 */
return 0;
}
static const struct of_device_id mydevice_of_match[] = {
{ .compatible = "vendor,mydevice" },
{ }
};
MODULE_DEVICE_TABLE(of, mydevice_of_match);
static const struct i2c_device_id mydevice_id[] = {
{ "mydevice", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, mydevice_id);
static struct i2c_driver mydevice_driver = {
.driver = {
.name = "mydevice",
.of_match_table = of_match_ptr(mydevice_of_match),
},
.probe = mydevice_probe,
.remove = mydevice_remove,
.id_table = mydevice_id,
};
module_i2c_driver(mydevice_driver);
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("MyDevice I2C Driver");
MODULE_LICENSE("GPL");
常见问题解决
Q: 如何确认设备地址是否正确绑定?
A: 可以检查/sys/bus/i2c/devices目录下的设备节点,或使用dmesg查看内核日志。
Q: 设备不支持自动检测怎么办?
A: 这种情况下必须使用平台数据方式或设备树方式明确指定地址,不能依赖自动检测机制。
Q: 新旧驱动模型可以混用吗?
A: 不建议混用,新内核版本可能会逐步淘汰旧API,应该完全迁移到新模型。