主题:深入解析 Platform Driver 驱动框架 —— 从架构设计到工程实战
平台驱动(platform driver)是 Linux 内核中应用最广泛的一种设备驱动框架。它用于管理那些不依赖总线枚举机制的固定外设,如 GPIO 控制器、I2C 控制器、SPI 控制器、PWM、ADC、各类片上模块等。
在嵌入式 Linux 开发中,熟练掌握 platform driver 的结构与接口,是理解设备模型与驱动机制的基础能力。本篇围绕平台驱动的本质机制,梳理其结构组成、设备匹配方式、设备树绑定流程、生命周期函数设计、资源管理与注册逻辑,并辅以完整可运行的驱动示例与工程化建议,帮助构建稳定、高效、清晰的驱动知识体系。
🎯 本期知识结构
模块 | 核心内容 |
---|---|
基本概念 | 什么是 platform 设备与驱动,适用场景 |
分离机制 | 驱动与设备分离的思想、本质、好处与典型示例 |
框架结构 | platform_device 与 platform_driver 的结构与作用 |
匹配原理 | 名字、compatible、ACPI 三种匹配方式 |
生命周期函数 | probe/remove 执行时机与职责 |
注册方式 | 宏展开 vs 手动注册机制解析 |
资源管理 | IO、GPIO、中断、时钟等常见资源的管理方式 |
实战案例 | LED 控制的完整 platform 驱动实现 |
框架对比 | 与 PCI、USB 等标准总线驱动的差异与联系 |
工程建议 | 如何写出稳定可维护的 platform 驱动 |
📘 Part 1:什么是 Platform Driver?
Platform Driver 是 Linux 内核中用于管理“平台设备”的驱动框架。
所谓“平台设备”,可以简单理解为:那些无法通过标准总线(如 PCI 或 USB)自动识别的固定连接外设。
这些设备通常具有如下特点:
- 是 SoC(系统级芯片)内部集成的硬件模块,如 UART、GPIO、I2C 控制器;
- 或通过固定方式连接在主控的管脚上,如 LED、按键、蜂鸣器、电源管理芯片 PMIC 等;
- 没有专门的总线控制器进行自动枚举,需开发者主动在设备树中声明其存在。
因此,Platform Driver 提供了这样一种机制:驱动专注实现控制逻辑,而设备信息由设备树提供,二者通过内核的 platform 总线完成匹配与绑定。
📘 Part 2:驱动与设备分离机制详解
Linux 提倡“驱动与设备分离”的设计思想,其核心是:将驱动逻辑与设备信息解耦,提高驱动代码的复用性与系统的灵活配置能力。
✅ 简单理解:
驱动代码只管“怎么驱动”,设备信息只说“驱动什么”,由内核机制负责把它们关联起来。
📌 核心优势:
- 同一套驱动逻辑可以复用在多个平台,仅需修改设备树而不必改动驱动源码;
- 适配不同 SoC 或板级硬件资源(如 IO 地址、中断号等)无需改代码,方便维护与适配;
- 遵循统一设备模型结构,支持模块热插拔、系统动态管理。
📘 举例说明:
- 如一个控制 GPIO 灯的驱动中声明
compatible = "demo,myled"
,只要设备树中出现对应节点,驱动就能自动匹配并完成初始化,无需更改驱动源码。
📘 Part 3:匹配机制与设备树关系
✅ 匹配方式主要有三种:
匹配方式 | 描述与适用情况 |
---|---|
name 字符串匹配 | 传统内核平台中 pdev->name 与 pdrv->driver.name 相同即可匹配 |
设备树匹配 | 通过 compatible 字符串与 of_device_id 匹配 |
ACPI 匹配 | 用于 x86 平台,略 |
✅ 示例:设备树节点 + 匹配表
led@0 {
compatible = "myvendor,myled";
reg = <0x0209c000 0x1000>;
};
驱动端:
static const struct of_device_id led_dt_ids[] = {
{ .compatible = "myvendor,myled" },
{},
};
MODULE_DEVICE_TABLE(of, led_dt_ids);
static struct platform_driver myled_driver = {
.driver = {
.name = "myled",
.of_match_table = led_dt_ids,
},
.probe = myled_probe,
.remove = myled_remove,
};
📘 Part 4:生命周期函数详解
✅ probe 流程:
系统启动 → 匹配设备 → 调用 probe()
驱动中可以做:
- 获取资源(IO 内存、中断、GPIO)
- 注册子系统(如 input、misc、regmap 等)
- 创建字符设备、proc 文件、sysfs 节点等
✅ remove 流程:
设备卸载或驱动卸载 → 调用 remove()
常见操作:
- 释放资源(释放中断、释放内存)
- 注销子设备、注销字符设备
📘 Part 5:驱动注册机制与代码宏解构
驱动注册通常用宏封装:
module_platform_driver(myled_driver);
展开后等价于:
static int __init myled_init(void) {
return platform_driver_register(&myled_driver);
}
static void __exit myled_exit(void) {
platform_driver_unregister(&myled_driver);
}
module_init(myled_init);
module_exit(myled_exit);
📘 Part 6:资源管理与接口使用
✅ 1. 获取 IO 资源
struct resource *res;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
void __iomem *base = devm_ioremap_resource(&pdev->dev, res);
✅ 2. 获取中断号
int irq = platform_get_irq(pdev, 0);
request_irq(irq, handler, 0, "myled", NULL);
✅ 3. 获取 GPIO / clocks / regmap / pinctrl
// GPIO 示例
gpio = of_get_named_gpio(pdev->dev.of_node, "gpios", 0);
// Clk 示例
clk = devm_clk_get(&pdev->dev, NULL);
clk_prepare_enable(clk);
📘 Part 7:完整 platform 驱动示例(简化 LED 控制)
✅ 设备树:
myled@0 {
compatible = "demo,myled";
reg = <0x0209c000 0x1000>;
};
✅ 驱动核心代码:
static int myled_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);
writel(0x1, base); // 点亮 LED
return 0;
}
static const struct of_device_id myled_ids[] = {
{ .compatible = "demo,myled" },
{},
};
MODULE_DEVICE_TABLE(of, myled_ids);
static struct platform_driver myled_driver = {
.driver = {
.name = "myled",
.of_match_table = myled_ids,
},
.probe = myled_probe,
};
module_platform_driver(myled_driver);
MODULE_LICENSE("GPL");
📘 Part 8:平台驱动框架与其他总线的对比
类型 | 自动枚举 | 用途 |
---|---|---|
Platform | 否 | SoC 内部或板载外设 |
PCI | 是 | PC 扩展卡、可插拔硬件 |
USB | 是 | 即插即用设备(摄像头、鼠标等) |
I2C/SPI | 否 | 外部挂载设备,常与 platform 协同 |
Platform driver 是“非总线驱动”,需要手动绑定,适合固定电路场景。
📘 Part 9:工程化编写建议
- 使用
devm_*()
系列函数自动管理资源,防止泄露 - 匹配设备树时使用
of_match_table
+MODULE_DEVICE_TABLE
提高兼容性 - 分离 probe 逻辑与设备管理逻辑,便于维护
- 适当添加调试信息如
dev_info()
、dev_err()
辅助排查
🧠 本日知识点总结
模块 | 核心内容 |
---|---|
Platform 机制 | 用于非自动枚举的板载设备管理 |
核心结构体 | platform_device / platform_driver / resource |
匹配方式 | name 字符串 / 设备树 compatible / ACPI ID |
生命周期函数 | probe → 初始化;remove → 卸载清理 |
资源获取 | IO 内存、中断、GPIO、CLK、regmap |
示例应用 | LED 控制、UART、I2C、PWM、RTC 等 |
✅ 总结
Platform Driver 驱动框架是嵌入式 Linux 驱动学习与开发的基石。理解其结构、匹配机制、生命周期、资源获取方式,不仅能快速开发 SoC 板载外设驱动,也为深入掌握 Linux 设备模型(device model)奠定基础。
📘 Day 6 预告:深入理解设备模型(Device Model)与驱动绑定机制
继续专注核心,逐步构建完整的驱动工程体系。