HI6421 PMIC Linux驱动移植:从手册到设备树的完整实践
发布时间:2026/9/14 2:25:29来源:尧图网络
简介面向嵌入式驱动开发者的Hi6421 PMIC驱动核心源码文件适合需要理解电源管理集成电路软件控制、I2C/SPI通信及低功耗策略的研发场景。资源以RAR压缩包形式提供压缩包内仅含1个C源文件整体大小约1KB属轻量级驱动代码片段便于快速阅读与移植。该源码对应Hi6421电源管理芯片的核心驱动模块通常涵盖设备初始化、电压与电流配置、控制函数、中断处理、故障保护等关键接口结合资源说明可从中学习驱动结构拆分、DVFS动态电压频率调整、休眠与待机低功耗切换、过压欠压过流保护、热管理策略以及驱动与主处理器之间I2C/SPI通信握手的代码实现。代码中的调试信息打印与状态监控逻辑也为后续故障排查和性能优化提供了参考思路。平台显示已有457人学习/下载适合正在调试Hi6421相关硬件、或需要参考PMIC驱动编写方法的开发者快速上手。1. 拿到 hi6421-pmic-core.rar 之后第一件事不是解压在网盘或 BSP 目录里看到 hi6421-pmic-core.rar 这种命名基本可以断定两件事这颗板子的核心电源管理芯片是 HI6421而厂商给的资料不是一个 git 仓库是一份打了日期的快照压缩包。rar 里通常同时放着 HI6421 的数据手册 PDF 和一套叫 pmic-core 的 C 驱动源码前者用来查寄存器后者用来告诉内核怎么操作这些寄存器。很多人拿到包后直接解压、丢进内核、编译报错然后开始怀疑工具链——真正的顺序应该反过来先确认手里的驱动版本和主芯片平台对应哪个内核版本再决定是整目录移植还是只提取关键文件。本文要解决的问题就是让一块只有 HI6421 手册和驱动快照的板子在内核里把 DCDC/LDO 正确注册成标准 regulator 设备并且能用手册反推驱动行为。2. 解压 rar 后先给资料分类pmic-core 到底对应内核哪条链路2.1 在 Linux 下解 rar建议用 unar 而不是 unrarDebian/Ubuntu 默认源里的 unrar 通常放在 non-free 组件里很多机器根本没开这个源。用 bsdtar 也能解 rar但遇到分卷和带注释的包容易解出不完整目录。我一般装 unar它是 The Unarchiver 的命令行版本对 rar 的兼容性比 unrar 更稳解出来的文件名不乱码。sudo apt-get install unar bsdtar p7zip-full unar -o ./hi6421_src hi6421-pmic-core.rar find ./hi6421_src -type f | sort-o指定输出目录建议单独建目录而不是直接在当前目录散开。find 列完文件后先不要急着打开源码按扩展名和文件大小把内容分成几类。rar 里常见的不只是驱动源码还可能有原理图局部截图、参考 DTS、寄存器手册、BSP patch这几类东西的调试用途完全不同。2.2 包内文件对照PDF 手册、C 源码与 BSP patch 各看什么pmic-core 这个名字不是 Linux mainline 的标准目录名它是厂商 BSP 自己组织的目录实际对应内核里drivers/mfd、drivers/regulator、drivers/rtc这几个子系统的工作总和。把包内文件对照成下面这张表后面排查问题时会快很多。文件类型常见命名调试时的用途数据手册 PDFHI6421_datasheet_*.pdfI2C 地址、寄存器偏移、电压范围、复位时序驱动源码pmic-core.c / *.h寄存器宏定义、bank 切换、初始化顺序BSP patch*.patch判断该驱动原本基于哪个内核版本DTS 示例*.dts / *.dtsi节点属性、regulator 命名、中断号如果包里有 patch 文件先看 patch header 里的diff --git a/drivers/...路径和上下文行号这能直接告诉你厂商当初对应的内核版本。你本地内核和它差距超过两个大版本时git apply大概率失败不要硬打手动把 hunk 搬过去更可控。源码里的宏定义要以你手里的手册为准不同批次芯片可能改了 bit 定义drivers 目录里的注释经常比芯片还老。2.3 pdftotext 把 PDF 变成可检索文本先抓寄存器模型HI6421 手册里最该先查的不是每个寄存器细节而是“寄存器访问模型”。这类 PMIC 常把寄存器按功能拆成多个 bank访问某个 bank 内的寄存器前需要先写 bank select 寄存器否则读到的不是你想要的地址。这句话决定了后面驱动里 regmap 怎么封装。pdftotext -layout HI6421_datasheet.pdf HI6421.txt grep -n -i bank\|i2c address\|DCDC1 HI6421.txt | head -60 pdfimages -png HI6421_datasheet.pdf pagepdftotext是 poppler-utils 自带的命令-layout保留版面结构方便按行 grep。部分扫描版手册转出来是乱码用pdfimages把页面导成图片再翻。抓完文本后重点确认四件事I2C 7 位设备地址、bank 切换的寄存器地址和取值、DCDC/LDO 各自的电压范围和步进、中断状态寄存器是读清除还是写清除。这四件事直接决定驱动能不能 probe 成功以及 regulator 调压时会不会把中断状态踩掉。另外读手册寄存器表时注意区分“整字节写”和“改位”。很多 DCDC 使能位和电压档位在同一个寄存器驱动里要准备一份 8 位掩码表用regmap_update_bits而不是regmap_write。直接覆盖整字节会顺手关掉相邻通道这类问题在双 DCDC 同时调压时特别容易复现。3. 把 hi6421 驱动读成寄存器操作序列regmap、bank 与 mfd_cell3.1 先想清楚pmic 驱动在内核里不是“一个驱动”而是一组子设备把 PMIC 驱动当成一个 i2c_driver 来写是很多新手移植 BSP 时最大的误解。HI6421 在设备树里是 I2C 子节点但内核里实际工作的是两三层驱动I2C 层负责 probe 和 regmap 初始化MFD 层负责把芯片拆成 regulator、RTC、watchdog 等子设备子设备再由各自的 platform_driver 继续 probe。内核目录驱动职责probe 失败的常见表现drivers/mfdI2C 访问、bank 切换、子设备注册i2c transfer error: -6drivers/regulatorDCDC/LDO 电压和开关控制regulator: probe deferraldrivers/rtcRTC 读写、闹钟中断rtc-hi6421: probe failed调试时先看 dmesg 里是哪一层失败。-6是 ENXIO说明 I2C 地址不对或芯片没应答-EPROBE_DEFER说明 regulator 父设备还没就绪不一定是驱动写错了。看到 deferral 先查设备树里父节点有没有status okay以及 I2C 控制器本身的时钟有没有配好。3.2 最小 regmap 骨架与 bank 切换HI6421 驱动里最常见的自定义逻辑就是 bank 切换。手册里如果出现BANK_EN、BANK_SEL这类寄存器驱动就不能直接拿 regmap 的默认读写函数需要把 bank 切换动作包进自定义的 read/write 回调里。static const struct regmap_config hi6421_regmap_cfg { .reg_bits 8, .val_bits 8, .reg_read hi6421_reg_read, .reg_write hi6421_reg_write, .max_register HI6421_REG_MAX, /* 以手册寄存器表最高偏移为准 */ }; static int hi6421_reg_read(void *ctx, unsigned int reg, unsigned int *val) { struct hi6421 *chip ctx; int ret; /* 手册要求访问 bank1 前先写 bank select */ if (reg HI6421_BANK1_START) { ret regmap_write(chip-regmap, HI6421_BANK_SEL, HI6421_BANK1); if (ret) return ret; } return regmap_read(chip-regmap, reg, val); }reg_bits 8表示寄存器地址是 8 位宽val_bits 8表示寄存器数据也是 8 位这是大多数 PMIC 的 I2C 寄存器模型。max_register 不要想当然填 0xFF以手册里寄存器地址最大值加 1 为准填大了 regmap 的 debugfs 读取会越界填小了高地址寄存器直接返回错误。自定义 read/write 函数的好处是上层regmap_update_bits完全感知不到 bank 的存在调压代码不需要关心当前在哪一组。调试 bank 相关问题时打开 regmap 的 cache 会让问题更难定位。可以先在驱动 probe 阶段调用regmap_cache_only(chip-regmap, false)关闭 cache确认读写路径正常后再打开。3.3 用 mfd_cell 拆分 regulator、rtc、watchdogMFD 拆分的方式是把每个子设备定义成一个 mfd_cellprobe 时一次性注册。注意子设备的名称不是随意起的它要能和 drivers/regulator 下的平台驱动名称对上。static const struct mfd_cell hi6421_devs[] { { .name hi6421-regulator, .of_compatible hisilicon,hi6421-regulator, }, { .name hi6421-rtc, .of_compatible hisilicon,hi6421-rtc, }, }; static int hi6421_i2c_probe(struct i2c_client *i2c) { struct hi6421 *chip; chip devm_kzalloc(i2c-dev, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; chip-regmap devm_regmap_init_i2c(i2c, hi6421_regmap_cfg); if (IS_ERR(chip-regmap)) return PTR_ERR(chip-regmap); return devm_mfd_add_devices(i2c-dev, PLATFORM_DEVID_NONE, hi6421_devs, ARRAY_SIZE(hi6421_devs), NULL, 0, NULL); }devm_mfd_add_devices会为每个 cell 创建 platform deviceof_compatible让子驱动能从设备树里找到自己的节点。一个常见错误是设备树里写了 regulator 子节点但of_compatible写错了字符串导致 regulator 驱动 probe 时找不到节点返回-ENODEV。这个字符串和 DTS 里regulators节点下的 compatible 必须完全一致。4. 设备树里把 hi6421 的 DCDC/LDO 变成 regulator 节点4.1 i2c 子节点reg 地址到底是 7 位还是 8 位HI6421 在设备树里挂在某个 I2C 控制器下reg属性写的是 7 位 I2C 地址。手册里经常给的是 8 位读写地址比如读地址 0xC3、写地址 0xC2转成 7 位就是右移一位得到 0x61。直接把 0xC2 填进reg内核会认为设备地址是 0x184I2C 控制器根本发不出这个地址。i2c2 { clock-frequency 400000; hi6421: pmic61 { compatible hisilicon,hi6421; reg 0x61; #address-cells 1; #size-cells 0; regulators { compatible hisilicon,hi6421-regulators; dcdc1: dcdc1 { regulator-name vdd_core; regulator-min-microvolt 800000; regulator-max-microvolt 1500000; regulator-boot-on; }; ldo1: ldo1 { regulator-name vdd_io; regulator-min-microvolt 1800000; regulator-max-microvolt 3300000; }; }; }; };clock-frequency建议先按手册允许的最高值配HI6421 这类 PMIC 通常支持 400kHz。如果 I2C 总线还挂了 EEPROM 之类设备降到 100kHz 更稳但 regulator 调压延迟会变大。regulators节点本身没有reg属性它的作用只是给 regulator 驱动一个挂载点真正的匹配靠 compatible。4.2 电压范围、ramp-delay、boot-on 的参数取舍设备树里 regulator 节点的属性决定了内核能对这个电源轨做什么最常见的五个属性按调试优先级排如下。属性作用数据来源regulator-min-microvolt / max-microvolt电压范围手册 DCDC/LDO 章节regulator-boot-on继承 bootloader 状态uboot 配置、原理图regulator-always-on禁止内核关闭该轨不能下电的域regulator-ramp-delay电压切换速率手册上升时间换算regulator-soft-start软启动大电容负载时建议开启ramp-delay 单位是 uV/us手册给的是“上升时间 100us/V”时换算方式为1V 除以 100us 得到 0.01V/us也就是 10000uV/us所以regulator-ramp-delay 10000。这个值配小了内核调压时会认为电压早就到位实际还在爬升导致外设提前上电配大了调压请求会被内核判定超时。regulator-boot-on和regulator-always-on是两回事。boot-on 表示 uboot 已经打开了这个轨内核 probe 时不要先关再开always-on 表示这个轨任何情况下都不能关。CPU 核心电压轨千万不要加 always-on否则系统 suspend 时没法下电。4.3 把原理图通道对应到 regulator_name不同板子上的 HI6421 通道用途差异很大不能照抄参考设计的 DTS。拿到原理图后把每个 DCDC/LDO 输出端的网络标号和负载芯片找出来再回来填regulator-name。DTS 节点参考设计常见用途调试要点dcdc1内核 VCC电流最大boot-on注意核电压不能过冲dcdc2DDR 电源与 DDR init 时序强相关ramp-delay 要准ldo1IO / PHY 供电不能随意欠压看负载瞬态响应ldo2PLL / 模拟域噪声敏感优先检查纹波regulator-name是调试时在/sys/kernel/debug/regulator/下看到的目录名起成和原理图网络标号一致的名字能省掉大量后续沟通成本。名字里不要带空格不要超过 30 个字符否则 sysfs 路径会出问题。5. 运行时验证 hi6421debugfs、tracepoint 与 i2ctransfer 三件套5.1 regulator debugfs先看状态别急着改 DTS驱动 probe 成功后先挂上 debugfs 看 regulator 的实时状态而不是直接改 DTS 参数重启。debugfs 里能看到每个 regulator 的 use_count、电压、状态和消费者列表。mount -t debugfs none /sys/kernel/debug ls /sys/kernel/debug/regulator/ cat /sys/kernel/debug/regulator/vdd_core/status cat /sys/kernel/debug/regulator/vdd_core/consumersstatus文件输出当前电压和 enabled/disabled 状态。consumers文件列出谁在使用这个轨每行有 consumer 名称、请求电压、use_count。如果 use_count 是 0 但电压正常说明是 boot-on 在撑着如果 use_count 大于 0 但实际电压不是请求值优先怀疑 ramp-delay 和负载能力而不是驱动逻辑。5.2 tracepoint 抓电压切换顺序调试电源上电时序时靠 dmesg 里零散的日志不够用内核 regulator tracepoint 可以抓到每次 set_voltage 的调用者和先后顺序。cd /sys/kernel/debug/tracing echo 1 events/regulator/regulator_set_voltage/enable echo 1 events/regulator/regulator_enable/enable cat trace | grep vdd_coretracepoint 输出包含设备名称、old_uv、new_uv 和调用者函数名。在系统启动时抓一段能看到 DCDC1 和 DDR 轨的启动顺序是否符合主芯片的 power sequence 要求。如果 DCDC1 还没起来、DDR 轨就开始调压说明 DTS 里 regulator 节点的 probe 顺序有问题可以在 regulator 子节点里加regulator-initial-mode或者调整父节点的regulators子节点顺序。5.3 i2ctransfer 直接读寄存器验证驱动写入是否到达芯片驱动内部的 regmap 操作可能被 cache、错误处理或休眠逻辑干扰最直接的验证方式是绕过内核直接用 i2c-tools 操作 I2C 总线。i2cdetect -y 2 i2ctransfer -y 2 w10x61 0x00 r1 i2ctransfer -y 2 w20x61 0x00 0x01i2cdetect -y 2扫描 I2C2 总线上的设备确认 0x61 地址有应答。第一条i2ctransfer读寄存器 0x00w10x61表示向 0x61 发一个字节寄存器地址 0x00r1表示随后读一个字节。第二条i2ctransfer写寄存器 0x00 为 0x01w2表示一次写两个字节0x00 是寄存器地址0x01 是数据。读回的值如果和手册 Reset value 对不上先不要判定驱动有问题。对照手册确认这个寄存器是否属于某个 bank如果是需要先写 bank select 寄存器再读。直接用 i2ctransfer 改 DCDC 电压时要格外小心确认当前电压是内核设置的还是 bootloader 设置的改完立刻用万用表量一下输出防止电压过高烧毁负载芯片。6. 最后两个 hi6421 排查技巧寄存器快照与写不进判定6.1 复位后先抓全寄存器快照每次拿到新板子先在上电后、任何驱动加载前把 HI6421 的全部寄存器读一遍存成文件。这块芯片寄存器地址空间不大用 i2ctransfer 循环读一遍开销很低。for i in $(seq 0 0x5F); do printf reg 0x%02x: $i i2ctransfer -y 2 w10x61 $i r1 done | tee hi6421_snapshot.txt这份快照是后续排查的基线。驱动跑飞、电压异常、系统 suspend/resume 失败后再抓一份对比能快速看出哪些位被意外改写。对比时重点看 enable 位、电压档位位、中断状态位很多时候排查半天的问题一对比快照就发现是某个驱动在 shutdown 路径里把寄存器清掉了。6.2 一次 I2C 写失败的判定顺序遇到“寄存器写不进”的情况按下面的顺序排查不要上来就改驱动。先用i2cdetect确认芯片有应答没应答先查 I2C 上拉电阻和片选。在驱动里临时关掉 regmap cache排除 cache 命中导致的假写。检查目标寄存器是否在其他 bank先写 bank select 再操作。查复位引脚电平HI6421 的复位脚一直被拉低时所有寄存器写操作都不会生效。示波器抓 I2C SCL/SDA确认主机发出地址后芯片是否回了 ACK。第 4 条最容易忽略。很多 PMIC 的复位脚是开漏输出外部要接上拉电阻到正确的电压域如果上拉电阻没焊芯片一直处于复位状态I2C 读出来的数据全是 0xFF 或者偶发正确。排除完这一圈再回头看驱动代码通常问题就落在 bank 切换和中断状态寄存器清位上。下次再看到一套 pmic-core 源码先找这三个文件regmap 配置、bank 切换函数、regulator_desc 里的电压表。读完这三个文件这颗芯片的脾气就摸清了一大半。本文还有配套的精品资源点击获取
网站建设高端定制企业官网