Linux 设备驱动模型(Device Model)的核心设计哲学:分层与解耦

1. 数据的源头:设备树 (DTS)

硬件工程师在设备树里写好硬件的参数。

在设备树文件中:

&ecspi1 {
    // ... 控制器配置 ...
    dac: dac {
        compatible = "spidev";            // 用于匹配驱动
        reg = <0>;                        // 对应片选 CS0
        spi-max-frequency = <20000000>;   // 对应 20MHz
    };
};

2. 数据的搬运工:SPI Core 层 (drivers/spi/spi.c)

在系统启动(或者动态加载设备树)时,Linux 内核的 SPI 核心层会做以下几件事,这些动作发生在 spidev_probe 被调用之前

  1. 解析 (Parse):SPI Core 读取设备树的二进制文件(DTB)。
  2. 分配 (Allocate):它会调用 spi_alloc_devicedac 这个节点分配一块内存,也就是 struct spi_device
  3. 填充 (Populate):它把 DTS 里的属性,“搬运”到 C 语言的结构体里。
    • DTS reg = <0> ==> C struct spi->chip_select = 0;
    • DTS spi-max-frequency = <20000000> ==> C struct spi->max_speed_hz = 20000000;
    • DTS compatible = "spidev" ==> C struct spi->modalias (用于匹配)
  4. 注册 (Register):将填好的 spi_device 注册到系统总线上。

3. 数据的消费者:Driver 层 (spidev_probe)

当 SPI Core 发现 spi_device (设备) 和 spidev_driver (驱动) 匹配成功后,它会调用 probe,并把那个已经填满了数据的结构体指针传给你。

static int spidev_probe(struct spi_device *spi) 
{
    // 此时,spi 指针指向的内存区域里,
    // spi->max_speed_hz 已经被 Core 层赋值为 20000000 了
    // spi->chip_select 已经被 Core 层赋值为 0 了
    spidev->speed_hz = spi->max_speed_hz; // 驱动把 Core 给的数据,存入自己的私有数据中
}

[图解] 数据流向全景

为了让你看得更清楚,我为你整理了一个一一映射表,你可以直接对应查看:

数据来源 (设备树 DTS) 负责解析的内核文件 数据去向 (spi_device 结构体) 最终在 spidev_probe 中的表现
Node: dac { ... } drivers/spi/spi.c struct spi_device *spi probe 函数的入参 spi
Prop: spi-max-frequency = <20000000> drivers/spi/spi.c spi->max_speed_hz spi->max_speed_hz 值为 20000000
Prop: reg = <0> drivers/spi/spi.c spi->chip_select spi->chip_select 值为 0
Parent: &ecspi1 drivers/spi/spi.c spi->master spi->master->bus_num (比如 1)
Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐