Lazy loaded image
🥳嵌入式Linux开发
🔬Linux 驱动专题 - IIO 子系统(Industrial I/O)
Words 3537Read Time 9 min
2026-3-3
2026-3-10
type
Post
date
Mar 3, 2026
slug
linux_drivers_iio_subsystem
category
🥳嵌入式Linux开发
icon
password
Linux内核的 Industrial I/O(IIO)子系统 是专门为传感器类设备设计的统一框架。它填补了 hwmon(低采样率系统监控)与 input(人机交互输入设备)之间的空白,为 ADC、DAC、加速度计、陀螺仪、温湿度传感器、光传感器、气压计等提供标准化的驱动接口。
IIO子系统自 Linux 2.6.32 进入 staging,后在 Linux 3.x 正式合入主线,至 Linux 5.x 已经非常成熟,是嵌入式Linux中传感器驱动开发的 事实标准

为什么需要IIO子系统

在IIO出现之前,传感器驱动分散在多个子系统中:
  • hwmon:面向低采样率的系统监控传感器(风扇转速、CPU温度),不适合高速ADC
  • input:面向人机交互设备(键盘、鼠标、触摸屏),Android早期滥用它来处理传感器
  • 自定义字符设备:各驱动各自为政,接口不统一
IIO的设计目标:
  • 统一的用户空间接口:所有传感器通过 sysfs 和字符设备提供一致的访问方式
  • 灵活的采样机制:支持单次读取(direct mode)和连续采样(triggered buffer)
  • 可组合的触发器模型:设备A的触发器可以驱动设备B采样
  • 标准的数据格式描述:通道类型、缩放因子、数据位宽等均有规范

架构总览

IIO子系统由四个核心概念组成:
  1. IIO Device:对应一个硬件传感器,产生采样数据
  1. IIO Trigger:触发采样的信号源(硬件中断、定时器、软件触发)
  1. IIO Buffer:存储连续采样数据的缓冲区
  1. IIO Event:阈值检测器,当数据超出设定范围时产生事件

核心数据结构

关键结构体说明

  • struct iio_dev:IIO设备的核心结构,由 devm_iio_device_alloc() 分配。驱动私有数据通过 iio_priv() 获取
  • struct iio_info:操作函数集,最重要的是 read_raw() 回调
  • struct iio_chan_spec:通道描述符,定义传感器能测量的物理量类型(IIO_TEMPIIO_HUMIDITYRELATIVEIIO_VOLTAGE 等)
  • struct iio_trigger:触发器抽象,可跨设备共享
  • struct iio_buffer:连续采样的数据缓冲区,通常使用 kfifo 实现

设备注册流程

数据读取流程

单次读取(Direct Mode)

用户通过 sysfs 读取单个通道值时,IIO核心调用驱动的 read_raw() 回调:

缩放因子(Scaling)

read_raw() 的返回值类型决定了数据的表示方式:
返回值类型
含义
最终值计算
IIO_VAL_INT
整数
value = val
IIO_VAL_INT_PLUS_MICRO
整数+微小数
value = val + val2 × 10⁻⁶
IIO_VAL_FRACTIONAL
分数
value = val / val2
IIO_VAL_FRACTIONAL_LOG2
对数分数
value = val / 2^val2

源码要点分析

关键文件

文件路径
功能说明
drivers/iio/industrialio-core.c
IIO核心,设备注册/注销、sysfs接口创建
drivers/iio/industrialio-buffer.c
Buffer框架,连续采样数据管理
drivers/iio/industrialio-trigger.c
Trigger框架,触发器注册与分发
drivers/iio/industrialio-event.c
Event框架,阈值事件处理
drivers/iio/buffer/kfifo_buf.c
kfifo缓冲区实现
include/linux/iio/iio.h
核心头文件,iio_dev / iio_info / iio_chan_spec 定义
include/linux/iio/trigger.h
触发器相关结构体和API
include/linux/iio/buffer.h
缓冲区相关结构体和API
drivers/iio/humidity/dht11.c
DHT11温湿度传感器驱动(本文分析对象)

iio_chan_spec 通道描述实例

以DHT11驱动为例,它定义了两个通道——温度和相对湿度:
  • IIO_CHAN_INFO_PROCESSED 表示驱动返回的是 已处理 的值(单位为毫摄氏度 / 千分之一%RH),而非原始ADC码值
  • 每个通道在 sysfs 中分别生成:in_temp_inputin_humidityrelative_input

DHT11 驱动实例分析

源码位置:drivers/iio/humidity/dht11.c
作者:Harald Geyer
许可证:GPL v2
DHT11 是一款常见的低成本温湿度传感器,使用 单总线协议(类似1-Wire,但非标准)通过一根GPIO数据线传输数据。它是学习IIO驱动的理想入门实例,因为它不涉及I2C/SPI总线复杂性,专注于IIO框架本身。

硬件协议

驱动私有数据结构

设计要点
  • 使用 completion 机制在中断上下文通知进程上下文数据就绪
  • timestamp 实现 2秒数据缓存,避免过于频繁地访问传感器(DHT11采样间隔需≥2秒)
  • edges[] 数组记录每个边沿的精确时间戳,用于后续解码

probe 函数分析

关键流程devm_iio_device_alloc() → 硬件初始化 → 填充 iio_devdevm_iio_device_register()

read_raw 核心读取逻辑

这是整个驱动最关键的函数,实现了完整的 触发采样 → 中断收集边沿 → 解码数据 流程:

中断处理函数

IRQ handler 非常简洁——仅记录边沿时间戳和GPIO电平:

数据解码

platform_driver 注册

设备树节点示例:

DHT11 驱动完整数据流


用户空间使用

单次读取

Triggered Buffer 采样(需支持的设备)


设计理念

Linux IIO子系统的设计体现了以下核心理念:
  1. 统一抽象:将千差万别的传感器设备统一到 iio_dev + iio_chan_spec 模型下,用户空间无需关心底层硬件差异
  1. 关注点分离:Device、Trigger、Buffer、Event 四者独立注册、可自由组合。设备A的触发器可以驱动设备B采样,体现了 Linux 内核一贯的"机制与策略分离"思想
  1. sysfs 自描述:通道类型、数据格式(scan_type)、缩放因子均通过 sysfs 暴露,用户空间可自动解析而无需硬编码
  1. devm 资源管理devm_iio_device_alloc() / devm_iio_device_register() 利用设备资源管理框架,避免手动释放资源的遗漏
  1. 最小驱动原则:DHT11驱动仅约 340 行代码即完成了完整功能——IIO框架承担了 sysfs 创建、字符设备管理、数据格式化等所有通用工作

回顾与常见陷阱

关键要点

  • IIO 填补了 hwmon 和 input 之间的传感器驱动空白
  • 四大核心概念:Device + Trigger + Buffer + Event
  • read_raw() 是最核心的回调,返回值类型决定数据的缩放方式
  • 通道的 info_mask_separateinfo_mask_shared_by_type 决定 sysfs 文件的共享方式
  • INDIO_DIRECT_MODE 用于按需单次采样,Triggered Buffer 用于连续高速采样

常见陷阱

  • 忘记互斥保护:IIO sysfs 接口不阻止并发读取,驱动必须自行加锁
  • 时钟分辨率问题:DHT11 依赖微秒级时间戳解码,系统时钟分辨率 >34μs 时无法正常工作
  • IIO_CHAN_INFO_RAW vs IIO_CHAN_INFO_PROCESSED:RAW 返回原始值(需配合 SCALE),PROCESSED 返回最终值。混淆会导致数据偏差
  • Trigger 与 Direct Mode 互斥:大多数设备不能同时支持两种模式,需用 iio_device_claim_direct_mode() 保护
  • devm 注册顺序devm_iio_device_register() 应在所有初始化完成后最后调用,因为注册后用户空间立即可访问
上一篇
Linux 驱动专题 - ASoC 驱动子系统
下一篇
Uboot 的移植

Comments
Loading...