电源管理节点语法:设备树电源管理节点基本语法、regulator节点、power-domain节点

好,咱们今天聊聊设备树里电源管理节点的语法。说实话,这部分内容在刚接触设备树时容易让人头大——各种属性、各种绑定,稍不留神就写错了。我刚开始做电源管理时,就因为在regulator节点里少写了一个regulator-min-microvolt,结果板子死活起不来。嗯,从那以后我就养成了仔细核对语法的习惯。

电源管理节点基本语法

设备树里的电源管理节点,说白了就是告诉内核:我这板子上有哪些电源设备、它们怎么控制、电压电流范围是多少。每个电源设备都是一个独立的节点,挂在对应的总线上。

基本结构长这样:

/ {
    regulators {
        compatible = "simple-bus";
        #address-cells = <1>;
        #size-cells = <0>;

        my_regulator: my-regulator {
            compatible = "regulator-fixed";
            regulator-name = "my-fixed-supply";
            regulator-min-microvolt = <3300000>;
            regulator-max-microvolt = <3300000>;
            gpio = <&gpio1 16 GPIO_ACTIVE_HIGH>;
            enable-active-high;
            regulator-boot-on;
        };
    };
};

这里有几个关键点:

  • compatible:匹配驱动用的,比如regulator-fixed对应固定电压 regulator
  • regulator-name:给这个电源起个名字,调试时有用
  • regulator-min/max-microvolt:电压范围,单位是微伏
  • gpio:控制使能的 GPIO 引脚
  • enable-active-high:高电平使能,反之用enable-active-low
  • regulator-boot-on:内核启动时就打开这个 regulator
我的小技巧: 我个人习惯把所有的 regulator 节点放在一个叫 regulators 的子节点里,compatible 用 simple-bus。这样结构清晰,也方便后续维护。

regulator节点详解

regulator 节点是电源管理的核心。它不只是描述一个电源,还描述了电源之间的依赖关系。你想想看,一个 SoC 可能有几十路供电,有些必须先上电,有些可以后上电,这些都得在设备树里说清楚。

来看一个更复杂的例子——可调电压 regulator:

vcc_core: vcc-core {
    compatible = "regulator-gpio";
    regulator-name = "vcc_core";
    regulator-min-microvolt = <900000>;
    regulator-max-microvolt = <1300000>;
    regulator-boot-on;
    regulator-always-on;

    gpios = <&gpio2 5 GPIO_ACTIVE_HIGH>,
            <&gpio2 6 GPIO_ACTIVE_HIGH>;
    gpios-states = <1 1>;
    states = <900000 0x0>,
             <1100000 0x1>,
             <1200000 0x2>,
             <1300000 0x3>;
};

这里多了几个属性:

  • gpios-states:GPIO 的初始状态
  • states:电压值与 GPIO 状态的映射表。比如 <900000 0x0> 表示 GPIO 输出 0b00 时输出 0.9V
  • regulator-always-on:永远不关闭,常用于核心供电
注意: 我曾经在项目中遇到过一个问题——regulator 的 states 表写错了顺序,导致电压切换时瞬间过压,烧坏了好几块板子。所以,states 里的 GPIO 状态值一定要和硬件设计一一对应,千万别想当然。

regulator 节点还有一个重要的概念——消费者。设备节点通过 *-supply 属性引用 regulator:

&mmc0 {
    vmmc-supply = <&vcc_sd>;
    vqmmc-supply = <&vcc_sd_io>;
};

这里的 vmmc-supplyvqmmc-supply 就是消费者属性。内核会根据这些属性自动管理 regulator 的开关和电压。

power-domain节点

power-domain(电源域)是比 regulator 更高层次的抽象。一个 power-domain 可能包含多个 regulator、时钟、甚至其他 power-domain。它的作用是把一组相关的电源资源打包管理,实现整体开关。

我举个例子:一个 GPU 模块,它需要核心电压、内存电压、还有一组时钟。如果每个都单独控制,代码会变得很复杂。用 power-domain 就可以统一管理。

基本语法如下:

power-domains {
    pd_gpu: power-domain@0 {
        compatible = "ti,sci-power-domain";
        #power-domain-cells = <0>;
        ti,sci-dev-id = <123>;
        ti,sci-rm-range-gp = <0x1>;
        domain-id = <0>;
        label = "gpu_pd";
    };
};

设备节点引用 power-domain:

&gpu {
    power-domains = <&pd_gpu>;
    clocks = <&clk_gpu_core>, <&clk_gpu_mem>;
};

这里 power-domains 属性指向了 pd_gpu 节点。内核在操作 GPU 设备时,会自动先打开对应的 power-domain。

核心要点: power-domain 可以嵌套。比如一个 SoC 有 PD_TOP 包含 PD_GPUPD_DSP。关闭 PD_TOP 时,所有子域都会关闭。这种层级关系在设备树里通过 power-domains 属性引用父域来实现。

来看一个嵌套的例子:

pd_top: power-domain@1 {
    compatible = "generic-power-domain";
    #power-domain-cells = <0>;
    domain-id = <1>;
};

pd_gpu: power-domain@2 {
    compatible = "generic-power-domain";
    #power-domain-cells = <0>;
    power-domains = <&pd_top>;  /* 父域是 PD_TOP */
    domain-id = <2>;
};

这里 pd_gpupower-domains 属性指向了 pd_top,表示它是 PD_TOP 的子域。内核在操作时,会先确保父域已经开启。

知识体系结构图

下面这张图展示了电源管理节点的核心逻辑关系:

设备树电源管理节点知识体系 设备树 (Device Tree) 基本电源节点 Regulator 节点 Power Domain 节点 基本属性 • compatible • status • reg / 地址映射 Regulator 属性 • regulator-*-microvolt • gpio / states • *-supply 消费者 Power Domain 属性 • #power-domain-cells • power-domains (父域) • domain-id / 厂商属性 应用场景 • 固定电压供电 (regulator-fixed) • 动态调压 (regulator-gpio / PWM) • 模块电源域管理 (GPU/ISP/DSP) • 低功耗状态切换 (suspend/resume)

避坑指南与经验总结

做了这么多年电源管理,我踩过不少坑。这里分享几个最常见的:

  • regulator 节点重复定义:同一个 regulator 名字在多个 dts 文件里出现,导致覆盖。我建议用 &节点名 的方式引用修改,不要重新定义整个节点。
  • 电压范围设置过宽:有些新手把 regulator-min-microvolt 设成 0,regulator-max-microvolt 设成很大值。这会导致内核调压时跑到硬件不支持的值。一定要严格按照硬件手册来。
  • power-domain 循环依赖:A 域依赖 B 域,B 域又依赖 A 域。内核在初始化时会死锁。我曾经排查过一个这样的问题,花了整整两天才找到原因。
  • 忘记加 #power-domain-cells:这个属性告诉内核这个 power-domain 需要几个参数。如果漏了,引用它的设备会解析失败。
调试小技巧: 内核启动时加 regulator.disable_early_printk=1debug 参数,可以看到 regulator 的注册和使能过程。如果某个 regulator 没起来,日志里会有明确的错误信息。

嗯,以上就是电源管理节点语法的核心内容。说白了,regulator 管的是具体的电压电流,power-domain 管的是模块级的电源状态。两者配合使用,才能实现精细化的电源管理。写设备树时,多对照硬件原理图,多检查属性值,能省去很多调试时间。


公众号:蓝海资料掘金营,微信deep3321