IIO子系统
1. IIO 子系统的作用
IIO 填补了 Input 子系统(处理键盘、鼠标)和 HWMON 子系统(处理风扇、温度监控)之间的空白:
- 统一接口:通过 sysfs(简单读取)和 字符设备(连续大数据流读取)提供数据。
- 缓冲管理:支持硬件 FIFO 和内核软件 Buffer(触发式采集)。
- 触发机制:支持外部中断、定时器或软件指令触发转换。
2. 核心数据结构
2.1 struct iio_dev (设备心脏)
每一个 IIO 设备都必须分配并填充这个结构体。
struct iio_dev {
int id; /* 设备 ID */
struct device dev; /* 继承的标准设备 */
struct iio_buffer *buffer; /* 缓冲区指针 */
int modes; /* 支持的模式(直接模式、缓冲模式等) */
int num_channels; /* 通道数量 */
struct iio_chan_spec const *channels; /* 通道定义数组 */
const struct iio_info *info; /* 读写操作函数表 */
const char *name; /* 设备名称,出现在 /sys/bus/iio/devices/iio:deviceX/name */
};
2.2 struct iio_chan_spec (通道描述)
定义 ADC 或传感器的一个通道(比如 ADC 的通道 0,或加速度计的 X 轴)。
struct iio_chan_spec {
enum iio_chan_type type; /* 通道类型:IIO_VOLTAGE, IIO_TEMP, IIO_ACCEL 等 */
int channel; /* 通道索引号 */
unsigned long address; /* 通道对应的寄存器地址(私有使用) */
int scan_index; /* 扫描顺序(用于缓冲采集) */
struct {
char sign; /* 's' 有符号, 'u' 无符号 */
u8 realbits; /* 有效位数(如 12位 ADC) */
u8 storagebits; /* 存储位数(通常为 16 或 32) */
} scan_type;
long info_mask_separate; /* 独立属性掩码(如 RAW) */
long info_mask_shared_by_type; /* 同类共享属性(如 SCALE) */
};
2.3 struct iio_info (回调函数表)
这是驱动程序与内核核心层交互的桥梁。
struct iio_info {
/* 核心函数:处理 sysfs 的读请求 */
int (*read_raw)(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,
int *val, int *val2, long mask);
/* 处理 sysfs 的写请求(如修改采样率) */
int (*write_raw)(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,
int val, int val2, long mask);
/* ... 还有读取事件、配置触发器等回调 ... */
};
3. 常用函数与宏 (API 手册)
3.1 设备生命周期
推荐使用 devm_ 版本,省去繁琐的注销逻辑。
3.1.1 struct iio_dev *devm_iio_device_alloc(struct device *dev, int sizeof_priv)
作用:为 struct iio_dev 分配内存,并可选地在同一个内存块中连续分配一块自定义私有数据区域。由于带 devm_,当驱动卸载时,这块内存会自动释放。
参数说明:
- dev:指向拥有该 IIO 设备的物理设备(通常是 pdev->dev)。
- sizeof_priv:你自定义的驱动私有结构体的大小(字节)。如果不需私有空间,填 0。
返回值:
- 成功:返回指向 iio_dev 结构体的指针。
- 失败:返回 NULL。
3.1.2 static inline void *iio_priv(const struct iio_dev *indio_dev)
作用:获取分配 iio_dev 时一同申请的私有数据区域的指针。
参数说明:indio_dev:指向已分配的 iio_dev 结构体的指针。
返回值:返回私有数据区域的起始地址指针。
核心逻辑:在内核实现中,私有数据紧跟在 iio_dev 结构体之后,该函数本质上是做一个地址偏移:return (void *)(indio_dev + 1);。
3.1.3 int devm_iio_device_register(struct device *dev, struct iio_dev *indio_dev)
作用:将初始化好的 IIO 设备注册到内核 IIO 核心层。注册成功后,用户态即可在 /sys/bus/iio/devices/ 下看到对应的设备节点。由于带 devm_,卸载驱动时无需手动调用 unregister。
参数说明:
- dev:物理设备指针。
- indio_dev:已经填充好(包括 name, info, channels 等成员)的 iio_dev 结构体指针。
返回值:
- 成功:返回 0。
- 失败:返回负数错误码(如 -ENOMEM 或其他注册错误)。
3.2 辅助宏
3.2.1 IIO_CHAN_SOFT_TIMESTAMP(index)
作用:在 IIO 通道数组中自动添加一个软件时间戳通道。当你的驱动支持 Buffer(缓冲)模式采集数据时,每一组传感器样本通常都需要配一个时间戳,以便用户态程序(如 libiio)进行时间对齐分析。
参数说明:index:该通道在扫描序列中的索引号。通常设置为所有数据通道之后的最后一个索引。
3.2.2 IIO_DEGREE_TO_RAD(val)
作用:将角度(Degrees)转换为弧度(Radians)。
参数说明:val:待转换的角度数值(通常是浮点数或定点数)。
4. 极简开发流程 (面试复习点)
4.1 Probe 阶段:
- 使用 devm_iio_device_alloc 申请设备,预留自定义私有数据空间。
- 初始化 iio_dev 成员(name, channels, num_channels, info)。
- 配置硬件(如通过 SPI/I2C 初始化 ADC 芯片)。
- 调用 devm_iio_device_register。
4.2 数据读取 (read_raw):
- 判断 mask == IIO_CHAN_INFO_RAW。
- 操作硬件寄存器获取数据。
- 返回 IIO_VAL_INT。

浙公网安备 33010602011771号