NXP PCA9450 PMIC 驱动中 probe 函数的总线模型与资源获取逻辑详解

🔍

B站相应的视屏教程
📌 内核:博文+视频 - 总线驱动模型实战全解析 —— 以 PCA9450 PMIC 为例
敬请关注,记得标为原始粉丝。


在这里插入图片描述

本节深入剖析 NXP PCA9450 PMIC(电源管理芯片)驱动中 pca9450_i2c_probe() 函数的实现原理,讲解如何通过设备树、I2C 总线模型和 Linux regulator 子系统实现多个电源通道的注册与管理。我们将从总线匹配、资源获取、regulator 注册、GPIO 处理等方面全面讲解,并配合结构图、函数表格、设备树实例等丰富内容,帮助读者全面掌握典型 PMIC 驱动的写法。本文共计约 6000 字,适合作为内核驱动学习和讲解材料。


一、驱动的总线模型与匹配机制:I2C 驱动非 platform 驱动

虽然使用了 devm_*regmap_*regulator_register() 等函数与平台驱动类似,但 本驱动并非 platform_driver,而是基于 I2C 的 i2c_driver

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

设备树通过 compatibleof_device_id 匹配,I2C 核心框架通过 reg 获取地址并自动探测设备。

示例:设备树结构(完整展开)

&i2c1 {
  pmic@25 {
    compatible = "nxp,pca9450a";
    reg = <0x25>;                             // I2C 地址
    interrupt-parent = <&gpio1>;
    interrupts = <3 IRQ_TYPE_LEVEL_LOW>;     // 中断来源
    sd-vsel-gpios = <&gpio3 5 GPIO_ACTIVE_HIGH>; // 控制 LDO5 电压表征

    regulators {
      buck1 {
        regulator-name = "vdd_arm";
        nxp,dvs-run-voltage = <900000>;      // DVS 运行模式电压
        nxp,dvs-standby-voltage = <800000>;  // DVS 待机模式电压
      };
      ldo1 {
        regulator-name = "vdd_3v3";
      };
    };
  };
};

二、probe 函数核心功能与分阶段操作

pca9450_i2c_probe() 的设计目标是:初始化 I2C 寄存器访问(regmap)、配置中断、注册所有电源通道(BUCK/LDO)、读取 GPIO 配置、验证芯片 ID 和版本。流程结构如下:

📘 probe 流程图

驱动加载
   ↓
i2c-core 匹配 compatible
   ↓
pca9450_i2c_probe()
├── devm_kzalloc()                    // 分配主数据结构
├── devm_regmap_init_i2c()           // 建立 regmap
├── regmap_read()                    // 读取设备 ID
├── 选择 regulator 表格
├── 遍历 regulator:
│    ├── 传入 desc
│    └── devm_regulator_register()
├── devm_request_threaded_irq()
├── 配置寄存器(中断屏蔽等)
└── 获取 sd-vsel GPIO(可选)

三、关键结构体成员说明与作用

struct pca9450_regulator_desc

struct pca9450_regulator_desc {
    struct regulator_desc desc;           // regulator 子系统用的描述符
    const struct pc9450_dvs_config dvs;   // 对应的 DVS 控制寄存器掩码信息
};

用于将一个 regulator_desc 进行封装,并指定该通道的 run/standby 电压控制寄存器与掩码。

struct pca9450

struct pca9450 {
    struct device *dev;                  // 设备对象(从 i2c_client 中获得)
    struct regmap *regmap;              // I2C 寄存器访问封装
    struct gpio_desc *sd_vsel_gpio;     // LDO5 电压控制引脚
    enum pca9450_chip_type type;        // 芯片型号
    unsigned int rcnt;                  // regulator 通道数量
    int irq;                             // 中断编号
};

四、资源获取函数与设备树属性的一一对应

API 函数获取资源类型对应设备树字段返回值类型 / 说明
devm_regmap_init_i2c()I2C 寄存器映射reg = <0x25>struct regmap *
regmap_read()寄存器读取-芯片 ID 或状态位
devm_request_threaded_irq()中断资源interrupts = <...>请求中断 IRQ(由设备树中断号决定)
gpiod_get_optional()GPIO 控制线sd-vsel-gpios控制 LDO5 模式(电压选择)
of_property_read_u32()获取电压值nxp,dvs-run-voltage运行/待机电压配置
devm_regulator_register()注册 regulatorregulators 节点下子节点生成 regulator 实例

五、以 buck1 为例完整说明设备树 → 驱动注册流程

buck1 {
  regulator-name = "vdd_arm";
  nxp,dvs-run-voltage = <900000>;
  nxp,dvs-standby-voltage = <800000>;
};

驱动注册过程:

  1. 遍历 regulator 描述表(pca9450a_regulators[]
  2. 传入 regulator_descdevm_regulator_register()
  3. 如果 desc->of_parse_cb 非 NULL,执行 pca9450_set_dvs_levels()
  4. 它进一步调用 buck_set_dvs(),使用 of_property_read_u32() 获取 nxp,dvs-run-voltage,并配置寄存器

六、设备树结构图与 API 映射示意

📊 结构与函数映射图

&i2c1                            →  i2c_adapter + i2c_client
  └── pmic@25                    →  i2c_client 绑定 probe()
       ├── reg = <0x25>         →  devm_regmap_init_i2c()
       ├── interrupts           →  devm_request_threaded_irq()
       ├── sd-vsel-gpios       →  gpiod_get_optional()
       └── regulators           →  regulator_register()
           ├── buck1           →  pca9450_set_dvs_levels()
           └── ldo1            →  无需解析电压,直接注册

七、devm_ 系列函数的资源释放机制

函数功能优势
devm_kzalloc()申请内存在驱动 remove 时自动释放
devm_regmap_init_i2c()初始化 regmap自动释放 regmap 资源
devm_request_threaded_irq()中断申请自动释放 IRQ 注册
devm_regulator_register()注册电源模块由 regulator core 管理生命周期
gpiod_get_optional()获取 GPIO 控制线自动释放 GPIO 控制器

📘 等价于现代 C++ 中的智能指针 RAII(资源自动释放)模型,避免内存泄漏和资源残留。


八、完整总结与拓展

该 PCA9450 驱动充分体现了嵌入式 Linux 中典型 I2C 器件的驱动结构:

  • 使用设备树匹配 → i2c-core 框架驱动探测
  • regmap 简化寄存器访问(无需手动写 I2C)
  • regulator 子系统标准化电源通道管理
  • devm_ 系列自动资源释放机制避免手动释放
  • 每个 regulator 支持 DVS(动态电压选择)控制
  • 可选 GPIO 控制硬件输入选择(如 sd-vsel

✅ 若你掌握了 PCA9450 的驱动结构,将轻松应对同类芯片,如 Dialog、TI、ROHM、Maxim 等 PMIC 驱动设计。


📘 后续扩展建议

扩展主题建议内容
regulator 注册流程内部如何挂载到 /sys/class/regulator
regmap 操作原理读写如何转换为 i2c_transfer 操作
BUCK 与 LDO 差异稳压结构、用途、配置区别
中断事件分析IRQ_THERM_125、IRQ_VR_FLT1 等意义
多 PMIC 管理多个 PMIC 时的调度策略与依赖配置
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值