I2C 驱动用 i2c_driver 结构体注册,id_table 或 of_match_table 匹配设备;probe 函数在设备匹配时调用,初始化硬件、创建 cdev 或 sysfs;用户态通过 /dev/i2c-X(i2c-dev)或 sysfs 访问;I2C 核心提供 i2c_transfer/i2c_smbus_* 收发函数,驱动不要直接操作寄存器。
本文概述
I2C 驱动是 Linux 字符设备常见类型,面试常考:i2c_driver、probe、设备树匹配、用户态访问。回答要给驱动框架。
核心要点
i2c_driver 注册:driver.name、probe、remove、id_table(传统)或 of_match_table(设备树)
probe 函数:i2c_check_functionality、初始化硬件、创建 cdev/sysfs、保存 client
收发:i2c_transfer(通用)或 i2c_smbus_read_byte_data/i2c_smbus_write_byte_data(SMBus)
设备树匹配:of_match_table 里 compatible 字符串和 dts 里一致
用户态访问:/dev/i2c-X(i2c-dev,ioctl 读写)或 /sys/bus/i2c/devices/ 下的 sysfs

面试官考察点
Linux 驱动基础题。面试官看你是否写过 I2C 驱动。重点听:i2c_driver、probe、收发。
回答思路
给 i2c_driver 结构、probe 流程、收发函数、用户态访问。
参考回答
i2c_driver 结构。
static const struct of_device_id my_i2c_of_match[] = {
{ .compatible = "vendor,mychip" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, my_i2c_of_match);
static struct i2c_driver my_i2c_driver = {
.driver = {
.name = "my_i2c_chip",
.of_match_table = my_i2c_of_match,
},
.probe = my_i2c_probe,
.remove = my_i2c_remove,
.id_table = my_i2c_id, // 可选,传统匹配
};
module_i2c_driver(my_i2c_driver);
probe 函数流程。
i2c_check_functionality(client, I2C_FUNC_I2C) 检查适配器能力;
读取设备 ID 寄存器,确认硬件存在(可选但推荐);
分配私有数据结构(devm_kzalloc),保存 client;
初始化硬件(复位、配置寄存器);
注册字符设备 cdev 或 sysfs 属性,让用户态访问;
i2c_set_clientdata(client, data) 保存私有数据。
static int my_i2c_probe(struct i2c_client *client){
struct my_data *data;
data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
data->client = client;
i2c_set_clientdata(client, data);
// 初始化硬件、注册 cdev/sysfs
return 0;
}
I2C 收发函数。
| 函数 | 用途 |
|---|---|
| i2c_transfer(client, msgs, num) | 通用 I2C 收发,支持多消息组合(写寄存器+读) |
| i2c_smbus_read_byte_data(client, reg) | 读 1 字节寄存器 |
| i2c_smbus_write_byte_data(client, reg, val) | 写 1 字节寄存器 |
| i2c_smbus_read_word_data | 读 2 字节 |
| i2c_smbus_read_i2c_block_data | 读块数据(最多 32 字节) |
// 读寄存器 reg 的值
u8 val = i2c_smbus_read_byte_data(client, reg);
// 写寄存器
i2c_smbus_write_byte_data(client, reg, val);
// 通用 i2c_transfer(写 reg 然后读 N 字节)
struct i2c_msg msgs[2];
u8 reg_addr = 0x10;
u8 buf[4];
msgs[0].addr = client->addr; msgs[0].flags = 0;
msgs[0].buf = ®_addr; msgs[0].len = 1;
msgs[1].addr = client->addr; msgs[1].flags = I2C_M_RD;
msgs[1].buf = buf; msgs[1].len = 4;
i2c_transfer(client->adapter, msgs, 2);
用户态访问。
/dev/i2c-X:i2c-dev 驱动提供,open + ioctl(I2C_RDWR/I2C_SMBUS) 读写,不需要写内核驱动;
sysfs:驱动在 /sys/bus/i2c/devices/X-YYYY/ 下创建属性文件,cat/echo 读写;
字符设备 /dev/mychip:驱动注册 cdev,用户态 read/write/ioctl;
i2c-tools:i2cdetect(扫描)、i2cget(读)、i2cset(写)、i2cdump(dump)。
注意。
I2C 地址 7 位(0x08~0x77),驱动里写 7 位地址(不包含读写位);
probe 失败要回滚已分配资源(devm_ 自动管理);
remove 里释放资源、注销 cdev/sysfs;
多实例支持:同一个驱动可以匹配多个同型号设备(不同地址),用 client 区分。

扫码关注




























