📍 本文适用于 Linux 内核开发者、嵌入式工程师、Yocto 项目实践者,深入讲解设备树(Device Tree)的结构、属性、驱动匹配机制与常用
of_
函数,结合 NXP i.MX 8M Plus EVK 示例展开分析。
🔍
B站相应的视屏教程:
📌 内核:博文+视频 - 备树深度解析:理论 + 实践全指南(含 of 函数与 i.MX8MP 实例)
敬请关注,记得标为原始粉丝。
在 Linux 设备树驱动中,有一个低调但极其关键的函数:of_platform_populate()
。它隐藏在许多驱动框架的初始化流程中,自动地把设备树中的子节点“变成”一个个 struct device,并交由相应驱动匹配和管理。
今天,我们将深度解析这个机制,从源码结构、使用方式到实际应用场景,全方位讲透它。
一、什么是 of_platform_populate?
of_platform_populate()
是 Linux 设备树框架中用于“自动创建平台子设备”的函数。
它的主要作用是:
把设备树中的子节点,转化为对应的 platform_device,挂到父设备下,并自动走驱动绑定流程。
很多驱动不会自己主动去创建子设备,而是依赖这个函数来“扫描”设备树子节点,注册成 platform 设备,驱动只需要提供 of_match_table
即可完成绑定。
二、典型使用场景
例如,在 SoC 的中断控制器(GIC)、时钟控制器、MMIO 总线控制器等驱动初始化阶段,经常会看到类似的代码:
of_platform_populate(np, NULL, NULL, &pdev->dev);
或者:
of_platform_populate(NULL, of_default_bus_match_table, NULL, &dev->dev);
含义是:扫描 np
或 dev->of_node
下的子节点,将符合匹配规则的节点都注册为 platform_device。
三、设备树结构示例
举个例子,设备树中我们可能定义如下结构:
soc {
compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
ranges;
serial@30890000 {
compatible = "fsl,imx8mp-uart", "fsl,imx6q-uart";
reg = <0x30890000 0x10000>;
interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
status = "okay";
};
spi@30820000 {
compatible = "fsl,imx8mp-spi";
reg = <0x30820000 0x10000>;
status = "okay";
};
};
当我们调用:
of_platform_populate(of_find_node_by_path("/soc"), NULL, NULL, NULL);
内核就会自动注册两个设备:
/soc/serial@30890000
→platform_device
/soc/spi@30820000
→platform_device
而你在 driver 中注册的 platform_driver
会根据 compatible 匹配进行绑定。
四、源码深入解析
源码位置:
drivers/of/platform.c
核心函数:
int of_platform_populate(struct device_node *root,
const struct of_device_id *matches,
const struct of_dev_auxdata *lookup,
struct device *parent);
核心逻辑:
- 遍历 root 节点的子节点;
- 判断是否匹配
matches
; - 如果是 compatible 节点,则构建 platform_device;
- 设置其资源信息(如 reg、interrupt);
- 调用
platform_device_register()
; - 自动执行驱动匹配流程。
实质上,这是将设备树静态定义的设备转化为动态注册流程的一座“桥梁”。
五、实战:基于 simple-bus 的子节点创建
很多平台的设备树会定义一个如下结构:
soc {
compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
ranges;
gpio@30200000 {
compatible = "fsl,imx-gpio";
reg = <0x30200000 0x10000>;
interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
status = "okay";
};
};
内核中 simple-bus
对应的驱动在 drivers/of/platform.c
中定义了一个特殊的 of_platform_driver
:
static const struct of_device_id of_default_bus_match_table[] = {
{ .compatible = "simple-bus", },
{ /* sentinel */ },
};
注册位置:
of_platform_default_populate_init();
在内核 early init 阶段执行,完成了所有 simple-bus
下设备的自动注册。
六、和 platform_device 机制的关系
我们可以理解为:
platform_device
是 Linux 的基础模型,用于表示挂载在平台总线上的设备。of_platform_populate
是一个“工厂函数”,负责从设备树中解析并自动生成platform_device
实例。
这一机制让我们不用手动注册 platform_device
,大大简化了驱动的开发。
七、常见问题与误区
✅ Q1:子设备不执行 probe,什么原因?
可能是:
- 设备树节点未启用(status != “okay”)
- compatible 不匹配
- 未调用
of_platform_populate()
(或未递归子节点)
✅ Q2:能否不使用 of_platform_populate,手动注册?
当然可以,但要自己处理:
- 解析 reg、interrupts;
- 注册 platform_device;
- 管理生命周期。
这不如使用 of_platform_populate()
简洁和一致。
八、核心总结表格
关键词 | 含义说明 |
---|---|
of_platform_populate() | 自动扫描并注册子节点为 platform_device |
compatible | 用于驱动匹配的关键字段 |
platform_driver | 驱动模型,用于匹配和管理设备 |
simple-bus | 通用容器节点,通过此机制实现自动子设备注册 |
reg 、interrupts | 自动传递给子设备的资源信息 |
九、启发:和设备模型的关联
在《Day 10》中,我们曾提到设备模型 ≈ 软件工程中的适配器模式。
现在你会发现:
of_platform_populate()
就像一个运行时的“适配器工厂”;- 它将静态结构(设备树)适配成 runtime 的 struct device;
- 通过
of_match_table
实现解耦和可扩展性。
它不是匹配驱动的机制本身,而是驱动模型中连接“静态结构”和“动态设备”的一部分。
十、结语与预告
今天我们系统讲解了 of_platform_populate()
的原理、作用和使用场景,揭示了它在设备树机制中的核心角色。
📌 下一篇 Day 12(下篇),我们将通过一个完整的子设备驱动实例,展示如何配合 of_platform_populate()
构建清晰、模块化的驱动架构。
欢迎点赞 + 收藏,关注“嵌入式 Jerry”技术平台(优快云,B站和公众号),持续追更《驱动开发硬核特训》系列!
🔍
B站相应的视屏教程:
📌 内核:博文+视频 - 备树深度解析:理论 + 实践全指南(含 of 函数与 i.MX8MP 实例)
敬请关注,记得标为原始粉丝。