Просмотр исходного кода

[drivers][power] add CLI helpers and current control support#11301

- add msh commands to inspect/operate power supplies and regulators
- expose snapshot/name helpers so shells and daemons can enumerate nodes safely
- add current support for regulator
- relax DM-only constraints in power/regulator stacks so basic builds work without DM/OFW
- solve the problem of enabling counting for regulator
Evlers 5 дней назад
Родитель
Сommit
8be4b05af6

+ 5 - 0
components/drivers/include/drivers/power_supply.h

@@ -6,6 +6,7 @@
  * Change Logs:
  * Date           Author       Notes
  * 2022-11-21     GuEe-GUI     first version
+ * 2026-03-27     Evlers       add snapshot helpers and public name getter
  */
 
 #ifndef __POWER_SUPPLY_H__
@@ -274,4 +275,8 @@ void rt_power_supply_changed(struct rt_power_supply *psy);
 struct rt_power_supply *rt_power_supply_get(struct rt_device *dev, const char *id);
 void rt_power_supply_put(struct rt_power_supply *psy);
 
+const char *rt_power_supply_name(struct rt_power_supply *psy);
+struct rt_power_supply **rt_power_supply_snapshot(rt_size_t *count);
+void rt_power_supply_snapshot_free(struct rt_power_supply **nodes, rt_size_t count);
+
 #endif /* __POWER_SUPPLY_H__ */

+ 30 - 0
components/drivers/include/drivers/regulator.h

@@ -6,6 +6,7 @@
  * Change Logs:
  * Date           Author       Notes
  * 2023-09-23     GuEe-GUI     first version
+ * 2026-03-27     Evlers       add current control API and snapshot helpers
  */
 
 #ifndef __REGULATOR_H__
@@ -18,6 +19,7 @@
 #include <drivers/misc.h>
 
 #define RT_REGULATOR_UVOLT_INVALID  (((int)(RT_UINT32_MAX >> 1)))
+#define RT_REGULATOR_UAMP_INVALID   (((int)(RT_UINT32_MAX >> 1)))
 
 struct rt_regulator_param
 {
@@ -86,6 +88,8 @@ struct rt_regulator_ops
     rt_bool_t   (*is_enabled)(struct rt_regulator_node *reg);
     rt_err_t    (*set_voltage)(struct rt_regulator_node *reg, int min_uvolt, int max_uvolt);
     int         (*get_voltage)(struct rt_regulator_node *reg);
+    rt_err_t    (*set_current)(struct rt_regulator_node *reg, int min_uamp, int max_uamp);
+    int         (*get_current)(struct rt_regulator_node *reg);
     rt_err_t    (*set_mode)(struct rt_regulator_node *reg, rt_uint32_t mode);
     rt_int32_t  (*get_mode)(struct rt_regulator_node *reg);
     rt_err_t    (*set_ramp_delay)(struct rt_regulator_node *reg, int ramp);
@@ -98,6 +102,8 @@ struct rt_regulator_notifier;
 #define RT_REGULATOR_MSG_DISABLE            RT_BIT(1)
 #define RT_REGULATOR_MSG_VOLTAGE_CHANGE     RT_BIT(2)
 #define RT_REGULATOR_MSG_VOLTAGE_CHANGE_ERR RT_BIT(3)
+#define RT_REGULATOR_MSG_CURRENT_CHANGE     RT_BIT(4)
+#define RT_REGULATOR_MSG_CURRENT_CHANGE_ERR RT_BIT(5)
 
 union rt_regulator_notifier_args
 {
@@ -107,6 +113,12 @@ union rt_regulator_notifier_args
         int min_uvolt;
         int max_uvolt;
     };
+    struct
+    {
+        int old_uamp;
+        int min_uamp;
+        int max_uamp;
+    };
 };
 
 typedef rt_err_t (*rt_regulator_notifier_callback)(struct rt_regulator_notifier *notifier,
@@ -140,9 +152,16 @@ rt_bool_t rt_regulator_is_supported_voltage(struct rt_regulator *reg, int min_uv
 rt_err_t rt_regulator_set_voltage(struct rt_regulator *reg, int min_uvolt, int max_uvolt);
 int rt_regulator_get_voltage(struct rt_regulator *reg);
 
+rt_bool_t rt_regulator_is_supported_current(struct rt_regulator *reg, int min_uamp, int max_uamp);
+rt_err_t rt_regulator_set_current(struct rt_regulator *reg, int min_uamp, int max_uamp);
+int rt_regulator_get_current(struct rt_regulator *reg);
+
 rt_err_t rt_regulator_set_mode(struct rt_regulator *reg, rt_uint32_t mode);
 rt_int32_t rt_regulator_get_mode(struct rt_regulator *reg);
 
+struct rt_regulator_node **rt_regulator_nodes_snapshot(rt_size_t *count);
+void rt_regulator_nodes_snapshot_free(struct rt_regulator_node **nodes, rt_size_t count);
+
 rt_inline rt_err_t rt_regulator_set_voltage_triplet(struct rt_regulator *reg,
         int min_uvolt, int target_uvolt, int max_uvolt)
 {
@@ -154,4 +173,15 @@ rt_inline rt_err_t rt_regulator_set_voltage_triplet(struct rt_regulator *reg,
     return rt_regulator_set_voltage(reg, min_uvolt, max_uvolt);
 }
 
+rt_inline rt_err_t rt_regulator_set_current_triplet(struct rt_regulator *reg,
+        int min_uamp, int target_uamp, int max_uamp)
+{
+    if (!rt_regulator_set_current(reg, target_uamp, max_uamp))
+    {
+        return RT_EOK;
+    }
+
+    return rt_regulator_set_current(reg, min_uamp, max_uamp);
+}
+
 #endif /* __REGULATOR_H__ */

+ 9 - 8
components/drivers/include/rtdevice.h

@@ -7,6 +7,7 @@
  * Date           Author       Notes
  * 2012-01-08     bernard      first version.
  * 2014-07-12     bernard      Add workqueue implementation.
+ * 2026-03-27     Evlers       reorder regulator/power supply headers after DM deps
  */
 
 #ifndef __RT_DEVICE_H__
@@ -118,10 +119,6 @@ extern "C" {
 #endif /* RT_PCI_ENDPOINT */
 #endif /* RT_USING_PCI */
 
-#ifdef RT_USING_REGULATOR
-#include "drivers/regulator.h"
-#endif /* RT_USING_REGULATOR */
-
 #ifdef RT_USING_RESET
 #include "drivers/reset.h"
 #endif /* RT_USING_RESET */
@@ -148,15 +145,19 @@ extern "C" {
 #include "drivers/hwcache.h"
 #endif /* RT_USING_HWCACHE */
 
-#ifdef RT_USING_POWER_SUPPLY
-#include "drivers/power_supply.h"
-#endif /* RT_USING_POWER_SUPPLY */
-
 #ifdef RT_USING_NVMEM
 #include "drivers/nvmem.h"
 #endif /* RT_USING_NVMEM */
 #endif /* RT_USING_DM */
 
+#ifdef RT_USING_REGULATOR
+#include "drivers/regulator.h"
+#endif /* RT_USING_REGULATOR */
+
+#ifdef RT_USING_POWER_SUPPLY
+#include "drivers/power_supply.h"
+#endif /* RT_USING_POWER_SUPPLY */
+
 #ifdef RT_USING_RTC
 #include "drivers/dev_rtc.h"
 #ifdef RT_USING_ALARM

+ 2 - 1
components/drivers/power/supply/Kconfig

@@ -1,6 +1,5 @@
 menuconfig RT_USING_POWER_SUPPLY
     bool "Using Power supply class support"
-    depends on RT_USING_DM
     select RT_USING_ADT
     select RT_USING_ADT_REF
     select RT_USING_SYSTEM_WORKQUEUE
@@ -27,6 +26,8 @@ config RT_POWER_SUPPLY_EMU
 config RT_POWER_SUPPLY_CHARGER_GPIO
     bool "GPIO charger"
     depends on RT_USING_POWER_SUPPLY
+    depends on RT_USING_DM
+    depends on RT_USING_OFW
     depends on RT_USING_PIN
     default y
 

+ 1 - 1
components/drivers/power/supply/SConscript

@@ -8,7 +8,7 @@ if not GetDepend(['RT_USING_POWER_SUPPLY']):
 cwd = GetCurrentDir()
 CPPPATH = [cwd + '/../../include']
 
-src = ['supply.c']
+src = ['supply.c', 'supply_cmd.c']
 
 if GetDepend(['RT_POWER_SUPPLY_DAEMON']):
     src += ['supply-daemon.c']

+ 5 - 0
components/drivers/power/supply/emu-power.c

@@ -6,6 +6,7 @@
  * Change Logs:
  * Date           Author       Notes
  * 2023-02-25     GuEe-GUI     the first version
+ * 2026-03-27     Evlers       allow building without DM by naming parent directly
  */
 
 #include <rtthread.h>
@@ -299,7 +300,11 @@ static int emu_power_init(void)
 
     rt_memset(ep, 0, sizeof(*ep));
 
+#ifdef RT_USING_DM
     rt_dm_dev_set_name(&ep->parent, "emu-power");
+#else
+    ep->parent.parent.name = "emu-power";
+#endif
 
     ep->battery.dev = &ep->parent,
     ep->battery.type = RT_POWER_SUPPLY_TYPE_BATTERY,

+ 6 - 5
components/drivers/power/supply/supply-daemon.c

@@ -6,6 +6,7 @@
  * Change Logs:
  * Date           Author       Notes
  * 2023-02-25     GuEe-GUI     the first version
+ * 2026-03-27     Evlers       support builds without DM names and improve logging
  */
 
 #include <rtdevice.h>
@@ -66,11 +67,11 @@ _capacity_check:
         {
             if (full_power)
             {
-                LOG_I("%s: Power is full", rt_dm_dev_get_name(psy->dev));
+                LOG_I("%s: Power is full", rt_power_supply_name(psy));
             }
             else
             {
-                LOG_I("%s: Power is sufficient", rt_dm_dev_get_name(psy->dev));
+                LOG_I("%s: Power is sufficient", rt_power_supply_name(psy));
             }
         }
     }
@@ -109,12 +110,12 @@ _capacity_check:
                 if (!rt_power_supply_get_property(psy, RT_POWER_SUPPLY_PROP_SCOPE, &propval) &&
                     propval.intval == RT_POWER_SUPPLY_SCOPE_SYSTEM)
                 {
-                    LOG_E("%s: Power is critical, poweroff now", rt_dm_dev_get_name(psy->dev));
+                    LOG_E("%s: Power is critical, poweroff now", rt_power_supply_name(psy));
                     rt_hw_cpu_shutdown();
                 }
             } while (0);
 
-            LOG_E("%s: Power is critical", rt_dm_dev_get_name(psy->dev));
+            LOG_E("%s: Power is critical", rt_power_supply_name(psy));
         }
         else if (propval.intval <= 10)
         {
@@ -136,7 +137,7 @@ _capacity_check:
             pm_sleep_mode = PM_SLEEP_MODE_LIGHT;
             rt_pm_run_enter(PM_RUN_MODE_NORMAL_SPEED);
         #endif
-            LOG_W("%s: Power is low", rt_dm_dev_get_name(psy->dev));
+            LOG_W("%s: Power is low", rt_power_supply_name(psy));
         }
 
     #ifdef RT_USING_PM

+ 69 - 114
components/drivers/power/supply/supply.c

@@ -6,6 +6,7 @@
  * Change Logs:
  * Date           Author       Notes
  * 2023-02-25     GuEe-GUI     the first version
+ * 2026-03-27     Evlers       add CLI snapshot/name helpers and OFW guards
  */
 
 #include <rtdevice.h>
@@ -26,6 +27,17 @@ static RT_DEFINE_SPINLOCK(nodes_lock);
 static rt_list_t power_supply_nodes = RT_LIST_OBJECT_INIT(power_supply_nodes);
 static rt_list_t power_supply_notifier_nodes = RT_LIST_OBJECT_INIT(power_supply_notifier_nodes);
 
+const char *rt_power_supply_name(struct rt_power_supply *psy)
+{
+    struct rt_device *dev = psy ? psy->dev : RT_NULL;
+
+#ifdef RT_USING_DM
+    return rt_dm_dev_get_name(dev);
+#else
+    return dev ? dev->parent.name : "<no-dev>";
+#endif
+}
+
 static rt_bool_t power_supply_have_property(struct rt_power_supply *psy,
         enum rt_power_supply_property prop);
 
@@ -68,10 +80,16 @@ rt_err_t power_supply_thermal_register(struct rt_power_supply *psy)
             return -RT_ENOMEM;
         }
 
+#ifdef RT_USING_DM
         rt_dm_dev_set_name(&psy->thermal_dev->parent, rt_dm_dev_get_name(psy->dev));
+#else
+        psy->thermal_dev->parent.parent.name = rt_power_supply_name(psy);
+#endif
         psy->thermal_dev->zone_id = 0;
         psy->thermal_dev->ops = &power_supply_thermal_zone_ops;
+#ifdef RT_USING_OFW
         psy->thermal_dev->parent.ofw_node = psy->dev->ofw_node;
+#endif
         psy->thermal_dev->priv = psy;
 
         if ((err = rt_thermal_zone_device_register(psy->thermal_dev)))
@@ -229,10 +247,14 @@ rt_err_t rt_power_supply_register(struct rt_power_supply *psy)
     rt_list_insert_before(&power_supply_nodes, &psy->list);
     rt_spin_unlock(&nodes_lock);
 
+#ifdef RT_USING_OFW
     if (psy->dev->ofw_node)
     {
+#ifdef RT_USING_DM
         rt_dm_dev_bind_fwdata(psy->dev, RT_NULL, psy);
+#endif
     }
+#endif
 
     return RT_EOK;
 }
@@ -256,10 +278,14 @@ rt_err_t rt_power_supply_unregister(struct rt_power_supply *psy)
 
     rt_list_remove(&psy->list);
 
+#ifdef RT_USING_OFW
     if (psy->dev->ofw_node)
     {
+#ifdef RT_USING_DM
         rt_dm_dev_unbind_fwdata(psy->dev, RT_NULL);
+#endif
     }
+#endif
 
 _unlock:
     rt_spin_unlock(&nodes_lock);
@@ -562,133 +588,62 @@ void rt_power_supply_put(struct rt_power_supply *psy)
     rt_ref_put(&psy->ref, power_supply_release);
 }
 
-#if defined(RT_USING_CONSOLE) && defined(RT_USING_MSH)
-const char * const type_str[] =
-{
-    [RT_POWER_SUPPLY_TYPE_UNKNOWN] = "UnKnown",
-    [RT_POWER_SUPPLY_TYPE_BATTERY] = "Battery",
-    [RT_POWER_SUPPLY_TYPE_UPS] = "UPS",
-    [RT_POWER_SUPPLY_TYPE_MAINS] = "Mains",
-    [RT_POWER_SUPPLY_TYPE_USB_SDP] = "USB SDP",
-    [RT_POWER_SUPPLY_TYPE_USB_DCP] = "USB DCP",
-    [RT_POWER_SUPPLY_TYPE_USB_CDP] = "USB CDP",
-    [RT_POWER_SUPPLY_TYPE_USB_ACA] = "USB ACA",
-    [RT_POWER_SUPPLY_TYPE_USB_TYPE_C] = "USB TypeC",
-    [RT_POWER_SUPPLY_TYPE_USB_PD] = "USB PD",
-    [RT_POWER_SUPPLY_TYPE_USB_PD_DRP] = "USB PD DRP",
-    [RT_POWER_SUPPLY_TYPE_USB_PD_PPS] = "USB PD PPS",
-    [RT_POWER_SUPPLY_TYPE_WIRELESS] = "Wireless",
-};
-
-const char * const status_str[] =
-{
-    [RT_POWER_SUPPLY_STATUS_UNKNOWN] = "UnKnown",
-    [RT_POWER_SUPPLY_STATUS_CHARGING] = "Charging",
-    [RT_POWER_SUPPLY_STATUS_DISCHARGING] = "Discharging",
-    [RT_POWER_SUPPLY_STATUS_NOT_CHARGING] = "Not Charging",
-    [RT_POWER_SUPPLY_STATUS_FULL] = "Full",
-};
-
-const char * const charge_type_str[] =
+struct rt_power_supply **rt_power_supply_snapshot(rt_size_t *count)
 {
-    [RT_POWER_SUPPLY_CHARGE_TYPE_UNKNOWN] = "Unknown",
-    [RT_POWER_SUPPLY_CHARGE_TYPE_NONE] = "None",
-    [RT_POWER_SUPPLY_CHARGE_TYPE_TRICKLE] = "Trickle",
-    [RT_POWER_SUPPLY_CHARGE_TYPE_FAST] = "Fast",
-    [RT_POWER_SUPPLY_CHARGE_TYPE_STANDARD] = "Standard",
-    [RT_POWER_SUPPLY_CHARGE_TYPE_ADAPTIVE] = "Adaptive",
-    [RT_POWER_SUPPLY_CHARGE_TYPE_CUSTOM] = "Custom",
-    [RT_POWER_SUPPLY_CHARGE_TYPE_LONGLIFE] = "Longlife",
-    [RT_POWER_SUPPLY_CHARGE_TYPE_BYPASS] = "Bypass",
-};
-
-const char * const health_str[] =
-{
-    [RT_POWER_SUPPLY_HEALTH_UNKNOWN] = "Unknown",
-    [RT_POWER_SUPPLY_HEALTH_GOOD] = "Good",
-    [RT_POWER_SUPPLY_HEALTH_OVERHEAT] = "Overheat",
-    [RT_POWER_SUPPLY_HEALTH_DEAD] = "Dead",
-    [RT_POWER_SUPPLY_HEALTH_OVERVOLTAGE] = "Overvoltage",
-    [RT_POWER_SUPPLY_HEALTH_UNSPEC_FAILURE] = "Unspec Failure",
-    [RT_POWER_SUPPLY_HEALTH_COLD] = "Cold",
-    [RT_POWER_SUPPLY_HEALTH_WATCHDOG_TIMER_EXPIRE] = "Watchdog Timer Expire",
-    [RT_POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE] = "Safety Timer Expire",
-    [RT_POWER_SUPPLY_HEALTH_OVERCURRENT] = "Overcurrent",
-    [RT_POWER_SUPPLY_HEALTH_CALIBRATION_REQUIRED] = "Calibration Required",
-    [RT_POWER_SUPPLY_HEALTH_WARM] = "Warm",
-    [RT_POWER_SUPPLY_HEALTH_COOL] = "Cool",
-    [RT_POWER_SUPPLY_HEALTH_HOT] = "Hot",
-    [RT_POWER_SUPPLY_HEALTH_NO_BATTERY] = "No Battery",
-};
+    struct rt_power_supply *psy, *psy_next;
+    struct rt_power_supply **nodes;
+    rt_size_t total = 0;
+    rt_size_t idx = 0;
 
-const char * const tech_str[] =
-{
-    [RT_POWER_SUPPLY_TECHNOLOGY_UNKNOWN] = "UnKnown",
-    [RT_POWER_SUPPLY_TECHNOLOGY_NiMH] = "NiMH",
-    [RT_POWER_SUPPLY_TECHNOLOGY_LION] = "LION",
-    [RT_POWER_SUPPLY_TECHNOLOGY_LIPO] = "LIPO",
-    [RT_POWER_SUPPLY_TECHNOLOGY_LiFe] = "LiFe",
-    [RT_POWER_SUPPLY_TECHNOLOGY_NiCd] = "NiCd",
-    [RT_POWER_SUPPLY_TECHNOLOGY_LiMn] = "LiMn",
-};
+    if (!count)
+    {
+        return RT_NULL;
+    }
 
-static int list_power_supply(int argc, char**argv)
-{
-    struct rt_power_supply *psy, *psy_next;
-    union rt_power_supply_property_val propval = {};
+    *count = 0;
 
     rt_spin_lock(&nodes_lock);
-
     rt_list_for_each_entry_safe(psy, psy_next, &power_supply_nodes, list)
     {
-        rt_spin_unlock(&nodes_lock);
-
-        rt_kprintf("%s %s\n", rt_dm_dev_get_name(psy->dev), type_str[psy->type]);
-
-        rt_power_supply_get_property(psy, RT_POWER_SUPPLY_PROP_STATUS, &propval);
-        rt_kprintf("status: %s\n", status_str[propval.intval]), propval.intval = 0;
+        total++;
+    }
+    rt_spin_unlock(&nodes_lock);
 
-        rt_power_supply_get_property(psy, RT_POWER_SUPPLY_PROP_CHARGE_TYPE, &propval);
-        rt_kprintf("charge type: %s\n", charge_type_str[propval.intval]), propval.intval = 0;
+    if (!total)
+    {
+        return RT_NULL;
+    }
 
-        rt_power_supply_get_property(psy, RT_POWER_SUPPLY_PROP_HEALTH, &propval);
-        rt_kprintf("health: %s\n", health_str[propval.intval]), propval.intval = 0;
+    nodes = rt_calloc(total, sizeof(*nodes));
+    if (!nodes)
+    {
+        return RT_NULL;
+    }
 
-        if (psy->battery_info)
-        {
-            struct rt_power_supply_battery_info *info = psy->battery_info;
-
-            rt_power_supply_get_property(psy, RT_POWER_SUPPLY_PROP_CAPACITY, &propval);
-            rt_kprintf("capacity:                       %d%%\n", propval.intval), propval.intval = 0;
-
-            rt_kprintf("technology:                     %s\n", tech_str[info->technology]);
-            rt_kprintf("energy full design:             %u uWh\n", info->energy_full_design_uwh);
-            rt_kprintf("charge full design:             %u uAh\n", info->charge_full_design_uah);
-            rt_kprintf("voltage design range:           %u~%u uV\n", info->voltage_min_design_uv, info->voltage_max_design_uv);
-            rt_kprintf("precharge current:              %u uA\n", info->precharge_current_ua);
-            rt_kprintf("charge term current:            %u uA\n", info->charge_term_current_ua);
-            rt_kprintf("charge restart voltage:         %u uV\n", info->charge_restart_voltage_uv);
-            rt_kprintf("constant charge current max:    %u uA\n", info->constant_charge_current_max_ua);
-            rt_kprintf("constant charge voltage max:    %u uV\n", info->constant_charge_voltage_max_uv);
-            rt_kprintf("temp ambient alert range:       %+d.%u~%+d.%u C\n",
-                    info->temp_ambient_alert_min / 1000, rt_abs(info->temp_ambient_alert_min) % 1000,
-                    info->temp_ambient_alert_max / 1000, rt_abs(info->temp_ambient_alert_max) % 1000);
-            rt_kprintf("temp alert range:               %+d.%u~%+d.%u C\n",
-                    info->temp_alert_min / 1000, rt_abs(info->temp_alert_min) % 1000,
-                    info->temp_alert_max / 1000, rt_abs(info->temp_alert_max) % 1000);
-            rt_kprintf("temp range:                     %+d.%u~%+d.%u C\n",
-                    info->temp_min / 1000, rt_abs(info->temp_min) % 1000,
-                    info->temp_max / 1000, rt_abs(info->temp_max) % 1000);
-        }
+    rt_spin_lock(&nodes_lock);
+    rt_list_for_each_entry_safe(psy, psy_next, &power_supply_nodes, list)
+    {
+        nodes[idx] = psy;
+        rt_ref_get(&psy->ref);
+        idx++;
+    }
+    rt_spin_unlock(&nodes_lock);
 
-        rt_kputs("\n");
+    *count = total;
+    return nodes;
+}
 
-        rt_spin_lock(&nodes_lock);
+void rt_power_supply_snapshot_free(struct rt_power_supply **nodes, rt_size_t count)
+{
+    if (!nodes)
+    {
+        return;
     }
 
-    rt_spin_unlock(&nodes_lock);
+    while (count--)
+    {
+        rt_ref_put(&nodes[count]->ref, power_supply_release);
+    }
 
-    return 0;
+    rt_free(nodes);
 }
-MSH_CMD_EXPORT(list_power_supply, dump all of power supply information);
-#endif /* RT_USING_CONSOLE && RT_USING_MSH */

+ 401 - 0
components/drivers/power/supply/supply_cmd.c

@@ -0,0 +1,401 @@
+/*
+ * Copyright (c) 2006-2026, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2026-03-27     Evlers       first version
+ */
+
+#include <rtdevice.h>
+
+#if defined(RT_USING_CONSOLE) && defined(RT_USING_MSH)
+
+const char * const type_str[] =
+{
+    [RT_POWER_SUPPLY_TYPE_UNKNOWN] = "UnKnown",
+    [RT_POWER_SUPPLY_TYPE_BATTERY] = "Battery",
+    [RT_POWER_SUPPLY_TYPE_UPS] = "UPS",
+    [RT_POWER_SUPPLY_TYPE_MAINS] = "Mains",
+    [RT_POWER_SUPPLY_TYPE_USB_SDP] = "USB SDP",
+    [RT_POWER_SUPPLY_TYPE_USB_DCP] = "USB DCP",
+    [RT_POWER_SUPPLY_TYPE_USB_CDP] = "USB CDP",
+    [RT_POWER_SUPPLY_TYPE_USB_ACA] = "USB ACA",
+    [RT_POWER_SUPPLY_TYPE_USB_TYPE_C] = "USB TypeC",
+    [RT_POWER_SUPPLY_TYPE_USB_PD] = "USB PD",
+    [RT_POWER_SUPPLY_TYPE_USB_PD_DRP] = "USB PD DRP",
+    [RT_POWER_SUPPLY_TYPE_USB_PD_PPS] = "USB PD PPS",
+    [RT_POWER_SUPPLY_TYPE_WIRELESS] = "Wireless",
+};
+
+const char * const status_str[] =
+{
+    [RT_POWER_SUPPLY_STATUS_UNKNOWN] = "UnKnown",
+    [RT_POWER_SUPPLY_STATUS_CHARGING] = "Charging",
+    [RT_POWER_SUPPLY_STATUS_DISCHARGING] = "Discharging",
+    [RT_POWER_SUPPLY_STATUS_NOT_CHARGING] = "Not Charging",
+    [RT_POWER_SUPPLY_STATUS_FULL] = "Full",
+};
+
+const char * const charge_type_str[] =
+{
+    [RT_POWER_SUPPLY_CHARGE_TYPE_UNKNOWN] = "Unknown",
+    [RT_POWER_SUPPLY_CHARGE_TYPE_NONE] = "None",
+    [RT_POWER_SUPPLY_CHARGE_TYPE_TRICKLE] = "Trickle",
+    [RT_POWER_SUPPLY_CHARGE_TYPE_FAST] = "Fast",
+    [RT_POWER_SUPPLY_CHARGE_TYPE_STANDARD] = "Standard",
+    [RT_POWER_SUPPLY_CHARGE_TYPE_ADAPTIVE] = "Adaptive",
+    [RT_POWER_SUPPLY_CHARGE_TYPE_CUSTOM] = "Custom",
+    [RT_POWER_SUPPLY_CHARGE_TYPE_LONGLIFE] = "Longlife",
+    [RT_POWER_SUPPLY_CHARGE_TYPE_BYPASS] = "Bypass",
+};
+
+const char * const health_str[] =
+{
+    [RT_POWER_SUPPLY_HEALTH_UNKNOWN] = "Unknown",
+    [RT_POWER_SUPPLY_HEALTH_GOOD] = "Good",
+    [RT_POWER_SUPPLY_HEALTH_OVERHEAT] = "Overheat",
+    [RT_POWER_SUPPLY_HEALTH_DEAD] = "Dead",
+    [RT_POWER_SUPPLY_HEALTH_OVERVOLTAGE] = "Overvoltage",
+    [RT_POWER_SUPPLY_HEALTH_UNSPEC_FAILURE] = "Unspec Failure",
+    [RT_POWER_SUPPLY_HEALTH_COLD] = "Cold",
+    [RT_POWER_SUPPLY_HEALTH_WATCHDOG_TIMER_EXPIRE] = "Watchdog Timer Expire",
+    [RT_POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE] = "Safety Timer Expire",
+    [RT_POWER_SUPPLY_HEALTH_OVERCURRENT] = "Overcurrent",
+    [RT_POWER_SUPPLY_HEALTH_CALIBRATION_REQUIRED] = "Calibration Required",
+    [RT_POWER_SUPPLY_HEALTH_WARM] = "Warm",
+    [RT_POWER_SUPPLY_HEALTH_COOL] = "Cool",
+    [RT_POWER_SUPPLY_HEALTH_HOT] = "Hot",
+    [RT_POWER_SUPPLY_HEALTH_NO_BATTERY] = "No Battery",
+};
+
+const char * const tech_str[] =
+{
+    [RT_POWER_SUPPLY_TECHNOLOGY_UNKNOWN] = "UnKnown",
+    [RT_POWER_SUPPLY_TECHNOLOGY_NiMH] = "NiMH",
+    [RT_POWER_SUPPLY_TECHNOLOGY_LION] = "LION",
+    [RT_POWER_SUPPLY_TECHNOLOGY_LIPO] = "LIPO",
+    [RT_POWER_SUPPLY_TECHNOLOGY_LiFe] = "LiFe",
+    [RT_POWER_SUPPLY_TECHNOLOGY_NiCd] = "NiCd",
+    [RT_POWER_SUPPLY_TECHNOLOGY_LiMn] = "LiMn",
+};
+
+const char * const capacity_level_str[] =
+{
+    [RT_POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN] = "Unknown",
+    [RT_POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL] = "Critical",
+    [RT_POWER_SUPPLY_CAPACITY_LEVEL_LOW] = "Low",
+    [RT_POWER_SUPPLY_CAPACITY_LEVEL_NORMAL] = "Normal",
+    [RT_POWER_SUPPLY_CAPACITY_LEVEL_HIGH] = "High",
+    [RT_POWER_SUPPLY_CAPACITY_LEVEL_FULL] = "Full",
+};
+
+const char * const scope_str[] =
+{
+    [RT_POWER_SUPPLY_SCOPE_UNKNOWN] = "Unknown",
+    [RT_POWER_SUPPLY_SCOPE_SYSTEM] = "System",
+    [RT_POWER_SUPPLY_SCOPE_DEVICE] = "Device",
+};
+
+enum power_supply_prop_dump_type
+{
+    POWER_SUPPLY_PROP_DUMP_INT = 0,
+    POWER_SUPPLY_PROP_DUMP_ENUM,
+    POWER_SUPPLY_PROP_DUMP_STR,
+};
+
+struct power_supply_prop_desc
+{
+    enum rt_power_supply_property prop;
+    const char *name;
+    const char *label;
+    const char *unit;
+    enum power_supply_prop_dump_type type;
+    const char * const *str_tab;
+    rt_size_t str_tab_size;
+};
+
+static const struct power_supply_prop_desc g_power_supply_prop_desc[] =
+{
+    {RT_POWER_SUPPLY_PROP_ONLINE,                      "online",                     "online:",                     RT_NULL, POWER_SUPPLY_PROP_DUMP_INT,  RT_NULL, 0},
+    {RT_POWER_SUPPLY_PROP_PRESENT,                     "present",                    "present:",                    RT_NULL, POWER_SUPPLY_PROP_DUMP_INT,  RT_NULL, 0},
+    {RT_POWER_SUPPLY_PROP_AUTHENTIC,                   "authentic",                  "authentic:",                  RT_NULL, POWER_SUPPLY_PROP_DUMP_INT,  RT_NULL, 0},
+    {RT_POWER_SUPPLY_PROP_STATUS,                      "status",                     "status:",                     RT_NULL, POWER_SUPPLY_PROP_DUMP_ENUM, status_str, sizeof(status_str) / sizeof(status_str[0])},
+    {RT_POWER_SUPPLY_PROP_CHARGE_TYPE,                 "charge_type",                "charge type:",                RT_NULL, POWER_SUPPLY_PROP_DUMP_ENUM, charge_type_str, sizeof(charge_type_str) / sizeof(charge_type_str[0])},
+    {RT_POWER_SUPPLY_PROP_HEALTH,                      "health",                     "health:",                     RT_NULL, POWER_SUPPLY_PROP_DUMP_ENUM, health_str, sizeof(health_str) / sizeof(health_str[0])},
+    {RT_POWER_SUPPLY_PROP_SCOPE,                       "scope",                      "scope:",                      RT_NULL, POWER_SUPPLY_PROP_DUMP_ENUM, scope_str, sizeof(scope_str) / sizeof(scope_str[0])},
+    {RT_POWER_SUPPLY_PROP_CAPACITY,                    "capacity",                   "capacity:",                   "%",    POWER_SUPPLY_PROP_DUMP_INT,  RT_NULL, 0},
+    {RT_POWER_SUPPLY_PROP_CAPACITY_LEVEL,              "capacity_level",             "capacity level:",             RT_NULL, POWER_SUPPLY_PROP_DUMP_ENUM, capacity_level_str, sizeof(capacity_level_str) / sizeof(capacity_level_str[0])},
+    {RT_POWER_SUPPLY_PROP_VOLTAGE_NOW,                 "voltage_now",                "voltage now:",                "uV",   POWER_SUPPLY_PROP_DUMP_INT,  RT_NULL, 0},
+    {RT_POWER_SUPPLY_PROP_VOLTAGE_AVG,                 "voltage_avg",                "voltage avg:",                "uV",   POWER_SUPPLY_PROP_DUMP_INT,  RT_NULL, 0},
+    {RT_POWER_SUPPLY_PROP_CURRENT_NOW,                 "current_now",                "current now:",                "uA",   POWER_SUPPLY_PROP_DUMP_INT,  RT_NULL, 0},
+    {RT_POWER_SUPPLY_PROP_CURRENT_AVG,                 "current_avg",                "current avg:",                "uA",   POWER_SUPPLY_PROP_DUMP_INT,  RT_NULL, 0},
+    {RT_POWER_SUPPLY_PROP_POWER_NOW,                   "power_now",                  "power now:",                  "uW",   POWER_SUPPLY_PROP_DUMP_INT,  RT_NULL, 0},
+    {RT_POWER_SUPPLY_PROP_POWER_AVG,                   "power_avg",                  "power avg:",                  "uW",   POWER_SUPPLY_PROP_DUMP_INT,  RT_NULL, 0},
+    {RT_POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT,         "input_voltage_limit",        "input voltage limit:",        "uV",   POWER_SUPPLY_PROP_DUMP_INT,  RT_NULL, 0},
+    {RT_POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,         "input_current_limit",        "input current limit:",        "uA",   POWER_SUPPLY_PROP_DUMP_INT,  RT_NULL, 0},
+    {RT_POWER_SUPPLY_PROP_INPUT_POWER_LIMIT,           "input_power_limit",          "input power limit:",          "uW",   POWER_SUPPLY_PROP_DUMP_INT,  RT_NULL, 0},
+    {RT_POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,     "constant_charge_voltage",    "constant charge voltage:",    "uV",   POWER_SUPPLY_PROP_DUMP_INT,  RT_NULL, 0},
+    {RT_POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, "constant_charge_voltage_max", "constant charge voltage max:", "uV",  POWER_SUPPLY_PROP_DUMP_INT,  RT_NULL, 0},
+    {RT_POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,     "constant_charge_current",    "constant charge current:",    "uA",   POWER_SUPPLY_PROP_DUMP_INT,  RT_NULL, 0},
+    {RT_POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, "constant_charge_current_max", "constant charge current max:", "uA",  POWER_SUPPLY_PROP_DUMP_INT,  RT_NULL, 0},
+    {RT_POWER_SUPPLY_PROP_TEMP,                        "temp",                       "temp:",                       "mC",   POWER_SUPPLY_PROP_DUMP_INT,  RT_NULL, 0},
+    {RT_POWER_SUPPLY_PROP_TEMP_AMBIENT,                "temp_ambient",               "temp ambient:",               "mC",   POWER_SUPPLY_PROP_DUMP_INT,  RT_NULL, 0},
+    {RT_POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,           "time_to_empty_now",          "time to empty now:",          "s",    POWER_SUPPLY_PROP_DUMP_INT,  RT_NULL, 0},
+    {RT_POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,            "time_to_full_now",           "time to full now:",           "s",    POWER_SUPPLY_PROP_DUMP_INT,  RT_NULL, 0},
+    {RT_POWER_SUPPLY_PROP_MODEL_NAME,                  "model_name",                 "model name:",                 RT_NULL, POWER_SUPPLY_PROP_DUMP_STR,  RT_NULL, 0},
+    {RT_POWER_SUPPLY_PROP_MANUFACTURER,                "manufacturer",               "manufacturer:",               RT_NULL, POWER_SUPPLY_PROP_DUMP_STR,  RT_NULL, 0},
+    {RT_POWER_SUPPLY_PROP_SERIAL_NUMBER,               "serial_number",              "serial number:",              RT_NULL, POWER_SUPPLY_PROP_DUMP_STR,  RT_NULL, 0},
+};
+
+#ifdef FINSH_USING_OPTION_COMPLETION
+static struct msh_cmd_opt power_supply_msh_options[] =
+{
+    {0, RT_NULL, RT_NULL},
+};
+#endif
+
+static const struct power_supply_prop_desc *power_supply_find_prop_desc(const char *name)
+{
+    rt_size_t i;
+
+    if (!name)
+    {
+        return RT_NULL;
+    }
+
+    for (i = 0; i < sizeof(g_power_supply_prop_desc) / sizeof(g_power_supply_prop_desc[0]); ++i)
+    {
+        if (!rt_strcmp(g_power_supply_prop_desc[i].name, name))
+        {
+            return &g_power_supply_prop_desc[i];
+        }
+    }
+
+    return RT_NULL;
+}
+
+static struct rt_power_supply *power_supply_find_by_name(const char *name)
+{
+    struct rt_power_supply **nodes;
+    struct rt_power_supply *result = RT_NULL;
+    rt_size_t count = 0;
+    rt_size_t i;
+
+    if (!name)
+    {
+        return RT_NULL;
+    }
+
+    nodes = rt_power_supply_snapshot(&count);
+    if (!nodes)
+    {
+        return RT_NULL;
+    }
+
+    for (i = 0; i < count; ++i)
+    {
+        const char *dev_name = rt_power_supply_name(nodes[i]);
+
+        if (!rt_strcmp(dev_name, name))
+        {
+            result = nodes[i];
+            rt_ref_get(&result->ref);
+            break;
+        }
+    }
+
+    rt_power_supply_snapshot_free(nodes, count);
+    return result;
+}
+
+static rt_err_t power_supply_dump_one_property(struct rt_power_supply *psy,
+        const struct power_supply_prop_desc *desc,
+        rt_bool_t print_unsupported)
+{
+    union rt_power_supply_property_val val = {};
+    rt_err_t err;
+
+    err = rt_power_supply_get_property(psy, desc->prop, &val);
+    if (err != RT_EOK)
+    {
+        if (print_unsupported)
+        {
+            rt_kprintf("%-30s <unsupported>\n", desc->label);
+        }
+        return err;
+    }
+
+    if (desc->type == POWER_SUPPLY_PROP_DUMP_STR)
+    {
+        rt_kprintf("%-30s %s\n", desc->label, val.strval ? val.strval : "<null>");
+        return RT_EOK;
+    }
+
+    if (desc->type == POWER_SUPPLY_PROP_DUMP_ENUM)
+    {
+        if ((val.intval >= 0) && ((rt_size_t)val.intval < desc->str_tab_size) && desc->str_tab[val.intval])
+        {
+            rt_kprintf("%-30s %s\n", desc->label, desc->str_tab[val.intval]);
+        }
+        else
+        {
+            rt_kprintf("%-30s %d\n", desc->label, val.intval);
+        }
+        return RT_EOK;
+    }
+
+    if (desc->unit)
+    {
+        rt_kprintf("%-30s %d %s\n", desc->label, val.intval, desc->unit);
+    }
+    else
+    {
+        rt_kprintf("%-30s %d\n", desc->label, val.intval);
+    }
+
+    return RT_EOK;
+}
+
+static void power_supply_dump_known_property_names(void)
+{
+    rt_size_t i;
+
+    rt_kputs("Known properties:\n");
+
+    for (i = 0; i < sizeof(g_power_supply_prop_desc) / sizeof(g_power_supply_prop_desc[0]); ++i)
+    {
+        rt_kprintf("  %s\n", g_power_supply_prop_desc[i].name);
+    }
+}
+
+static void power_supply_dump_battery_info(struct rt_power_supply *psy)
+{
+    if (psy->battery_info)
+    {
+        struct rt_power_supply_battery_info *info = psy->battery_info;
+
+        rt_kprintf("technology:                     %s\n", tech_str[info->technology]);
+        rt_kprintf("energy full design:             %u uWh\n", info->energy_full_design_uwh);
+        rt_kprintf("charge full design:             %u uAh\n", info->charge_full_design_uah);
+        rt_kprintf("voltage design range:           %u~%u uV\n", info->voltage_min_design_uv, info->voltage_max_design_uv);
+        rt_kprintf("precharge current:              %u uA\n", info->precharge_current_ua);
+        rt_kprintf("charge term current:            %u uA\n", info->charge_term_current_ua);
+        rt_kprintf("charge restart voltage:         %u uV\n", info->charge_restart_voltage_uv);
+        rt_kprintf("constant charge current max:    %u uA\n", info->constant_charge_current_max_ua);
+        rt_kprintf("constant charge voltage max:    %u uV\n", info->constant_charge_voltage_max_uv);
+        rt_kprintf("temp ambient alert range:       %+d.%u~%+d.%u C\n",
+                info->temp_ambient_alert_min / 1000, rt_abs(info->temp_ambient_alert_min) % 1000,
+                info->temp_ambient_alert_max / 1000, rt_abs(info->temp_ambient_alert_max) % 1000);
+        rt_kprintf("temp alert range:               %+d.%u~%+d.%u C\n",
+                info->temp_alert_min / 1000, rt_abs(info->temp_alert_min) % 1000,
+                info->temp_alert_max / 1000, rt_abs(info->temp_alert_max) % 1000);
+        rt_kprintf("temp range:                     %+d.%u~%+d.%u C\n",
+                info->temp_min / 1000, rt_abs(info->temp_min) % 1000,
+                info->temp_max / 1000, rt_abs(info->temp_max) % 1000);
+    }
+}
+
+static void power_supply_dump_properties(struct rt_power_supply *psy)
+{
+    rt_size_t i;
+
+    for (i = 0; i < sizeof(g_power_supply_prop_desc) / sizeof(g_power_supply_prop_desc[0]); ++i)
+    {
+        power_supply_dump_one_property(psy, &g_power_supply_prop_desc[i], RT_FALSE);
+    }
+}
+
+static int power_supply_do_list(void)
+{
+    struct rt_power_supply **nodes;
+    rt_size_t count = 0;
+    rt_size_t i;
+
+    nodes = rt_power_supply_snapshot(&count);
+    if (!nodes || !count)
+    {
+        return 0;
+    }
+
+    for (i = 0; i < count; ++i)
+    {
+        rt_kprintf("%s %s\n", rt_power_supply_name(nodes[i]), type_str[nodes[i]->type]);
+        power_supply_dump_properties(nodes[i]);
+        power_supply_dump_battery_info(nodes[i]);
+    }
+
+    rt_power_supply_snapshot_free(nodes, count);
+    return 0;
+}
+
+static int power_supply_do_show(const char *name)
+{
+    struct rt_power_supply *psy = power_supply_find_by_name(name);
+
+    if (!psy)
+    {
+        rt_kprintf("power_supply: device '%s' not found\n", name ? name : "<null>");
+        return -RT_ERROR;
+    }
+
+    rt_kprintf("%s %s\n", rt_power_supply_name(psy), type_str[psy->type]);
+    power_supply_dump_properties(psy);
+    power_supply_dump_battery_info(psy);
+    rt_power_supply_put(psy);
+    return RT_EOK;
+}
+
+static int power_supply_do_get(const char *name, const char *prop_name)
+{
+    struct rt_power_supply *psy = power_supply_find_by_name(name);
+    const struct power_supply_prop_desc *desc = power_supply_find_prop_desc(prop_name);
+    int ret;
+
+    if (!psy)
+    {
+        rt_kprintf("power_supply: device '%s' not found\n", name ? name : "<null>");
+        return -RT_ERROR;
+    }
+
+    if (!desc)
+    {
+        rt_kprintf("power_supply: unknown property '%s'\n", prop_name ? prop_name : "<null>");
+        power_supply_dump_known_property_names();
+        rt_power_supply_put(psy);
+        return -RT_EINVAL;
+    }
+
+    ret = power_supply_dump_one_property(psy, desc, RT_TRUE);
+    rt_power_supply_put(psy);
+    return ret;
+}
+
+static int power_supply(int argc, char **argv)
+{
+    if (argc == 2 && !rt_strcmp(argv[1], "list"))
+    {
+        return power_supply_do_list();
+    }
+
+    if (argc == 3 && !rt_strcmp(argv[1], "show"))
+    {
+        return power_supply_do_show(argv[2]);
+    }
+
+    if (argc == 4 && !rt_strcmp(argv[1], "get"))
+    {
+        return power_supply_do_get(argv[2], argv[3]);
+    }
+
+    rt_kputs("Usage:\n");
+    rt_kputs("  power_supply list\n");
+    rt_kputs("  power_supply show <name>\n");
+    rt_kputs("  power_supply get <name> <property>\n");
+
+    return RT_EOK;
+}
+MSH_CMD_EXPORT(power_supply, power supply helper use power_supply list);
+
+#endif /* RT_USING_CONSOLE && RT_USING_MSH */

+ 4 - 1
components/drivers/regulator/Kconfig

@@ -2,12 +2,13 @@ menuconfig RT_USING_REGULATOR
     bool "Using Voltage and Current Regulator"
     select RT_USING_ADT
     select RT_USING_ADT_REF
-    depends on RT_USING_DM
     default n
 
 config RT_REGULATOR_FIXED
     bool "Fixed regulator support"
     depends on RT_USING_REGULATOR
+    depends on RT_USING_DM
+    depends on RT_USING_OFW
     depends on RT_USING_PIN
     depends on RT_USING_PINCTRL
     default y
@@ -15,6 +16,8 @@ config RT_REGULATOR_FIXED
 config RT_REGULATOR_GPIO
     bool "GPIO regulator support"
     depends on RT_USING_REGULATOR
+    depends on RT_USING_DM
+    depends on RT_USING_OFW
     depends on RT_USING_PIN
     default y
 

+ 1 - 1
components/drivers/regulator/SConscript

@@ -8,7 +8,7 @@ if not GetDepend(['RT_USING_REGULATOR']):
 cwd = GetCurrentDir()
 CPPPATH = [cwd + '/../include']
 
-src = ['regulator.c', 'regulator_dm.c']
+src = ['regulator.c', 'regulator_dm.c', 'regulator_cmd.c']
 
 if GetDepend(['RT_REGULATOR_FIXED']):
     src += ['regulator-fixed.c']

+ 272 - 9
components/drivers/regulator/regulator.c

@@ -6,32 +6,70 @@
  * Change Logs:
  * Date           Author       Notes
  * 2023-09-23     GuEe-GUI     first version
+ * 2026-03-27     Evlers       add current support and break away from reliance on DM,
+ *                             and solve the problem of enabling counting.
  */
 
 #include <rtthread.h>
 #include <rtservice.h>
+#include <rtdevice.h>
 
 #define DBG_TAG "rtdm.regulator"
 #define DBG_LVL DBG_INFO
 #include <rtdbg.h>
 
-#include <drivers/ofw.h>
-#include <drivers/platform.h>
-#include <drivers/regulator.h>
 
 struct rt_regulator
 {
     struct rt_regulator_node *reg_np;
 };
 
+struct rt_regulator_record
+{
+    rt_list_t list;
+    struct rt_regulator_node *reg_np;
+};
+
 static RT_DEFINE_SPINLOCK(_regulator_lock);
+static rt_list_t _regulator_records = RT_LIST_OBJECT_INIT(_regulator_records);
 
 static rt_err_t regulator_enable(struct rt_regulator_node *reg_np);
 static rt_err_t regulator_disable(struct rt_regulator_node *reg_np);
 
+static struct rt_regulator_record *regulator_find_record_by_name(const char *name)
+{
+    struct rt_regulator_record *record = RT_NULL;
+
+    rt_list_for_each_entry(record, &_regulator_records, list)
+    {
+        if (!rt_strcmp(record->reg_np->supply_name, name))
+        {
+            return record;
+        }
+    }
+
+    return RT_NULL;
+}
+
+static struct rt_regulator_record *regulator_find_record_by_node(struct rt_regulator_node *reg_np)
+{
+    struct rt_regulator_record *record = RT_NULL;
+
+    rt_list_for_each_entry(record, &_regulator_records, list)
+    {
+        if (record->reg_np == reg_np)
+        {
+            return record;
+        }
+    }
+
+    return RT_NULL;
+}
+
 rt_err_t rt_regulator_register(struct rt_regulator_node *reg_np)
 {
     rt_err_t err;
+    struct rt_regulator_record *record;
     const struct rt_regulator_param *param;
 
     if (!reg_np || !reg_np->dev || !reg_np->param || !reg_np->ops)
@@ -59,6 +97,28 @@ rt_err_t rt_regulator_register(struct rt_regulator_node *reg_np)
         }
     }
 
+    rt_hw_spin_lock(&_regulator_lock.lock);
+
+    if (regulator_find_record_by_name(reg_np->supply_name))
+    {
+        rt_hw_spin_unlock(&_regulator_lock.lock);
+        return -RT_EBUSY;
+    }
+
+    record = rt_calloc(1, sizeof(*record));
+
+    if (!record)
+    {
+        rt_hw_spin_unlock(&_regulator_lock.lock);
+        return -RT_ENOMEM;
+    }
+
+    record->reg_np = reg_np;
+    rt_list_init(&record->list);
+    rt_list_insert_before(&_regulator_records, &record->list);
+
+    rt_hw_spin_unlock(&_regulator_lock.lock);
+
 #ifdef RT_USING_OFW
     if (reg_np->dev->ofw_node)
     {
@@ -77,6 +137,7 @@ rt_err_t rt_regulator_register(struct rt_regulator_node *reg_np)
 rt_err_t rt_regulator_unregister(struct rt_regulator_node *reg_np)
 {
     rt_err_t err = RT_EOK;
+    struct rt_regulator_record *record;
 
     if (!reg_np)
     {
@@ -109,9 +170,21 @@ rt_err_t rt_regulator_unregister(struct rt_regulator_node *reg_np)
     reg_np->parent = RT_NULL;
     rt_list_remove(&reg_np->list);
 
+    record = regulator_find_record_by_node(reg_np);
+
+    if (record)
+    {
+        rt_list_remove(&record->list);
+    }
+
 _unlock:
     rt_hw_spin_unlock(&_regulator_lock.lock);
 
+    if (!err && record)
+    {
+        rt_free(record);
+    }
+
     return err;
 }
 
@@ -302,6 +375,7 @@ static rt_err_t regulator_enable(struct rt_regulator_node *reg_np)
 rt_err_t rt_regulator_enable(struct rt_regulator *reg)
 {
     rt_err_t err;
+    int enabled_cnt;
 
     if (!reg)
     {
@@ -310,11 +384,20 @@ rt_err_t rt_regulator_enable(struct rt_regulator *reg)
 
     if (rt_regulator_is_enabled(reg))
     {
+        rt_atomic_add(&reg->reg_np->enabled_count, 1);
         return RT_EOK;
     }
 
     rt_hw_spin_lock(&_regulator_lock.lock);
 
+    enabled_cnt = rt_atomic_load(&reg->reg_np->enabled_count);
+    if (enabled_cnt > 0)
+    {
+        rt_atomic_add(&reg->reg_np->enabled_count, 1);
+        rt_hw_spin_unlock(&_regulator_lock.lock);
+        return RT_EOK;
+    }
+
     err = regulator_enable(reg->reg_np);
 
     rt_hw_spin_unlock(&_regulator_lock.lock);
@@ -352,6 +435,7 @@ static rt_err_t regulator_disable(struct rt_regulator_node *reg_np)
 rt_err_t rt_regulator_disable(struct rt_regulator *reg)
 {
     rt_err_t err;
+    int enabled_cnt;
 
     if (!reg)
     {
@@ -363,15 +447,21 @@ rt_err_t rt_regulator_disable(struct rt_regulator *reg)
         return RT_EOK;
     }
 
-    if (rt_atomic_load(&reg->reg_np->enabled_count) != 0)
+    rt_hw_spin_lock(&_regulator_lock.lock);
+
+    enabled_cnt = rt_atomic_load(&reg->reg_np->enabled_count);
+    if (enabled_cnt > 0)
     {
         rt_atomic_sub(&reg->reg_np->enabled_count, 1);
+        enabled_cnt--;
 
-        return RT_EOK;
+        if (enabled_cnt > 0)
+        {
+            rt_hw_spin_unlock(&_regulator_lock.lock);
+            return RT_EOK;
+        }
     }
 
-    rt_hw_spin_lock(&_regulator_lock.lock);
-
     err = regulator_disable(reg->reg_np);
 
     rt_hw_spin_unlock(&_regulator_lock.lock);
@@ -440,6 +530,41 @@ static rt_err_t regulator_set_voltage(struct rt_regulator_node *reg_np, int min_
     return err;
 }
 
+static rt_err_t regulator_set_current(struct rt_regulator_node *reg_np, int min_uamp, int max_uamp)
+{
+    rt_err_t err = RT_EOK;
+
+    if (reg_np->ops->set_current)
+    {
+        union rt_regulator_notifier_args args;
+
+        RT_ASSERT(reg_np->ops->get_current != RT_NULL);
+
+        args.old_uamp = reg_np->ops->get_current(reg_np);
+        args.min_uamp = min_uamp;
+        args.max_uamp = max_uamp;
+
+        err = regulator_notifier_call_chain(reg_np, RT_REGULATOR_MSG_CURRENT_CHANGE, &args);
+
+        if (!err)
+        {
+            err = reg_np->ops->set_current(reg_np, min_uamp, max_uamp);
+        }
+
+        if (err)
+        {
+            regulator_notifier_call_chain(reg_np, RT_REGULATOR_MSG_CURRENT_CHANGE_ERR,
+                                          (void *)(rt_base_t)args.old_uamp);
+        }
+    }
+    else
+    {
+        err = -RT_ENOSYS;
+    }
+
+    return err;
+}
+
 rt_bool_t rt_regulator_is_supported_voltage(struct rt_regulator *reg, int min_uvolt, int max_uvolt)
 {
     const struct rt_regulator_param *param;
@@ -502,6 +627,71 @@ int rt_regulator_get_voltage(struct rt_regulator *reg)
     return uvolt;
 }
 
+rt_bool_t rt_regulator_is_supported_current(struct rt_regulator *reg, int min_uamp, int max_uamp)
+{
+    const struct rt_regulator_param *param;
+
+    if (!reg)
+    {
+        return RT_FALSE;
+    }
+
+    param = reg->reg_np->param;
+
+    if (!param || param->max_uamp <= 0)
+    {
+        return RT_FALSE;
+    }
+
+    return param->min_uamp <= min_uamp && param->max_uamp >= max_uamp;
+}
+
+rt_err_t rt_regulator_set_current(struct rt_regulator *reg, int min_uamp, int max_uamp)
+{
+    rt_err_t err;
+
+    if (!reg)
+    {
+        return -RT_EINVAL;
+    }
+
+    rt_hw_spin_lock(&_regulator_lock.lock);
+
+    err = regulator_set_current(reg->reg_np, min_uamp, max_uamp);
+
+    rt_hw_spin_unlock(&_regulator_lock.lock);
+
+    return err;
+}
+
+int rt_regulator_get_current(struct rt_regulator *reg)
+{
+    int uamp = RT_REGULATOR_UAMP_INVALID;
+    struct rt_regulator_node *reg_np;
+
+    if (!reg)
+    {
+        return -RT_EINVAL;
+    }
+
+    rt_hw_spin_lock(&_regulator_lock.lock);
+
+    reg_np = reg->reg_np;
+
+    if (reg_np->ops->get_current)
+    {
+        uamp = reg_np->ops->get_current(reg_np);
+    }
+    else
+    {
+        uamp = -RT_ENOSYS;
+    }
+
+    rt_hw_spin_unlock(&_regulator_lock.lock);
+
+    return uamp;
+}
+
 rt_err_t rt_regulator_set_mode(struct rt_regulator *reg, rt_uint32_t mode)
 {
     rt_err_t err;
@@ -603,14 +793,14 @@ struct rt_regulator *rt_regulator_get(struct rt_device *dev, const char *id)
     struct rt_regulator *reg = RT_NULL;
     struct rt_regulator_node *reg_np = RT_NULL;
 
-    if (!dev || !id)
+    if (!id)
     {
         reg = rt_err_ptr(-RT_EINVAL);
         goto _end;
     }
 
 #ifdef RT_USING_OFW
-    if (dev->ofw_node)
+    if (dev && dev->ofw_node)
     {
         rt_phandle supply_phandle;
         struct rt_ofw_node *np = dev->ofw_node;
@@ -639,6 +829,19 @@ struct rt_regulator *rt_regulator_get(struct rt_device *dev, const char *id)
     }
 #endif /* RT_USING_OFW */
 
+    if (!reg_np)
+    {
+        struct rt_regulator_record *record;
+
+        rt_hw_spin_lock(&_regulator_lock.lock);
+        record = regulator_find_record_by_name(id);
+        if (record)
+        {
+            reg_np = record->reg_np;
+        }
+        rt_hw_spin_unlock(&_regulator_lock.lock);
+    }
+
     if (!reg_np)
     {
         goto _end;
@@ -682,3 +885,63 @@ void rt_regulator_put(struct rt_regulator *reg)
     rt_ref_put(&reg->reg_np->ref, &regulator_release);
     rt_free(reg);
 }
+
+struct rt_regulator_node **rt_regulator_nodes_snapshot(rt_size_t *count)
+{
+    struct rt_regulator_record *record;
+    struct rt_regulator_node **nodes;
+    rt_size_t total = 0;
+    rt_size_t idx = 0;
+
+    if (!count)
+    {
+        return RT_NULL;
+    }
+
+    *count = 0;
+
+    rt_hw_spin_lock(&_regulator_lock.lock);
+    rt_list_for_each_entry(record, &_regulator_records, list)
+    {
+        total++;
+    }
+    rt_hw_spin_unlock(&_regulator_lock.lock);
+
+    if (!total)
+    {
+        return RT_NULL;
+    }
+
+    nodes = rt_calloc(total, sizeof(*nodes));
+    if (!nodes)
+    {
+        return RT_NULL;
+    }
+
+    rt_hw_spin_lock(&_regulator_lock.lock);
+    rt_list_for_each_entry(record, &_regulator_records, list)
+    {
+        nodes[idx] = record->reg_np;
+        rt_ref_get(&record->reg_np->ref);
+        idx++;
+    }
+    rt_hw_spin_unlock(&_regulator_lock.lock);
+
+    *count = total;
+    return nodes;
+}
+
+void rt_regulator_nodes_snapshot_free(struct rt_regulator_node **nodes, rt_size_t count)
+{
+    if (!nodes)
+    {
+        return;
+    }
+
+    while (count--)
+    {
+        rt_ref_put(&nodes[count]->ref, &regulator_release);
+    }
+
+    rt_free(nodes);
+}

+ 548 - 0
components/drivers/regulator/regulator_cmd.c

@@ -0,0 +1,548 @@
+/*
+ * Copyright (c) 2006-2026, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2026-03-27     Evlers       first version
+ */
+
+#include <rtdevice.h>
+
+#ifdef RT_USING_FINSH
+
+#include <limits.h>
+#include <stdlib.h>
+
+static void regulator_msh_usage(void)
+{
+    rt_kprintf("Usage:\n");
+    rt_kprintf("  regulator list\n");
+    rt_kprintf("  regulator info <name>\n");
+    rt_kprintf("  regulator <name> on|off|status\n");
+    rt_kprintf("  regulator <name> getv\n");
+    rt_kprintf("  regulator <name> setv <min_uV> [max_uV]\n");
+    rt_kprintf("  regulator <name> getc\n");
+    rt_kprintf("  regulator <name> setc <min_uA> [max_uA]\n");
+}
+
+static rt_bool_t regulator_node_is_enabled(struct rt_regulator_node *node)
+{
+    if (!node)
+    {
+        return RT_FALSE;
+    }
+
+    if (node->ops->is_enabled)
+    {
+        return node->ops->is_enabled(node);
+    }
+
+    return rt_atomic_load(&node->enabled_count) > 0;
+}
+
+static rt_err_t regulator_msh_parse_value(const char *str, int *out)
+{
+    char *endptr;
+    long value;
+
+    if (!str || !out)
+    {
+        return -RT_EINVAL;
+    }
+
+    value = strtol(str, &endptr, 10);
+    if (endptr == str || *endptr != '\0')
+    {
+        return -RT_EINVAL;
+    }
+
+    if (value <= 0 || value > INT_MAX)
+    {
+        return -RT_EINVAL;
+    }
+
+    *out = (int)value;
+    return RT_EOK;
+}
+
+static rt_err_t regulator_msh_get_reg(const char *name, struct rt_regulator **out)
+{
+    struct rt_regulator *reg;
+
+    if (!name || !out)
+    {
+        return -RT_EINVAL;
+    }
+
+    reg = rt_regulator_get(RT_NULL, name);
+    if (!reg)
+    {
+        rt_kprintf("regulator '%s' not found\n", name);
+        return -RT_ERROR;
+    }
+
+    if (rt_is_err(reg))
+    {
+        rt_err_t err = rt_ptr_err(reg);
+
+        rt_kprintf("regulator '%s' get failed: %d\n", name, err);
+        return err;
+    }
+
+    *out = reg;
+    return RT_EOK;
+}
+
+static struct rt_regulator_node *regulator_find_node_by_name(const char *name)
+{
+    struct rt_regulator_node **nodes;
+    struct rt_regulator_node *result = RT_NULL;
+    rt_size_t count = 0;
+    rt_size_t i;
+
+    if (!name)
+    {
+        return RT_NULL;
+    }
+
+    nodes = rt_regulator_nodes_snapshot(&count);
+    if (!nodes)
+    {
+        return RT_NULL;
+    }
+
+    for (i = 0; i < count; ++i)
+    {
+        if (nodes[i]->supply_name && !rt_strcmp(nodes[i]->supply_name, name))
+        {
+            result = nodes[i];
+            break;
+        }
+    }
+
+    rt_regulator_nodes_snapshot_free(nodes, count);
+    return result;
+}
+
+static rt_err_t regulator_msh_info(const char *name)
+{
+    struct rt_regulator *reg;
+    struct rt_regulator_node *node;
+    const struct rt_regulator_param *param;
+    rt_err_t err;
+    int value;
+
+    node = regulator_find_node_by_name(name);
+    if (!node)
+    {
+        rt_kprintf("regulator '%s' not found\n", name ? name : "(null)");
+        return -RT_ERROR;
+    }
+
+    err = regulator_msh_get_reg(name, &reg);
+    if (err)
+    {
+        return err;
+    }
+
+    param = node->param;
+
+    rt_kprintf("Regulator info:\n");
+    rt_kprintf("  name        : %s\n", node->supply_name ? node->supply_name : "(null)");
+    rt_kprintf("  state       : %s\n", regulator_node_is_enabled(node) ? "on" : "off");
+    rt_kprintf("  enabled_cnt : %d\n", rt_atomic_load(&node->enabled_count));
+
+    if (param)
+    {
+        rt_kprintf("  boot_on     : %d\n", param->boot_on);
+        rt_kprintf("  always_on   : %d\n", param->always_on);
+        if (param->min_uvolt || param->max_uvolt)
+        {
+            rt_kprintf("  volt_range  : [%d, %d] uV\n", param->min_uvolt, param->max_uvolt);
+        }
+        if (param->min_uamp || param->max_uamp)
+        {
+            rt_kprintf("  curr_range  : [%d, %d] uA\n", param->min_uamp, param->max_uamp);
+        }
+        if (param->enable_delay)
+        {
+            rt_kprintf("  enable_delay: %d us\n", param->enable_delay);
+        }
+        if (param->off_on_delay)
+        {
+            rt_kprintf("  off_on_delay: %d us\n", param->off_on_delay);
+        }
+    }
+
+    value = rt_regulator_get_voltage(reg);
+    if (value >= 0)
+    {
+        rt_kprintf("  voltage_now : %d uV\n", value);
+    }
+
+    value = rt_regulator_get_current(reg);
+    if (value >= 0)
+    {
+        rt_kprintf("  current_now : %d uA\n", value);
+    }
+
+    value = rt_regulator_get_mode(reg);
+    if (value >= 0)
+    {
+        rt_kprintf("  mode        : 0x%X\n", value);
+    }
+
+    rt_regulator_put(reg);
+
+    return RT_EOK;
+}
+
+static void regulator_msh_list(void)
+{
+    struct rt_regulator_node **nodes;
+    rt_size_t count = 0;
+    rt_size_t idx;
+
+    nodes = rt_regulator_nodes_snapshot(&count);
+
+    rt_kprintf("Regulator list:\n");
+
+    if (!nodes || !count)
+    {
+        rt_kprintf("  (none)\n");
+        return;
+    }
+
+    for (idx = 0; idx < count; idx++)
+    {
+        rt_kprintf("%2d) %-20s state=%-3s boot_on=%d always_on=%d\n",
+                (int)(idx + 1),
+                nodes[idx]->supply_name ? nodes[idx]->supply_name : "(null)",
+                regulator_node_is_enabled(nodes[idx]) ? "on" : "off",
+                nodes[idx]->param ? nodes[idx]->param->boot_on : 0,
+                nodes[idx]->param ? nodes[idx]->param->always_on : 0);
+    }
+
+    rt_kprintf("Total: %d\n", (int)count);
+    rt_regulator_nodes_snapshot_free(nodes, count);
+}
+
+static rt_err_t regulator_msh_switch(const char *name, rt_bool_t enable)
+{
+    struct rt_regulator *reg;
+    struct rt_regulator_node *node;
+    rt_err_t err;
+    int enabled_cnt = -1;
+
+    err = regulator_msh_get_reg(name, &reg);
+    if (err)
+    {
+        return err;
+    }
+
+    node = regulator_find_node_by_name(name);
+
+    if (enable)
+    {
+        err = rt_regulator_enable(reg);
+    }
+    else
+    {
+        err = rt_regulator_disable(reg);
+    }
+
+    if (err)
+    {
+        rt_kprintf("%s '%s' failed: %d\n", enable ? "enable" : "disable", name, err);
+    }
+    else
+    {
+        if (node)
+        {
+            enabled_cnt = (int)rt_atomic_load(&node->enabled_count);
+        }
+
+        if (enabled_cnt >= 0)
+        {
+            rt_kprintf("regulator '%s' %s (enabled_cnt=%d)\n", name,
+                    enable ? "enabled" : "disabled", enabled_cnt);
+        }
+        else
+        {
+            rt_kprintf("regulator '%s' %s\n", name, enable ? "enabled" : "disabled");
+        }
+    }
+
+    rt_regulator_put(reg);
+    return err;
+}
+
+static rt_err_t regulator_msh_status(const char *name)
+{
+    struct rt_regulator *reg;
+    rt_err_t err;
+
+    err = regulator_msh_get_reg(name, &reg);
+    if (err)
+    {
+        return err;
+    }
+
+    rt_kprintf("regulator '%s' is %s\n", name, rt_regulator_is_enabled(reg) ? "on" : "off");
+    rt_regulator_put(reg);
+
+    return RT_EOK;
+}
+
+static rt_err_t regulator_msh_get_voltage_cmd(const char *name)
+{
+    struct rt_regulator *reg;
+    rt_err_t err;
+    int value;
+
+    err = regulator_msh_get_reg(name, &reg);
+    if (err)
+    {
+        return err;
+    }
+
+    value = rt_regulator_get_voltage(reg);
+    if (value < 0)
+    {
+        rt_kprintf("get voltage of '%s' failed: %d\n", name, value);
+        err = value;
+    }
+    else
+    {
+        rt_kprintf("regulator '%s' voltage: %d uV\n", name, value);
+    }
+
+    rt_regulator_put(reg);
+    return err;
+}
+
+static rt_err_t regulator_msh_set_voltage_cmd(const char *name, const char *min_str, const char *max_str)
+{
+    struct rt_regulator *reg;
+    int min_uvolt;
+    int max_uvolt;
+    rt_err_t err;
+
+    if ((err = regulator_msh_parse_value(min_str, &min_uvolt)))
+    {
+        rt_kprintf("invalid min_uV: %s\n", min_str ? min_str : "(null)");
+        return err;
+    }
+
+    if (max_str)
+    {
+        if ((err = regulator_msh_parse_value(max_str, &max_uvolt)))
+        {
+            rt_kprintf("invalid max_uV: %s\n", max_str);
+            return err;
+        }
+    }
+    else
+    {
+        max_uvolt = min_uvolt;
+    }
+
+    if (max_uvolt < min_uvolt)
+    {
+        rt_kprintf("max_uV must be >= min_uV\n");
+        return -RT_EINVAL;
+    }
+
+    err = regulator_msh_get_reg(name, &reg);
+    if (err)
+    {
+        return err;
+    }
+
+    err = rt_regulator_set_voltage(reg, min_uvolt, max_uvolt);
+    if (err)
+    {
+        rt_kprintf("set voltage of '%s' failed: %d\n", name, err);
+    }
+    else
+    {
+        rt_kprintf("regulator '%s' voltage set to [%d, %d] uV\n", name, min_uvolt, max_uvolt);
+    }
+
+    rt_regulator_put(reg);
+    return err;
+}
+
+static rt_err_t regulator_msh_get_current_cmd(const char *name)
+{
+    struct rt_regulator *reg;
+    rt_err_t err;
+    int value;
+
+    err = regulator_msh_get_reg(name, &reg);
+    if (err)
+    {
+        return err;
+    }
+
+    value = rt_regulator_get_current(reg);
+    if (value < 0)
+    {
+        rt_kprintf("get current of '%s' failed: %d\n", name, value);
+        err = value;
+    }
+    else
+    {
+        rt_kprintf("regulator '%s' current: %d uA\n", name, value);
+    }
+
+    rt_regulator_put(reg);
+    return err;
+}
+
+static rt_err_t regulator_msh_set_current_cmd(const char *name, const char *min_str, const char *max_str)
+{
+    struct rt_regulator *reg;
+    int min_uamp;
+    int max_uamp;
+    rt_err_t err;
+
+    if ((err = regulator_msh_parse_value(min_str, &min_uamp)))
+    {
+        rt_kprintf("invalid min_uA: %s\n", min_str ? min_str : "(null)");
+        return err;
+    }
+
+    if (max_str)
+    {
+        if ((err = regulator_msh_parse_value(max_str, &max_uamp)))
+        {
+            rt_kprintf("invalid max_uA: %s\n", max_str);
+            return err;
+        }
+    }
+    else
+    {
+        max_uamp = min_uamp;
+    }
+
+    if (max_uamp < min_uamp)
+    {
+        rt_kprintf("max_uA must be >= min_uA\n");
+        return -RT_EINVAL;
+    }
+
+    err = regulator_msh_get_reg(name, &reg);
+    if (err)
+    {
+        return err;
+    }
+
+    if (!rt_regulator_is_supported_current(reg, min_uamp, max_uamp))
+    {
+        rt_kprintf("regulator '%s' does not support current setting in [%d, %d] uA\n",
+                   name, min_uamp, max_uamp);
+        rt_regulator_put(reg);
+        return -RT_ENOSYS;
+    }
+
+    err = rt_regulator_set_current(reg, min_uamp, max_uamp);
+    if (err)
+    {
+        rt_kprintf("set current of '%s' failed: %d\n", name, err);
+    }
+    else
+    {
+        rt_kprintf("regulator '%s' current set to [%d, %d] uA\n", name, min_uamp, max_uamp);
+    }
+
+    rt_regulator_put(reg);
+    return err;
+}
+
+static int regulator_msh(int argc, char **argv)
+{
+    if (argc < 2)
+    {
+        regulator_msh_usage();
+        return RT_EOK;
+    }
+
+    if (!rt_strcmp(argv[1], "list"))
+    {
+        regulator_msh_list();
+        return RT_EOK;
+    }
+
+    if (!rt_strcmp(argv[1], "info"))
+    {
+        if (argc < 3)
+        {
+            regulator_msh_usage();
+            return -RT_EINVAL;
+        }
+
+        return regulator_msh_info(argv[2]);
+    }
+
+    if (argc < 3)
+    {
+        regulator_msh_usage();
+        return -RT_EINVAL;
+    }
+
+    if (!rt_strcmp(argv[2], "on"))
+    {
+        return regulator_msh_switch(argv[1], RT_TRUE);
+    }
+
+    if (!rt_strcmp(argv[2], "off"))
+    {
+        return regulator_msh_switch(argv[1], RT_FALSE);
+    }
+
+    if (!rt_strcmp(argv[2], "status"))
+    {
+        return regulator_msh_status(argv[1]);
+    }
+
+    if (!rt_strcmp(argv[2], "getv"))
+    {
+        return regulator_msh_get_voltage_cmd(argv[1]);
+    }
+
+    if (!rt_strcmp(argv[2], "setv"))
+    {
+        if (argc < 4)
+        {
+            regulator_msh_usage();
+            return -RT_EINVAL;
+        }
+
+        return regulator_msh_set_voltage_cmd(argv[1], argv[3], argc >= 5 ? argv[4] : RT_NULL);
+    }
+
+    if (!rt_strcmp(argv[2], "getc"))
+    {
+        return regulator_msh_get_current_cmd(argv[1]);
+    }
+
+    if (!rt_strcmp(argv[2], "setc"))
+    {
+        if (argc < 4)
+        {
+            regulator_msh_usage();
+            return -RT_EINVAL;
+        }
+
+        return regulator_msh_set_current_cmd(argv[1], argv[3], argc >= 5 ? argv[4] : RT_NULL);
+    }
+
+    regulator_msh_usage();
+    return -RT_EINVAL;
+}
+MSH_CMD_EXPORT_ALIAS(regulator_msh, regulator, regulator command);
+
+#endif /* RT_USING_FINSH */

+ 4 - 1
components/drivers/regulator/regulator_dm.h

@@ -6,6 +6,7 @@
  * Change Logs:
  * Date           Author       Notes
  * 2023-09-23     GuEe-GUI     first version
+ * 2026-03-27     Evlers       stub out regulator_ofw_parse when OFW disabled
  */
 
 #ifndef __REGULATOR_DM_H__
@@ -17,8 +18,10 @@
 #ifdef RT_USING_OFW
 rt_err_t regulator_ofw_parse(struct rt_ofw_node *np, struct rt_regulator_param *param);
 #else
-rt_inline rt_err_t regulator_ofw_parse(struct rt_ofw_node *np, struct rt_regulator_param *param);
+rt_inline rt_err_t regulator_ofw_parse(void *np, struct rt_regulator_param *param)
 {
+    RT_UNUSED(np);
+    RT_UNUSED(param);
     return RT_EOK;
 }
 #endif /* RT_USING_OFW */