一篇看懂Linux下的IIC驱动
IIC驱动概述
IIC(Inter-Integrated Circuit)是一种串行通信协议,广泛应用于嵌入式系统中连接低速外设。Linux内核提供了完善的IIC子系统,包括核心层、适配器驱动和设备驱动。
内核IIC子系统架构
Linux IIC子系统分为三层:
- IIC核心层:提供注册/注销适配器和设备的API,实现协议的核心逻辑。
- IIC适配器驱动:针对具体SoC或IIC控制器硬件实现底层操作。
- IIC设备驱动:实现具体外设的功能逻辑。
适配器驱动开发
适配器驱动需要实现i2c_algorithm和i2c_adapter:
static const struct i2c_algorithm foo_algorithm = { .master_xfer = foo_i2c_xfer, .functionality = foo_i2c_func, }; static int foo_i2c_probe(struct platform_device *pdev) { struct foo_adapter *adap; adap = devm_kzalloc(&pdev->dev, sizeof(*adap), GFP_KERNEL); adap->adapter.owner = THIS_MODULE; adap->adapter.algo = &foo_algorithm; i2c_add_adapter(&adap->adapter); }设备驱动开发
设备驱动通过i2c_driver结构体注册:
static const struct i2c_device_id foo_id[] = { { "foo_device", 0 }, { } }; static struct i2c_driver foo_driver = { .driver = { .name = "foo", }, .probe = foo_probe, .remove = foo_remove, .id_table = foo_id, }; module_i2c_driver(foo_driver);用户空间访问
通过sysfs接口或i2c-dev字符设备访问:
# 扫描IIC总线 i2cdetect -y 1 # 读写寄存器 i2cset -y 1 0x50 0x00 0x12 i2cget -y 1 0x50 0x00设备树配置
在设备树中声明IIC设备和适配器:
i2c1: i2c@40005400 { compatible = "st,stm32-i2c"; reg = <0x40005400 0x400>; interrupts = <31>; clocks = <&rcc 0 150>; #address-cells = <1>; #size-cells = <0>; eeprom@50 { compatible = "atmel,24c256"; reg = <0x50>; }; };调试技巧
使用内核动态调试功能:
echo "file i2c-* +p" > /sys/kernel/debug/dynamic_debug/control dmesg -w常见问题解决
- NACK错误:检查设备地址、上拉电阻和电源
- 时钟拉伸:确认设备支持标准模式(100kHz)或快速模式(400kHz)
- 时序问题:使用逻辑分析仪抓取波形验证时序
性能优化
- 使用DMA传输减少CPU占用
- 合理设置超时时间避免总线挂起
- 批量读写减少启动/停止条件开销
