下面我给你一篇内核源码级 + 驱动实战 + 面试友好的完整讲解
👉 Linux Platform 平台设备驱动详解
这是嵌入式 Linux / 驱动工程师必会核心内容


一、什么是 Platform 设备驱动?(一句话先记)

Platform 是 Linux 内核中用于描述“非热插拔、SoC 内部外设”的设备模型

📌 典型对象:

  • GPIO
  • I2C 控制器
  • SPI 控制器
  • UART
  • 定时器
  • 看门狗

👉 不是 USB / PCI 这类可枚举总线


二、为什么需要 Platform 总线?

传统问题(老写法)

// 在驱动中直接写死寄存器地址
#define GPIO_BASE 0x01C20800

❌ 缺点:

  • 不可移植
  • 地址硬编码
  • 不支持设备树
  • 驱动与硬件强耦合

Platform 的解决方案

硬件信息  →  设备(device)
驱动逻辑  →  驱动(driver)
Platform 总线负责匹配

📌 设备和驱动解耦


三、Platform 架构全景图

                +------------------+
                |   Platform Bus   |
                +------------------+
                  ↑             ↑
        platform_device   platform_driver


四、Platform 三大核心结构体(必考)


1️⃣ platform_device(描述硬件)

struct platform_device {
    const char          *name;
    int                  id;
    struct device        dev;
    u32                  num_resources;
    struct resource     *resource;
};

📌 重点成员:

  • name:匹配驱动
  • resource:硬件资源(寄存器 / IRQ)

2️⃣ resource(硬件资源)

struct resource {
    resource_size_t start;
    resource_size_t end;
    unsigned long flags;
};

常见 flags:

IORESOURCE_MEM   // 寄存器
IORESOURCE_IRQ   // 中断


3️⃣ platform_driver(驱动)

struct platform_driver {
    int (*probe)(struct platform_device *);
    int (*remove)(struct platform_device *);
    struct device_driver driver;
};

📌 probe = 驱动入口


五、Platform 匹配机制(面试必问)

1️⃣ 非设备树(旧)

platform_device.name == platform_driver.driver.name


2️⃣ 设备树(主流)

of_match_table

static const struct of_device_id my_of_match[] = {
    { .compatible = "myvendor,mydevice" },
    { }
};

MODULE_DEVICE_TABLE(of, my_of_match);

📌 compatible 是核心


六、Platform 设备注册方式


1️⃣ 非设备树(不推荐)

注册 device

static struct resource my_res[] = {
    {
        .start = 0x10000000,
        .end   = 0x10000FFF,
        .flags = IORESOURCE_MEM,
    },
};

static struct platform_device my_dev = {
    .name = "my_plat_dev",
    .id = -1,
    .resource = my_res,
    .num_resources = ARRAY_SIZE(my_res),
};

platform_device_register(&my_dev);


2️⃣ 设备树(主流)

DTS 示例

mydev@10000000 {
    compatible = "myvendor,mydevice";
    reg = <0x10000000 0x1000>;
    interrupts = <10>;
};

📌 设备树自动生成 platform_device


七、Platform 驱动完整示例(设备树)


1️⃣ 驱动代码

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

    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    base = devm_ioremap_resource(&pdev->dev, res);

    printk("platform device probed\n");
    return 0;
}

static int my_remove(struct platform_device *pdev)
{
    printk("platform device removed\n");
    return 0;
}


2️⃣ 驱动注册

static const struct of_device_id my_of_match[] = {
    { .compatible = "myvendor,mydevice" },
    {}
};

static struct platform_driver my_driver = {
    .probe = my_probe,
    .remove = my_remove,
    .driver = {
        .name = "my_plat_drv",
        .of_match_table = my_of_match,
    },
};

module_platform_driver(my_driver);


八、Platform 驱动中常用 API(高频)

API作用
platform_get_resource获取资源
devm_ioremap_resource映射寄存器
platform_get_irq获取中断
devm_request_irq申请中断
devm_kzalloc设备托管内存

📌 devm_ = 自动释放


九、为什么 probe 会被调用?

设备树加载
 ↓
生成 platform_device
 ↓
platform_driver 注册
 ↓
匹配 compatible
 ↓
probe()

📌 不是 main 函数调用


十、Platform 与字符设备关系(必懂)

platform_driver
     ↓
probe()
     ↓
注册 char device
     ↓
创建 /dev/xxx

👉 Platform 负责 “找到硬件”
👉 字符设备负责 “提供用户接口”


十一、常见面试题 & 标准答案

Q1:Platform 和 PCI/USB 区别?

Platform 不支持枚举,靠设备树描述


Q2:probe 什么时候调用?

设备和驱动匹配成功时


Q3:platform_device 从哪来?

设备树 or board 文件


Q4:为什么用 devm_*?

自动资源回收,防泄漏


十二、一句话终极总结(必背)

Platform 是 Linux 中描述 SoC 内部设备的核心机制,
通过设备树生成 device,
通过 compatible 匹配 driver,
probe 完成硬件初始化。