从零构建:手把手教你编写Linux I2C设备驱动
在嵌入式Linux开发中,I2C设备驱动是最常见且最具挑战性的任务之一。无论是连接传感器、EEPROM存储器还是其他外设,掌握I2C驱动的编写技巧都是嵌入式工程师的必备技能。本文将从实际项目经验出发,带你一步步完成一个完整的I2C设备驱动开发过程,避开常见的陷阱,提供可直接落地的代码示例。
1. 环境准备与基础概念
在开始编写驱动之前,我们需要先理解Linux I2C子系统的基本架构。I2C子系统采用典型的分层设计:最底层是I2C控制器驱动(通常由芯片厂商提供),中间是I2C核心层,最上层才是我们需要编写的设备驱动。
关键结构体介绍:
i2c_client:代表一个I2C从设备,包含设备地址、适配器指针等信息i2c_driver:驱动的主要结构,包含probe、remove等回调函数i2c_adapter:代表I2C控制器,提供底层的传输能力i2c_msg:描述一次I2C传输的消息结构
提示:在实际开发中,我们通常不需要直接操作I2C控制器,而是通过I2C核心层提供的API与设备通信。
先确认你的开发环境已准备好必要的工具和内核头文件:
# 安装编译工具和内核头文件
sudo apt-get install build-essential linux-headers-$(uname -r)
# 检查系统已加载的I2C适配器
i2cdetect -l
2. 设备树配置与硬件连接
现代Linux驱动开发强烈推荐使用设备树来描述硬件信息。对于I2C设备,我们需要在设备树中正确声明设备节点。
典型I2C设备节点配置:
&i2c1 {
status = "okay";
clock-frequency = <100000>;
/* 假设我们连接了一个温度传感器 */
temp_sensor: lm75@48 {
compatible = "national,lm75";
reg = <0x48>;
/* 可选的中断引脚配置 */
interrupt-parent = <&gpio1>;
interrupts = <14 IRQ_TYPE_EDGE_FALLING>;
};
/* EEPROM设备示例 */
eeprom: at24c64@50 {
compatible = "atmel,at24c64";
reg = <0x50>;
pagesize = <32>;
};
};
设备树编译后,内核会自动为每个设备创建对应的i2c_client。在驱动中,我们可以通过of_match_table来匹配这些设备。
常见问题排查:
如果设备无法检测,首先使用i2c-tools检查硬件连接:
# 扫描I2C总线上的设备
i2cdetect -y 1
# 读取设备寄存器
i2cget -y 1 0x48 0x00
3. I2C驱动框架搭建
让我们从最简单的驱动框架开始。一个完整的I2C驱动需要定义i2c_driver结构,并实现必要的回调函数。
基础驱动框架代码:
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
/* 设备私有数据结构 */
struct i2c_dev_data {
struct i2c_client *client;
struct cdev cdev;
struct device *dev;
/* 其他设备特定数据 */
};
/* Probe函数 - 设备被

6528

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



