1. Platform驱动概述

在Linux内核驱动模型中,Platform驱动(Platform Driver)是一种不依赖具体硬件总线(如PCI、USB、I2C、SPI)的虚拟总线驱动框架。它通过内核提供的“Platform总线”将设备与驱动进行匹配,是嵌入式Linux系统中最常用的驱动类型之一。

1.1 什么是Platform驱动

Platform驱动是Linux内核中一种基于虚拟总线的驱动模型。其核心思想是:将系统中无法挂载到物理总线上的设备(如片上外设、内存映射设备、中断控制器等)抽象为“Platform设备”,并通过统一的Platform总线完成设备与驱动的绑定。

关键特征: Platform驱动不依赖硬件枚举机制(如PCI的VID/PID),而是通过名称匹配或设备树兼容字符串完成驱动与设备的绑定。
对比项 Platform驱动 PCI/USB驱动
总线类型 虚拟Platform总线 物理硬件总线
设备发现方式 设备树/静态注册 硬件枚举(VID/PID)
典型应用场景 SoC内部外设、内存映射设备 扩展卡、外接设备
资源描述 设备树节点或platform_data PCI配置空间/USB描述符
Platform驱动在Linux内核驱动模型中的位置 用户空间 (User Space) 系统调用接口 (VFS / 字符设备 / 块设备) 内核空间 (Kernel Space) Platform驱动 (probe/remove/PM) Platform总线 (匹配/枚举/资源传递) Platform设备 (设备树节点) 设备树 (Device Tree) 硬件 (SoC外设 / 内存映射) 说明:Platform驱动通过Platform总线与设备树节点描述的Platform设备进行匹配,匹配成功后调用probe函数完成驱动初始化。 设备树提供硬件资源描述(寄存器地址、中断号、DMA通道等),Platform驱动通过API获取这些资源。

1.2 为什么需要Platform驱动

嵌入式系统中存在大量非总线可枚举的硬件设备,例如:

  • SoC内部外设: GPIO控制器、定时器、看门狗、RTC、DMA控制器等
  • 内存映射设备: 直接映射到CPU地址空间的FPGA逻辑、显示控制器等
  • 中断控制器: GIC(通用中断控制器)、级联中断控制器等
  • 时钟与电源管理单元: 时钟发生器、PLL、电源域控制器等

这些设备不具备PCI/USB那样的硬件枚举能力,无法通过VID/PID自动发现。Platform驱动提供了以下核心价值:

需求 Platform驱动的解决方案
统一驱动模型 将非总线设备纳入Linux设备驱动模型(LDM),复用driver/core框架
资源解耦 通过设备树或platform_data将硬件资源与驱动代码分离,提高可移植性
电源管理 提供标准的suspend/resume回调,支持系统级电源管理
热插拔模拟 支持设备动态注册/注销,便于模块化开发和调试
多实例支持 同一驱动可绑定多个同类型设备实例,通过设备ID区分
实践建议: 在嵌入式Linux开发中,90%以上的设备驱动都可以基于Platform驱动框架实现。即使设备挂载在I2C/SPI总线上,其控制器本身通常也是Platform设备。

1.3 Platform驱动与设备树的关联

设备树(Device Tree)是Platform驱动获取硬件资源描述的核心数据源。在引入设备树之前,Platform驱动依赖C语言结构体(platform_data)传递硬件信息,这种方式存在以下问题:

  • 硬编码: 硬件资源(地址、中断号)写在C代码中,修改需重新编译内核
  • 单板耦合: 不同硬件平台需要维护不同的板级文件(board-*.c)
  • 维护困难: 内核版本升级时,板级文件需要同步修改

设备树解决了上述问题,其与Platform驱动的协作流程如下:

  1. 设备树描述硬件: 在.dts文件中定义设备节点,包含reg(地址)、interrupts(中断)、clocks(时钟)等属性
  2. 内核解析设备树: 启动时,内核将设备树二进制(DTB)解析为device_node结构体链表
  3. Platform设备创建: 内核为每个匹配的device_node创建platform_device实例
  4. 驱动匹配与Probe: Platform驱动通过of_match_table与设备树节点的compatible属性匹配,匹配成功后调用probe函数
  5. 资源获取: 在probe函数中,驱动通过platform_get_resource、of_property_read_*等API获取设备树中的资源
Platform驱动与设备树的协作流程 ① 设备树源文件 (.dts / .dtsi) ② DTC编译 (.dts → .dtb) ③ Bootloader加载 (DTB传递给内核) ④ 内核解析DTB (device_node链表) ⑤ 创建Platform设备 (platform_device) ⑥ 驱动匹配 (of_match_table) ⑦ Probe函数调用 (获取资源/初始化硬件) ⑧ 资源获取 (reg / interrupts / clocks) 核心关联:设备树节点中的compatible属性与驱动中的of_match_table 进行匹配,匹配成功后驱动通过设备树API获取硬件资源。
常见误区: Platform驱动并不必须依赖设备树。在没有设备树的旧内核中,Platform驱动可以通过platform_data结构体传递资源。但在现代嵌入式Linux(ARM64、RISC-V等架构)中,设备树已成为标准配置,建议所有新开发都基于设备树实现。

1.4 设备树中的Platform设备节点示例

以下是一个典型的设备树节点定义,描述了一个UART控制器:

/* 设备树节点:描述UART控制器硬件资源 */
uart0: serial@10000000 {
    compatible = "vendor,uart-ip-v1", "simple-bus";
    reg = <0x10000000 0x1000>;          /* 寄存器基地址 + 范围 */
    interrupts = <0 33 4>;              /* 中断号:GIC SPI 33, 上升沿触发 */
    clocks = <&clk_uart0>;              /* 时钟句柄 */
    clock-names = "uart_clk";            /* 时钟名称 */
    pinctrl-names = "default";           /* 引脚复用状态 */
    pinctrl-0 = <&uart0_pins>;
    status = "okay";                     /* 设备使能 */
};

对应的Platform驱动probe函数中,资源获取方式如下:

static int uart_probe(struct platform_device *pdev)
{
    struct resource *res;
    void __iomem *base;
    int irq;

    /* 1. 获取寄存器地址资源 */
    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    if (!res)
        return -ENXIO;
    base = devm_ioremap_resource(&pdev->dev, res);
    if (IS_ERR(base))
        return PTR_ERR(base);

    /* 2. 获取中断号 */
    irq = platform_get_irq(pdev, 0);
    if (irq < 0)
        return irq;

    /* 3. 获取时钟资源(设备树属性) */
    clk = devm_clk_get(&pdev->dev, "uart_clk");
    if (IS_ERR(clk))
        return PTR_ERR(clk);

    /* 4. 注册字符设备或tty驱动 */
    // ... 初始化逻辑 ...

    return 0;
}

/* 匹配表:与设备树compatible属性对应 */
static const struct of_device_id uart_of_match[] = {
    { .compatible = "vendor,uart-ip-v1", },
    { /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, uart_of_match);

static struct platform_driver uart_driver = {
    .probe  = uart_probe,
    .remove = uart_remove,
    .driver = {
        .name = "vendor-uart",
        .of_match_table = uart_of_match,
    },
};
module_platform_driver(uart_driver);
核心要点: 设备树中的compatible属性与驱动中的of_match_table是Platform驱动与设备树之间的匹配桥梁。驱动通过platform_get_resource、devm_clk_get、device_property_read_*等API从设备树节点中获取硬件资源,实现驱动代码与硬件描述的完全解耦。

1.5 本章小结

知识点 核心内容
Platform驱动定义 基于虚拟Platform总线的驱动模型,用于非总线可枚举设备
存在意义 统一驱动模型、资源解耦、电源管理、多实例支持
与设备树关联 设备树提供硬件资源描述,驱动通过of_match_table匹配并获取资源
核心API platform_get_resource、devm_ioremap_resource、platform_get_irq、devm_clk_get