Day 8(下篇):总线驱动模型实战全解析 —— 以 PCA9450 PMIC 为例

发布于:2025-04-12 ⋅ 阅读:(37) ⋅ 点赞:(0)

✅ Day 8(下篇):总线驱动模型实战全解析 —— 以 PCA9450 PMIC 为例

在上一篇博文中,我们深入梳理了 Linux 驱动框架中两大核心模型 —— 平台驱动模型与总线驱动模型 —— 的结构差异与匹配逻辑。在本篇下篇中,我们将从一个完整的 I2C 总线驱动模型实战出发,以 NXP i.MX8M Plus EVK 板载的 PCA9450 PMIC 电源芯片为例,详细讲解设备树设计、驱动匹配过程、驱动模型与资源获取机制,帮助你真正掌握“总线驱动模型”的应用与核心技术点。


🔁 一、上篇回顾:平台 vs 总线驱动模型

在上篇中,我们明确区分了两个核心驱动模型:

分类 模型名称 典型接口 设备绑定方式 匹配依据
平台驱动模型 platform_driver + platform_device platform_get_resource() 设备树 + platform_bus .compatible + platform_match
总线驱动模型 i2c_driverspi_driverpci_driver i2c_add_driver()i2c_probe() 总线设备自动挂载 总线类型 + .id_table or .of_match_table

它们都属于统一的 Linux 设备模型体系,但在驱动注册、设备创建、资源获取方式等方面有着本质差异。

在这篇文章中,我们将把理论落地,从实际硬件和驱动代码出发,对总线驱动模型做一次全面的实战讲解。


🧩 二、硬件结构解析:PCA9450 在 i.MX8MP 上的供电角色

✅ 2.1 电源架构图理解

我们首先看下官方 EVK 的 PWR TREE 图:

这张图显示了 PCA9450 PMIC 所控制的多个电压通道(BUCKx、LDOx),它们为 i.MX8MP 的核心电源、IO 电源、LPDDR4 等子系统提供稳压输出。

从图中可见:

  • PCA9450 是通过 I2C 接口与 SoC 相连。
  • PMIC 的多个输出通道,如 BUCK1/2/4/5/6LDO1/2/3/4/5,分别负责供电给 CPU、LPDDR4、eMMC、USB、WiFi 等模块。
  • VDD_ARMVDD_DRAMNVCC_DRAM 等电源信号直接由 PCA9450 管脚控制。

📁 三、设备树结构讲解(以 i2c1@30a20000 节点为起点)

我们先来看设备树中关于 I2C1 控制器与 PCA9450 的定义:

&i2c1 {
    clock-frequency = <400000>;
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_i2c1>;
    status = "okay";

    pmic@25 {
        compatible = "nxp,pca9450c";
        reg = <0x25>;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_pmic>;
        interrupt-parent = <&gpio1>;
        interrupts = <3 IRQ_TYPE_LEVEL_LOW>;

        regulators {
            buck1: BUCK1 {
                regulator-name = "BUCK1";
                regulator-min-microvolt = <600000>;
                regulator-max-microvolt = <2187500>;
                regulator-boot-on;
                regulator-always-on;
            };
            ...
        };
    };
};

✅ 核心字段解释:

字段 含义
&i2c1 表示引用 i2c1 控制器
pmic@25 PMIC 芯片的 I2C 地址为 0x25
compatible 匹配驱动的关键字段,驱动需声明支持 "nxp,pca9450c"
regulators 子节点,定义具体电源通道的电压配置和属性

设备树中通过 .compatible + reg 进行 设备绑定,再通过 regulators 子节点完成电源控制逻辑的描述。


🧩 四、驱动注册与匹配分析

在 PCA9450 的驱动源码中,我们可以看到典型的 I2C 总线驱动写法:

static const struct of_device_id pca9450_of_match[] = {
    { .compatible = "nxp,pca9450c", .data = (void *)PCA9450_TYPE_PCA9450C },
    ...
};
MODULE_DEVICE_TABLE(of, pca9450_of_match);

static struct i2c_driver pca9450_i2c_driver = {
    .driver = {
        .name = "nxp-pca9450",
        .of_match_table = pca9450_of_match,
    },
    .probe = pca9450_i2c_probe,
};
module_i2c_driver(pca9450_i2c_driver);

✅ 匹配流程详解:

  1. i2c 总线子系统扫描设备树,识别挂载在 i2c1 控制器下的从设备节点。
  2. 找到 compatible = "nxp,pca9450c"
  3. 内核会遍历 i2c_driver 中的 .of_match_table,发现匹配项,调用 .probe()

此过程无需手动注册 platform_device,而是 通过 i2c 子系统自动完成,这就是总线驱动模型的优势:结构清晰,自动匹配


🔧 五、资源获取方式差异说明

功能 平台驱动模型 总线驱动模型
获取资源(reg) platform_get_resource() regmap_init_i2c()i2c_smbus_read_*()
时钟 devm_clk_get() 通常不涉及
中断 platform_get_irq() 通过 client->irq 获得
设备数据 platform_get_drvdata() i2c_set_clientdata()

以 PCA9450 为例,驱动通过 regmap_init_i2c() 来访问内部寄存器:

pca9450->regmap = devm_regmap_init_i2c(i2c, &pca9450_regmap_config);

这本质上就是用 i2c_transfersmbus API,完成对 PMIC 内部寄存器的读写操作。


🧩 六、regulator 框架接入流程

PCA9450 的每一个电源输出(BUCK/LDO)都以子设备形式注册为一个 regulator 控制器,整个驱动通过如下步骤完成电源输出控制的注册:

  1. 解析设备树 regulators 节点;
  2. 注册每个 regulator 设备;
  3. 提供 regulator_ops 函数集支持 enable/disable、set_voltage 等操作;
  4. 提供 ramp_delay、电压范围等配置。

示例代码:

rdev = devm_regulator_register(pca9450->dev, desc, &config);

注册成功后,其他子系统(如 CPU 调频、系统电源管理等)就可以调用 regulator API 控制该 PMIC 电压。


📌 七、I2C 总线驱动模型核心总结

核心要素 总结说明
驱动结构 i2c_driver 注册、.probe() 初始化、.remove() 清理
匹配机制 依赖 i2c-core 扫描设备树并调用 .of_match_table
资源访问 通过 regmap_init_i2c() 映射寄存器,使用 i2c_transfer 进行访问
驱动模型 本质上是总线驱动模型的一种典型实现,属于设备模型框架下的子类
与平台模型区别 不需创建 platform_device,资源访问机制不同,结构更自动

✅ 结语:理解“设备模型”的统一性

总线驱动模型和平台驱动模型虽然接口风格不同,但都基于 Linux 内核统一的 设备模型(device model) 框架:

  • 驱动与设备通过 bus_type 关联;
  • 匹配靠 of_match_tableid_table
  • 所有子系统设备(如 i2c_clientspi_deviceplatform_device)都挂接到统一的 /sys/bus/ 下。

通过本篇内容,我们以 PCA9450 的完整结构为例,深刻理解了 “从设备树 → 总线匹配 → 驱动注册 → 子设备资源注册” 的全过程。


📚 推荐阅读

  • Documentation/devicetree/bindings/regulator/
  • drivers/regulator/core.c
  • drivers/i2c/i2c-core-base.c
  • NXP i.MX Linux BSP 源码中的 drivers/regulator/pca9450.c

如果你已经理解本篇内容,那么恭喜你已真正掌握 Linux 总线驱动模型的底层结构和实战应用。下一篇,我们将深入 Linux 电源管理机制中的 suspend/resume 实现逻辑,进一步探讨 regulator 与 runtime PM 的协同作用。


网站公告

今日签到

点亮在社区的每一天
去签到