1. Linux I2C驱动开发概述
I2C(Inter-Integrated Circuit)总线是嵌入式系统中最常用的串行通信接口之一。作为一名Linux驱动开发者,掌握I2C驱动的开发流程是必备技能。本文将深入剖析Linux内核中的I2C子系统架构,并通过完整实例演示如何开发一个专业的I2C设备驱动。
1.1 I2C总线特点
I2C总线具有以下显著特点:
- 仅需两根信号线(SCL时钟线和SDA数据线)
- 支持多主多从架构
- 7位或10位设备地址寻址
- 标准模式(100kHz)、快速模式(400kHz)和高速模式(3.4MHz)
- 半双工通信方式
在实际项目中,I2C常用于连接各种传感器、EEPROM、RTC等低速外设。理解I2C协议的工作原理是开发高质量驱动的基础。
2. Linux I2C子系统架构
2.1 三层架构设计
Linux内核中的I2C子系统采用经典的三层架构设计:
code复制┌─────────────────────────────────┐
│ I2C设备驱动层 │
│ (具体设备驱动如EEPROM、传感器) │
└─────────────────────────────────┘
↓
┌─────────────────────────────────┐
│ I2C核心层 │
│ (设备匹配、传输管理、工具函数) │
└─────────────────────────────────┘
↓
┌─────────────────────────────────┐
│ I2C总线驱动层 │
│ (具体I2C控制器驱动如i2c-rk3x) │
└─────────────────────────────────┘
这种分层设计使得驱动开发更加模块化,设备驱动开发者只需关注业务逻辑,而不需要了解底层硬件的具体实现。
2.2 关键组件解析
2.2.1 I2C适配器(Adapter)
代表一个物理I2C总线控制器,主要功能包括:
- 管理I2C总线的物理特性(时钟频率、时序等)
- 提供底层传输接口
- 维护总线上的设备列表
每个适配器在内核中都有一个唯一的总线编号,可以通过i2c_get_adapter()获取适配器指针。
2.2.2 I2C客户端(Client)
代表连接到I2C总线上的一个具体设备,包含以下关键信息:
- 设备地址(7位或10位)
- 设备名称
- 关联的适配器
- 设备私有数据
在驱动中,我们通过struct i2c_client结构体与设备交互。
2.2.3 I2C驱动(Driver)
管理一类I2C设备的驱动实现,主要职责包括:
- 实现probe/remove等生命周期回调
- 提供设备操作接口
- 管理设备状态
驱动通过struct i2c_driver结构体向内核注册。
3. I2C设备驱动开发实战
3.1 驱动框架搭建
一个完整的I2C设备驱动通常包含以下部分:
c复制#include <linux/module.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/delay.h>
/* 设备ID表 */
static const struct i2c_device_id my_device_id[] = {
{ "my_i2c_device", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, my_device_id);
/* 设备树匹配表 */
static const struct of_device_id my_i2c_of_match[] = {
{ .compatible = "vendor,my-device", },
{ }
};
MODULE_DEVICE_TABLE(of, my_i2c_of_match);
/* 设备私有数据结构 */
stru
