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。
posted @ 2026-04-16 11:49  r5ett  阅读(57)  评论(0)    收藏  举报