Linux 内核中的 I2C 子系统 提供了对 I2C(Inter-Integrated Circuit)总线的完整支持,包括 I2C 控制器驱动(Adapter)、设备驱动(Client Driver) 和 用户空间访问接口。
1. I2C 子系统架构
Linux I2C 子系统采用分层设计,主要分为以下部分:
| 层级 | 功能 |
|---|---|
| I2C Core | 核心层,提供注册/注销 Adapter 和 Client 的 API |
| I2C Bus | 管理 I2C 设备与驱动的匹配(基于 i2c_device_id 或 of_device_id) |
| I2C Adapter | I2C 控制器驱动(如 i2c-imx、i2c-s3c2410) |
| I2C Client | I2C 设备驱动(如 lm75 温度传感器驱动) |
| 用户空间接口 | 通过 /dev/i2c-* 或 sysfs 访问 I2C 设备 |
2. I2C 核心数据结构
(1) struct i2c_adapter
代表一个 I2C 控制器(如 SoC 的 I2C 接口),关键字段:
struct i2c_adapter {
struct device dev; // 关联的设备
const struct i2c_algorithm *algo; // 通信方法(如 master_xfer)
int nr; // 适配器编号(如 i2c-0)
char name[48]; // 适配器名称(如 "i2c-imx")
struct i2c_bus_recovery_info *bus_recovery_info; // 总线恢复
};
(2) struct i2c_client
代表一个 I2C 设备,关键字段:
struct i2c_client {
unsigned short addr; // 7-bit 设备地址(如 0x48)
char name[I2C_NAME_SIZE]; // 设备名称(如 "lm75")
struct i2c_adapter *adapter; // 所属的 I2C 控制器
struct device dev; // 设备模型
};
(3) struct i2c_driver
I2C 设备驱动,关键方法:
struct i2c_driver {
int (*probe)(struct i2c_client *); // 设备探测
int (*remove)(struct i2c_client *); // 设备移除
const struct of_device_id *of_match_table; // 设备树匹配表
const struct i2c_device_id *id_table; // 设备 ID 表
};
3. I2C 设备驱动开发
(1) 设备树(Device Tree)描述
&i2c1 {
status = "okay";
clock-frequency = <100000>; // 100kHz
lm75: temperature-sensor@48 {
compatible = "national,lm75";
reg = <0x48>; // I2C 地址
};
};
(2) 驱动代码示例
#include <linux/i2c.h>
#include <linux/module.h>
static int lm75_probe(struct i2c_client *client)
{
u8 reg_val[2];
int temp;
// 读取温度(LM75 的温度寄存器是 0x00)
i2c_smbus_read_i2c_block_data(client, 0x00, 2, reg_val);
temp = (reg_val[0] << 8) | reg_val[1];
temp >>= 7; // LM75 温度数据格式
printk("Temperature: %d°C\n", temp);
return 0;
}
static const struct of_device_id lm75_of_match[] = {
{ .compatible = "national,lm75" },
{ }
};
MODULE_DEVICE_TABLE(of, lm75_of_match);
static struct i2c_driver lm75_driver = {
.driver = {
.name = "lm75",
.of_match_table = lm75_of_match,
},
.probe = lm75_probe,
};
module_i2c_driver(lm75_driver);
4. 用户空间访问 I2C
(1) 通过 sysfs 访问
# 查看所有 I2C 适配器 ls /sys/bus/i2c/devices/ # 扫描 I2C-1 总线上的设备 i2cdetect -y 1 # 读取 I2C-1 上地址 0x48 的寄存器 0x00 i2cget -y 1 0x48 0x00
(2) 通过 /dev/i2c-* 使用 ioctl
#include <linux/i2c-dev.h>
#include <fcntl.h>
int fd = open("/dev/i2c-1", O_RDWR);
ioctl(fd, I2C_SLAVE, 0x48); // 设置从机地址
uint8_t reg = 0x00;
uint8_t buf[2];
write(fd, ®, 1); // 发送要读取的寄存器
read(fd, buf, 2); // 读取 2 字节数据
close(fd);
5. I2C 子系统调试
(1) 内核配置
确保启用:
CONFIG_I2C=y CONFIG_I2C_CHARDEV=y # 提供 /dev/i2c-* 接口 CONFIG_I2C_DEBUG_CORE=y # 调试支持
(2) 动态调试
# 启用 I2C 核心调试信息 echo 8 > /proc/sys/kernel/printk dmesg | grep i2c
(3) 逻辑分析仪
-
使用 Saleae Logic 或 PulseView 抓取 I2C 波形,检查 SCL/SDA 信号。
6. 常见问题
(1) 设备未被检测到
-
检查
i2cdetect是否能发现设备。 -
确认设备树(
compatible和reg)是否正确。
(2) 通信失败
-
检查
clock-frequency是否匹配设备要求。 -
测量 SCL/SDA 电压(标准 I2C 是 3.3V/5V)。
(3) 驱动加载但未绑定设备
-
检查
of_match_table或id_table是否匹配。
7. 典型应用场景
| 场景 | 示例驱动 |
|---|---|
| 温度传感器 | lm75、tmp102 |
| RTC 时钟 | ds1307、pcf8563 |
| EEPROM | at24 |
| 触摸屏 | ft5x06 |
| PMIC 电源管理 | max77650 |
总结
-
I2C Core 提供核心 API(注册 Adapter/Client)。
-
I2C Adapter 对应 SoC 的 I2C 控制器。
-
I2C Client 代表具体的 I2C 设备。
-
可通过 设备树 或 静态声明 注册设备。
-
用户空间可通过
i2c-tools或/dev/i2c-*访问设备。
563

被折叠的 条评论
为什么被折叠?



