Linux I2C 子系统

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 AdapterI2C 控制器驱动(如 i2c-imxi2c-s3c2410
I2C ClientI2C 设备驱动(如 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, &reg, 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. 典型应用场景

场景示例驱动
温度传感器lm75tmp102
RTC 时钟ds1307pcf8563
EEPROMat24
触摸屏ft5x06
PMIC 电源管理max77650

总结

  • I2C Core 提供核心 API(注册 Adapter/Client)。

  • I2C Adapter 对应 SoC 的 I2C 控制器。

  • I2C Client 代表具体的 I2C 设备。

  • 可通过 设备树 或 静态声明 注册设备。

  • 用户空间可通过 i2c-tools 或 /dev/i2c-* 访问设备。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值