📄 Linux Platform 总线、设备与驱动原理详解
🔷 什么是 Platform 总线?
Platform 总线(platform_bus) 是 Linux 内核提供的一种虚拟总线,用于管理和组织与特定硬件平台相关的设备和驱动。
它充当了 平台设备(platform_device) 和 平台驱动(platform_driver) 之间的桥梁,负责将两者进行匹配和绑定。
🌟 核心原则:
先分离后搭档。
硬件资源写在 device.c,驱动逻辑写在 driver.c,两者通过相同的名字匹配。
💡 platform 的应用场景:
没有明确标准总线的片上资源(SoC 内部),比如 GPIO、时钟控制器、LED、按键等。
🔷 为什么要用 Platform 总线?
✅ 设备和驱动分离,逻辑更清晰
✅ 提高驱动代码的复用性
✅ 减少重复代码
✅ 提高代码的可移植性
🔷 Platform 总线的三个角色
| 部分 | 结构体 | 作用 | 包含内容 |
|---|---|---|---|
| 🛠 硬件资源 | struct platform_device | 告诉内核:我有一个 XXX 设备在这里 | 名字、物理地址、IRQ、设备树节点 |
| ⚙️ 驱动逻辑 | struct platform_driver | 告诉内核:我能控制名字叫 XXX 的设备 | 驱动逻辑、probe/remove 等回调 |
| 🚌 虚拟总线 | platform_bus | 匹配 device 和 driver | 管理两者的绑定关系 |
📄 硬件资源注册(device.c)
🔷 注册 platform 设备
通过 platform_device_register() 向内核注册一个平台设备。
🔷 platform_device 结构体
定义在:include/linux/platform_device.h
用于描述平台设备的硬件资源。
struct platform_device {
const char *name; // 设备名字
int id; // 设备ID
struct resource *resource; // 硬件资源数组
unsigned int num_resources; // 资源个数
...
};
🔷 资源描述(struct resource)
定义在:include/linux/ioport.h
用于描述硬件资源:内存、I/O、IRQ 等。
struct resource {
resource_size_t start; // 资源起始地址
resource_size_t end; // 资源结束地址
const char *name; // 资源名字
unsigned long flags; // 资源类型标志
};
常见 flags:
| 类型 | 宏 |
|---|---|
| 内存资源 | IORESOURCE_MEM |
| I/O 资源 | IORESOURCE_IO |
| 中断资源 | IORESOURCE_IRQ |
📄 驱动逻辑注册(driver.c)
🔷 注册 platform 驱动
通过 platform_driver_register() 注册平台驱动。
🔷 platform_driver 结构体
定义在:include/linux/platform_device.h
struct platform_driver {
int (*probe)(struct platform_device *pdev); // 匹配成功后调用
int (*remove)(struct platform_device *pdev); // 驱动卸载时调用
struct device_driver driver; // 名字、of_match_table
};
匹配条件:
- 如果有设备树:根据
compatible匹配。- 没有设备树:
platform_device.name == platform_driver.driver.name
🔷 驱动卸载
通过:
platform_device_unregister();
platform_driver_unregister();
从内核注销设备或驱动。
🔷 probe 函数的编写
当设备和驱动匹配成功后,内核会调用驱动的 probe() 函数。
典型流程:
✅ 打印匹配成功
✅ 获取硬件资源
✅ ioremap 资源地址
✅ 初始化硬件寄存器
✅ 注册字符设备
✅ 创建设备节点 /dev/xxx
🔷 获取硬件资源的两种方式
方法 1️⃣:直接访问资源数组
pdev->resource[i]
不推荐,写死了顺序。
方法 2️⃣:推荐使用 platform_get_resource()
struct resource *platform_get_resource(
struct platform_device *pdev,
unsigned int type,
unsigned int num);
返回值:找到的资源指针,失败返回 NULL。
📄 平台驱动 + 字符设备示意
| 步骤 | 关键 API |
|---|---|
| 驱动注册 | platform_driver_register() |
| 设备注册 | platform_device_register() |
| 获取资源 | platform_get_resource() |
| 地址映射 | ioremap() |
| 操作寄存器 | readl()/writel() |
| 注册 cdev | cdev_add() |
| 创建设备节点 | device_create() |
🔷 probe() 关键步骤总结
1️⃣ 匹配成功打印
2️⃣ 获取资源:platform_get_resource()
3️⃣ ioremap:将物理地址映射为内核虚拟地址
4️⃣ 初始化硬件(GPIO、寄存器、默认状态)
5️⃣ 注册字符设备、创建设备节点
📄 Platform 总线驱动框架总结
| 步骤 | 描述 |
|---|---|
| 📝 1 | 编写 platform_device 描述硬件资源 |
| 📝 2 | 编写 platform_driver 实现驱动逻辑 |
| 📝 3 | 注册 device 和 driver |
| 📝 4 | 内核扫描匹配 |
| 📝 5 | 调用 probe() 初始化设备 |
📖 匹配优先级
✅ 设备树(compatible) > 设备/驱动名字匹配
📋 总结
✅ 平台设备负责告诉内核硬件资源在这里。
✅ 平台驱动负责告诉内核我能控制这些硬件。
✅ 两者通过名字(或设备树)匹配成功后,调用驱动的 probe() 初始化设备。
✅ 所有资源的管理都通过 Platform 总线完成,逻辑清晰、便于维护。
🚀 推荐阅读
- Linux 设备驱动开发指南
- 《Linux 设备驱动开发详解》
543

被折叠的 条评论
为什么被折叠?



