拓冰建站拓冰建站
首页 / 资讯中心 / 正文

hi6421 PMIC驱动适配实战:从源码解析到设备树配置

简介这是一份聚焦Hi6421电源管理集成电路核心驱动的源码资源适合嵌入式驱动开发人员、Linux内核学习者以及电源管理方案设计者参考。压缩包仅含1个C语言源文件整体大小约1KB文件虽小却覆盖PMIC驱动的主干实现涉及初始化流程、控制与中断处理、I2C/SPI总线通信、动态电压频率调整、休眠低功耗模式以及过压/欠压保护等关键环节。逐段阅读这份源码可直观理解Hi6421与主处理器之间的交互机制掌握电压等级配置、负载开关控制、异常事件上报与热管理接口的具体写法为后续驱动移植或电源策略定制提供低成本的入门路径也可作为微型PMIC驱动范例用于教学或自学。该资源已有457人学习过。1. 拿到 hi6421-pmic-core.rar先确认你面对的是哪一层问题嵌入式开发里PMIC驱动往往不是最耀眼的部分但它一旦出问题整块板子都起不来。hi6421是海思平台常用的电源管理芯片而hi6421-pmic-core.rar这个名字通常出现在 BSP 包或第三方 SDK 的某个角落里——它不是一个完整的应用而是PMIC核心驱动的源码压缩包里面一般包含hi6421的 regulator 驱动、pmic-core框架代码以及一份或多份 PDF 规格书或驱动说明。对 Linux 驱动工程师来说这个压缩包意味着两件事一是你要把hi6421的电压调节器接入内核的 regulator 子系统二是你需要根据 PDF 里的寄存器定义和时序要求确认驱动的初始化和回调实现是否与硬件版本匹配。这篇文章顺着hi6421-pmic-core的实际内容和常见适配路径从驱动结构、源码解析、设备树配置到调试手法讲一套可以直接落地的做法。读者如果是做 BSP 移植或正在被“板子起来后电压不对”折磨的人这篇值得往下看。2. 拆开压缩包理清 hi6421 驱动在 BSP 里的真实结构2.1 先从 rar 包的文件布局判断驱动形态海思平台的 PMIC 驱动发布方式不固定有时以补丁形式有时以完整目录形式。打开hi6421-pmic-core.rar后常见的关键文件包括hi6421_pmic.c、hi6421_pmic.h、hi6421_regulator.c、Makefile或Kconfig以及确认芯片寄存器的 PDF。pmic-core这个后缀通常表示这一层是PMIC的核心抽象层它对接内核的regulator框架同时为同系列的hi6422、hi6423提供复用基础。# 解压后建议先做一次目录结构确认 mkdir -p hi6421_pmic cd hi6421_pmic unrar x ../hi6421-pmic-core.rar tree -L 2 -d # 预期看到 drivers/power/ 或 drivers/regulator/ 这类内核路径层级解压后确认目录层级是第一步这决定了你要把文件放到内核源码树的哪个位置以及Makefile应该如何修改。如果压缩包内的路径是drivers/power/hi6421那通常对应旧版内核的power目录如果是drivers/regulator/hi6421则说明驱动已经按新版内核的习惯放在 regulator 子系统下。实际做移植时我会直接让Makefile里的obj-$(CONFIG_REGULATOR_HI6421)指向解压出来的源文件路径这样可以避免复制源码时漏掉依赖头文件。pmic-core的核心价值在于把regmap、irq_chip、notifier这些通用机制封装在底层而上层的hi6421_regulator.c只需要关心芯片私有的电压表和寄存器位定义。分析这种驱动时不要从probe函数开始读而是先看Kconfig和Makefile明确它依赖哪些内核选项——比如REGULATOR、MFD_CORE、REGMAP——再进源码。2.2 regmap 和 regulator 框架是理解 pmic-core 的钥匙hi6421是一颗通过 I2C 接口访问寄存器组的 PMIC驱动中大量使用regmap来进行寄存器读写。regmap是内核提供的一套统一的寄存器访问缓存层好处是驱动不需要关心底层的 I2C 传输细节只需要指定regmap_config里的寄存器位宽、地址位宽和读写回调。// 典型的 regmap_config 初始化片段常见于 hi6421 pmic-core static const struct regmap_config hi6421_regmap_config { .reg_bits 8, .val_bits 8, .max_register HI6421_REG_MAX, .volatile_reg hi6421_is_volatile_reg, };reg_bits 8表示寄存器地址是 8 位宽度val_bits 8表示寄存器值是 8 位这种配置与多数 PMIC 的 I2C 寄存器协议一致。volatile_reg回调用来标记哪些寄存器不能被缓存——比如状态寄存器、中断标志寄存器。适配新板子时如果发现电压寄存器值写进去读出来不一致首先要检查的就是这个回调函数确认该寄存器没有被错误地标记为non-volatile。regulator框架部分hi6421_pmic.c中的probe函数一般会注册struct regulator_desc数组每个regulator_desc对应一路输出如LDO1、BUCK2然后调用devm_regulator_register注册到内核。这里最关键的字段是fixed_uV、min_uV、max_uV、uV_step它们直接决定regulator框架计算电压时的行为。很多 PMIC 的电压表非线性无法用简单的min n * step描述这种情况通常需要实现.set_voltage_sel回调用查找表代替线性计算。3. 驱动适配与设备树配置从 “能编译过” 到 “电压对得上”3.1 在目标内核版本里加入 hi6421 pmic-core 驱动拿到pmic-core源码后第一件要确认的事情是它对应的内核版本。海思 BSP 包的内核版本跨度很大linux-3.18、linux-4.4、linux-4.9甚至更新版本都有出现。regulator框架的 API 在演进过程中有变化特别是of_regulator_match和regulator_desc结构体的字段调整直接影响编译是否通过。# 以 4.9 内核为例添加驱动的基本步骤 cp -r hi6421_pmic ${KERNEL_DIR}/drivers/regulator/ cat ${KERNEL_DIR}/drivers/regulator/Makefile EOF obj-$(CONFIG_REGULATOR_HI6421) hi6421_pmic/regulator-hi6421.o EOF一些驱动包里自带 Makefile但通常不会自动加入到主Kconfig的依赖树中。如果你在make menuconfig里找不到REGULATOR_HI6421选项需要手动把配置项加进drivers/regulator/Kconfig。Kconfig条目要声明depends on关系常见的是depends on REGULATOR I2C。如果漏了I2C依赖编译时可能因为找不到i2c_client相关符号而失败。编译只是第一步真正容易踩坑的是regulator-core.c在某些内核版本中会检查regulator_desc的.name和.of_match如果两者不匹配设备树节点probe不会报错但驱动注册后会挂在dummy状态电压输出完全不受控制。所以适配启动阶段第一件事是先把设备树里regulator节点的compatible与of_match_table对上其次才是管脚和启动时序。3.2 设备树中 PMIC 节点的电压参数写法和语义hi6421在设备树中的常见形态是挂在 I2C 总线下的一个节点子节点用regulator-LDO1、regulator-BUCK2等方式表达各路输出。匹配驱动时of_regulator_match会遍历设备树子节点通过regulator-compatible属性寻找对应的regulator_desc。i2c0 { hi6421: hi64216b { compatible hisilicon,hi6421-pmic; reg 0x6b; regulators { ldo1: ldo1 { regulator-name hi6421_ldo1; regulator-min-microvolt 1800000; regulator-max-microvolt 3000000; regulator-always-on; regulator-boot-on; }; buck2: buck2 { regulator-name hi6421_buck2; regulator-min-microvolt 800000; regulator-max-microvolt 1500000; }; }; }; };参数说明hi64216b的reg 0x6b是芯片在 I2C 总线上的从机地址这个地址必须与 PDF 里的I2C address一致否则驱动probe时i2c_client根本无法匹配到设备。regulator-min-microvolt和regulator-max-microvolt是内核 regulator 框架用来约束电压范围的值不能超过驱动内部电压表的区间否则驱动会直接返回-EINVAL。regulator-always-on和regulator-boot-on是两个经常被误解的属性。前者表示设备树节点对应的 regulator 在系统运行期间不允许被关闭即使没有驱动持有它后者表示在启动阶段就要把电压输出拉起来多用于 DDR 或核心供电这类必须先上电的设备。实际调试中如果某个外设的供电在系统起来后被莫名其妙关掉优先检查设备树是否少写regulator-always-on。4. 编译、加载与 probe 顺序的三类典型问题4.1 编译报错不是代码问题先查 API 版本差异hi6421-pmic-core的源码如果来自较老的分支在新内核上编译时最常撞见的问题就是regulator_desc结构体中.ops指向的函数实现不满足新框架的声明。比如旧版内核的.is_enabled回调返回int但新内核要求bool。这类编译错误信息明确但如果你不熟悉两个版本的差异容易被后面十几行其他报错带偏。# 编译时重点捕获的类型错误示例 make ARCHarm CROSS_COMPILEarm-linux-gnueabihf- zImage # 常见报错initializer element is not constant # 或assignment of read-only member ops遇到这类问题我的做法是直接切到本内核版本的include/linux/regulator/driver.h对比结构体字段差异然后调整驱动代码而不是反向修改头文件。同时要检查hi6421_pmic-core里是否有自己的regulator.h副本有的 BSP 包为了兼容性会在源码头文件里塞一份旧版头文件这会跟内核头文件冲突导致KERNEL_VERSION宏判断逻辑吃不到正确分支。4.2 probe 失败时从 i2c 探测阶段开始确认链路probe失败不一定是驱动本身的问题。hi6421的驱动通过 I2C 访问芯片如果 I2C 控制器没有正确初始化或总线时序不对probe会在第一次regmap_read时返回-EREMOTEIO。此时驱动会释放资源并报probe failed但日志里真正的根因在i2c子系统的错误信息中。# 内核启动日志重点过滤词 dmesg | grep -E hi6421|regulator|i2c|regmap # 列出 I2C 总线上实际探测到的设备 i2cdetect -y 0 # 在设备树禁用主节点后手动读取芯片 ID 寄存器 i2cget -f -y 0 0x6b 0x00i2cdetect返回6b代表地址 7 位上出现了设备的 ACK这可以快速验证芯片是否活着。如果i2cdetect探测不到先看 I2C 控制器是否已被设备树正确使能再看上拉电阻是否焊接。hi6421的 I2C 速率一般不要超过 400KHz部分开发板为了兼容其他外设把 I2C 配成 1MHz芯片可能因为时序不满足拒绝响应这时需要在i2c_dev节点用clock-frequency属性限速。4.3 启动时序boot-on 与 always-on 的叠加效果PMIC 驱动与普通驱动不同它在系统启动早期就需要被加载因为 DDR、CPU 内核、PLL 这些关键模块都需要电压供给。设备树里同时写regulator-boot-on和regulator-always-on的节点会在内核regulator_init_complete阶段强制执行一次开/关检查。如果probe时驱动已经把电压输出拉高但boot-on没有设置regulator框架可能在late_initcall阶段把不需要的电压关掉导致系统随机挂死。# 查看运行时 regulator 状态确认电压输出 cat /sys/kernel/debug/regulator/regulator_summary # 单路强制开/关的调试入口 echo 1 /sys/class/regulator/regulator.4/force_enable调试阶段regulator_summary的输出是所有电压轨状态的第一手资料会直接显示每个 regulator 的use_count、open_count、电压当前值和上下限。如果发现某一路电压在系统启动一分钟后突然变成 0去查regulator的消费者列表多半是某个驱动在remove时释放了电压。force_enable是一个临时的调试手段不推荐在正式代码里使用它会让框架的引用计数失效。5. 电压输出与下电时序的进阶调试技巧5.1 用查找表对齐 PDF 里的电压步进值hi6421的数据手册里LDO 和 BUCK 的电压表通常是一张寄存器值到电压值的映射表寄存器每增加 1电压增量可能是 50mV、100mV 或无明显规律。线性计算只适用于部分 LDOBUCK 则通常分多个区段每个区段的步进不同。驱动代码里出现大块static const int voltage_table[]数组就是芯片规格的直接翻译。// BUCK 电压表的分段示例结构 static const struct regulator_linear_range hi6421_buck_voltage_ranges[] { REGULATOR_LINEAR_RANGE(800000, 0x0, 0x1F, 10000), // 800mV 起每步 10mV REGULATOR_LINEAR_RANGE(1100000, 0x20, 0x5F, 20000), // 1.1V 起每步 20mV REGULATOR_LINEAR_RANGE(1900000, 0x60, 0x7F, 30000), // 1.9V 起每步 30mV };参数说明这个数组里的三个字段分别是min_uV、min_sel、max_sel、step_uV。使用regulator_linear_range的好处是驱动不需要自己实现换算逻辑框架会自动根据你填的selector计算出电压值。但要注意min_sel对应的电压800000微伏必须与 PDF 的寄存器0x0一致如果 PDF 表格里0x0是禁用状态那这个写法就完全不对。5.2 用 sysfs 和 regulator events 定位驱动异常驱动运行中的调压失败通常表现为请求电压后实际输出不变或者输出跳变到异常值。regulator子系统的events机制可以在电压越界时给消费者发送通知但首先得在驱动里实现error_notifier回调并处理REGULATOR_EVENT_UNDER_VOLTAGE等事件。# 手动请求调整某路电压观察内核事件 sudo su -c echo 1800000 /sys/class/regulator/regulator.5/microvolts dmesg | tail -20 # 如果事件通知未触发确认驱动是否实现了 notifier cat /sys/kernel/debug/regulator/regulator.5/notifier调压后如果出现系统重启或外设工作异常先看dmesg里有没有under voltage的关键字。有些 PMIC 的过压/欠压保护是硬件自动触发的驱动层面根本感知不到表现出来就是系统瞬间断电。遇到这种情况需要回到 PDF 确认BUCK_SR寄存器里的OVP和UVP阈值是否被驱动默认值改掉了。5.3 下电时序的 debounce 参数验证方法多路 PMIC 输出在系统关机时会有严格的先后顺序通常是先关大电流的 BUCK再关 LDO间隔几毫秒。驱动里的.disable回调如果只是简单地写寄存器那时序全部由外部信号或硬件控制。如果在驱动里的.disable回调中加入了gpiod_set_value来控制使能脚务必在实现前后增加延时来满足芯片手册上的t_off要求。// 带时延的下电控制示例 static int hi6421_buck_disable(struct regulator_dev *rdev) { struct hi6421_regulator *info rdev_get_drvdata(rdev); regmap_update_bits(info-regmap, HI6421_EN_REG, info-enable_mask, 0); // 手动增加延时等待 BUCK 完全关闭 usleep_range(2000, 2500); return 0; }这里的2000到2500微秒不是凭空填的需要从 PDF 的开关时序章节里查t_off_min和t_off_max。延时长了会拖慢系统关机的总时间延时短了下一路电压启动时前面的 BUCK 还没放电完毕可能造成电流倒灌。用usleep_range而不是udelay是因为驱动上下文可以睡眠并且给调度器留出合并唤醒的余量。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门