目录

驱动开发硬核特训 · Day 6 : 深入解析设备模型的数据流与匹配机制 —— 以 i.MX8M 与树莓派为例的实战对比

🔍

B站相应的视屏教程

📌 内核:博文+视频 - 从静态绑定驱动模型到现代设备模型


主题:深入解析设备模型的数据流与匹配机制 ------ 以 i.MX8M 与树莓派为例的实战对比

在上一节中,我们从驱动框架的历史演进出发,分析了早期的静态绑定驱动模型及其局限性,并逐步过渡到现代 Linux 设备模型架构。本节将聚焦于设备模型运行时的数据结构与匹配流程,结合实际平台(NXP i.MX8M 与 Raspberry Pi),从设备树的编写、设备注册、驱动匹配、probe 调用 等多个角度展开,理论与实战融合讲解设备模型的本质运作方式。


📘 第一部分:设备模型的本质问题 ------ 驱动如何找到设备?

在设备模型中,驱动程序不再"直接控制硬件",而是等待系统提供设备信息,再由总线驱动匹配机制 完成"驱动与设备的配对",最终执行 probe()

因此,理解设备模型的核心本质,就是要搞清楚:

"驱动是怎么和设备匹配的?设备又是怎么被注册到系统中的?"

我们将通过 i.MX8M 和 Raspberry Pi 两个平台,来回答这个问题。


📘 第二部分:设备节点的来源 ------ 设备树(Device Tree)

✅ 什么是设备树?

设备树(DTS)是一种用于描述硬件信息的数据结构,编译为 DTB 后在内核启动初期被解析,生成内核中的 struct device_node 树形结构。内核随后根据设备树中的节点内容,注册相应的 platform_device

📎 i.MX8M 示例(LCDIF3 控制器)

dts 复制代码
lcdif3: lcd-controller@32fc6000 {
    compatible = "fsl,imx8mp-lcdif1";
    reg = <0x32fc6000 0x10000>;
    interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
    clocks = <&clk IMX8MP_CLK_MEDIA_APB_ROOT>, ...;
    status = "okay";
};

📌 内核会根据 compatible 字符串创建一个 platform_device,名字类似 lcdif3.32fc6000

📎 Raspberry Pi 示例(I2C 控制器)

dts 复制代码
i2c1: i2c@7e804000 {
    compatible = "brcm,bcm2835-i2c";
    reg = <0x7e804000 0x1000>;
    interrupts = <2 21>;
    clock-frequency = <100000>;
    status = "okay";
};

设备树被内核解析后,注册为 platform_device,后续等待匹配合适的驱动。


📘 第三部分:驱动如何声明匹配信息?

驱动需要提供一个 of_match_table,用于告诉设备模型:"我支持哪些设备"。

c 复制代码
static const struct of_device_id lcdifv3_dt_ids[] = {
    { .compatible = "fsl,imx8mp-lcdif1" },
    { }
};
MODULE_DEVICE_TABLE(of, lcdifv3_dt_ids);

static struct platform_driver lcdifv3_driver = {
    .probe = lcdifv3_probe,
    .remove = lcdifv3_remove,
    .driver = {
        .name = "imx-lcdifv3",
        .of_match_table = lcdifv3_dt_ids,
    },
};

🔍 注意:只有匹配成功,probe 才会被调用


📘 第四部分:匹配过程是如何完成的?

✅ 匹配的参与者:

组件 数据结构
设备 struct platform_device
驱动 struct platform_driver
匹配规则 struct of_device_id[]
总线中转调度器 struct bus_type

✅ 匹配流程

  1. 设备树解析阶段,生成 platform_device(如 lcdif3
  2. 驱动注册时,添加到 platform_bus_typedriver_list
  3. 内核自动遍历设备与驱动,调用 bus_type->match()
  4. 匹配成功后:
    • 设置 pdev->dev.driver = &driver
    • 调用 driver->probe(pdev) 完成初始化

📘 第五部分:数据结构流动分析(从 DTS 到 probe)

📌 流程图:

复制代码
DTS  of_node (设备树节点)
   
of_platform_populate()
   
platform_device_register()
   
/sys/devices/platform/xxx  ←→ /sys/bus/platform/devices/xxx
   
platform_bus_type.match()
   
platform_driver.probe()

📎 代码对应点(以 LCDIF3 为例):

关键节点 对应代码
compatible = "fsl,imx8mp-lcdif1" of_device_id 中匹配
reg/clocks 等资源 of_address_to_resource() 等函数读取
probe 中访问资源 platform_get_resource() / devm_ioremap_resource()

📘 第六部分:i.MX8M vs 树莓派平台对比

对比维度 NXP i.MX8M Raspberry Pi
SoC 架构 多个 LCDIF 控制器 + VPU Broadcom BCM283x
DTS 中定义 fsl,imx8mp-lcdif1 brcm,bcm2835-i2c
驱动模块名 imx-lcdifv3 i2c-bcm2835
驱动结构 完整 platform_driver + match 同样采用 of_match_table 匹配
热插拔支持 支持 runtime pm / suspend / resume 同样支持 PM、sysfs、modprobe 热加载

📌 虽然 SoC 不同,但设备模型使用方式完全统一


📘 第七部分:常见问题与调试技巧

❓ Q1: 为什么 probe 没被调用?

  • 没有写 of_match_table
  • compatible 写错,无法匹配
  • 驱动未被编译进内核或未加载
  • status = "disabled" 导致设备未注册

❓ Q2: 如何确认设备已注册?

  • 查看 /sys/bus/platform/devices/
  • 使用 dmesg 检查设备是否出现
  • dev_info() 等日志确认 probe 是否执行

❓ Q3: 如何查看匹配关系?

bash 复制代码
modinfo xxx.ko  # 查看 compatible alias
ls /sys/bus/platform/drivers/xxx

📘 第八部分:实战建议

  • 永远在驱动中写上正确的 of_match_table
  • 使用 devm_* 系列管理资源,避免内存泄漏
  • 善用 dev_dbg()dev_err() 等接口打印调试信息
  • 多观察 /sys/ 目录,理解设备与驱动的 sysfs 映射关系
  • 多平台共享一个驱动时,合理利用 of_device_id.data 携带平台定制参数

✅ 总结与回顾

本篇深入分析了设备模型中从 DTS → 设备注册 → 驱动匹配 → probe 执行的完整过程。通过对比 i.MX8M 与树莓派平台,我们看到了设备模型在不同平台间的通用性与强大抽象能力

📌 核心关键词:

  • 设备树注册 → platform_device 创建
  • 驱动注册 → platform_driver with of_match_table
  • 内核总线 → bus_type 匹配 → 调用 probe

这正是现代 Linux 驱动开发的标准范式。

下一篇我们将从 资源管理角度 (时钟、中断、寄存器、GPIO)展开,讲解 platform_get_resource()devm_*()of_property_read_*() 等函数在实际项目中的最佳使用方式。

本文是转载文章,点击查看原文
如有侵权,请联系 xyy@jishuzhan.net 删除
相关推荐
程序员JerrySUN2 天前
驱动开发硬核特训 · Day 25 (附加篇):从设备树到驱动——深入理解Linux时钟子系统的实战链路
linux·运维·驱动开发
程序员JerrySUN2 天前
驱动开发硬核特训 · Day 24(上篇):走进Linux内核时钟子系统 —— 硬件基础全解析
linux·驱动开发·单片机
程序员JerrySUN2 天前
驱动开发硬核特训 │ Regulator 子系统全解
linux·驱动开发·嵌入式硬件
qxqxa2 天前
dma_request_slave_channel_compat 与 dma_request_channel 的区别
linux·驱动开发
程序员JerrySUN2 天前
驱动开发硬核特训 · Day 21(上篇) 抽象理解 Linux 子系统:内核工程师的视角
java·linux·驱动开发
kuinnebula2 天前
Linux GPIO驱动开发实战:Poll与异步通知双机制详解
驱动开发
程序员JerrySUN3 天前
驱动开发硬核特训 │ 深度解析 fixed regulator 驱动与 regulator_ops
驱动开发
Blossom.1183 天前
可解释人工智能(XAI):让机器决策透明化
人工智能·驱动开发·深度学习·目标检测·机器学习·aigc·硬件架构
Ant?13 天前
rk3588 驱动开发(三)第五章 新字符设备驱动实验
数据库·驱动开发
程序员JerrySUN3 天前
驱动开发硬核特训 · Day 22(下篇): # 深入理解 Power-domain 框架:概念、功能与完整代码剖析
linux·开发语言·驱动开发·嵌入式硬件