You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2021/12/08 05:29:13 UTC

[incubator-nuttx] 01/04: driver:power:add regulator framework

This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git

commit c8f1a9e4308ac1ba4c49316ad7dd16341c803c0a
Author: zhuyanlin <zh...@xiaomi.com>
AuthorDate: Thu Nov 25 17:48:58 2021 +0800

    driver:power:add regulator framework
    
    N/A
    
    Signed-off-by: zhuyanlin <zh...@xiaomi.com>
---
 drivers/power/Kconfig           |   8 +
 drivers/power/Make.defs         |  10 +
 drivers/power/regulator.c       | 772 ++++++++++++++++++++++++++++++++++++++++
 include/nuttx/power/consumer.h  |  75 ++++
 include/nuttx/power/regulator.h | 162 +++++++++
 5 files changed, 1027 insertions(+)

diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index d45abb5..2ac5c04 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -343,6 +343,14 @@ menuconfig POWER
 
 if POWER
 
+config REGULATOR
+	bool "Regulator core driver support"
+	default n
+	---help---
+		The regulator core driver implements the uper layer framework that the lower
+		layer driver can register with, and the common regulator APIs that are easy
+		for other drivers to call for the control of their power supply.
+
 config BATTERY_CHARGER
 	bool "Battery Charger support"
 	default n
diff --git a/drivers/power/Make.defs b/drivers/power/Make.defs
index 3f62be9..07e0be8 100644
--- a/drivers/power/Make.defs
+++ b/drivers/power/Make.defs
@@ -71,6 +71,16 @@ POWER_CFLAGS := ${shell $(INCDIR) "$(CC)" $(TOPDIR)$(DELIM)drivers$(DELIM)power}
 
 endif
 
+ifeq ($(CONFIG_REGULATOR), y)
+
+CSRCS += regulator.c
+
+POWER_DEPPATH := --dep-path power
+POWER_VPATH := :power
+POWER_CFLAGS := ${shell $(INCDIR) "$(CC)" $(TOPDIR)$(DELIM)drivers$(DELIM)power}
+
+endif
+
 # Add battery charger drivers
 
 ifeq ($(CONFIG_BATTERY_CHARGER),y)
diff --git a/drivers/power/regulator.c b/drivers/power/regulator.c
new file mode 100644
index 0000000..3223530
--- /dev/null
+++ b/drivers/power/regulator.c
@@ -0,0 +1,772 @@
+/****************************************************************************
+ * drivers/power/regulator.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <debug.h>
+#include <errno.h>
+#include <semaphore.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/power/regulator.h>
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int _regulator_is_enabled(FAR struct regulator_dev_s *rdev);
+static int _regulator_do_enable(FAR struct regulator_dev_s *rdev);
+static int _regulator_do_disable(FAR struct regulator_dev_s *rdev);
+static int regulator_check_consumers(FAR struct regulator_dev_s *rdev,
+                                     FAR int *min_uv, FAR int *max_uv);
+static FAR struct regulator_dev_s *regulator_dev_lookup(const char *supply);
+static int regulator_map_voltage_iterate(FAR struct regulator_dev_s *rdev,
+                                         int min_uv, int max_uv);
+static int _regulator_get_voltage(FAR struct regulator_dev_s *rdev);
+static int _regulator_do_set_voltage(FAR struct regulator_dev_s *rdev,
+                                     int min_uv, int max_uv);
+static int _regulator_set_voltage_unlocked(FAR struct regulator_s *regulator,
+                                           int min_uv, int max_uv);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct list_node g_reg_list = LIST_INITIAL_VALUE(g_reg_list);
+static sem_t g_reg_sem             = SEM_INITIALIZER(1);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static int _regulator_is_enabled(FAR struct regulator_dev_s *rdev)
+{
+  if (!rdev->ops->is_enabled)
+    {
+      return 1;
+    }
+
+  return rdev->ops->is_enabled(rdev);
+}
+
+static int _regulator_do_enable(FAR struct regulator_dev_s *rdev)
+{
+  int ret = 0;
+
+  if (rdev->ops->enable)
+    {
+      ret = rdev->ops->enable(rdev);
+      if (ret < 0)
+        {
+          pwrerr("failed to enable %d\n", ret);
+          return ret;
+        }
+    }
+
+  if (rdev->desc->enable_time > 0)
+    {
+      up_udelay(rdev->desc->enable_time);
+    }
+
+  return ret;
+}
+
+static int _regulator_do_disable(FAR struct regulator_dev_s *rdev)
+{
+  int ret = 0;
+
+  if (rdev->ops->disable)
+    {
+      ret = rdev->ops->disable(rdev);
+      if (ret < 0)
+        {
+          pwrerr("failed to disable %d\n", ret);
+        }
+    }
+
+  return ret;
+}
+
+static int regulator_check_consumers(FAR struct regulator_dev_s *rdev,
+                                     FAR int *min_uv, FAR int *max_uv)
+{
+  FAR struct regulator_s *regulator;
+
+  list_for_every_entry(&rdev->consumer_list, regulator,
+                       struct regulator_s, list)
+    {
+      if (!regulator->min_uv && !regulator->max_uv)
+        {
+          continue;
+        }
+
+      if (*max_uv > regulator->max_uv)
+        {
+          *max_uv = regulator->max_uv;
+        }
+
+      if (*min_uv < regulator->min_uv)
+        {
+          *min_uv = regulator->min_uv;
+        }
+    }
+
+  if (*min_uv > *max_uv)
+    {
+      pwrerr("Restricting voltage, %d-%d uv\n", *min_uv, *max_uv);
+      return -EINVAL;
+    }
+
+  return 0;
+}
+
+static FAR struct regulator_dev_s *regulator_dev_lookup(const char *supply)
+{
+  FAR struct regulator_dev_s *rdev;
+  FAR struct regulator_dev_s *rdev_found = NULL;
+
+  nxsem_wait_uninterruptible(&g_reg_sem);
+  list_for_every_entry(&g_reg_list, rdev, struct regulator_dev_s, list)
+    {
+      if (rdev->desc->name && strcmp(rdev->desc->name, supply) == 0)
+        {
+          rdev_found = rdev;
+          break;
+        }
+    }
+
+  nxsem_post(&g_reg_sem);
+
+  return rdev_found;
+}
+
+static int regulator_map_voltage_iterate(FAR struct regulator_dev_s *rdev,
+                                         int min_uv, int max_uv)
+{
+  int best_val = INT_MAX;
+  int selector = 0;
+  int i;
+  int ret;
+
+  for (i = 0; i < rdev->desc->n_voltages; i++)
+    {
+      ret = rdev->ops->list_voltage(rdev, i);
+      if (ret < 0)
+        {
+          continue;
+        }
+
+      if (ret < best_val && ret >= min_uv && ret <= max_uv)
+        {
+          best_val = ret;
+          selector = i;
+        }
+    }
+
+  if (best_val != INT_MAX)
+    {
+      return selector;
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+static int _regulator_get_voltage(FAR struct regulator_dev_s *rdev)
+{
+  int sel;
+  int ret;
+
+  if (rdev->ops->get_voltage_sel)
+    {
+      sel = rdev->ops->get_voltage_sel(rdev);
+      if (sel < 0)
+        {
+          return sel;
+        }
+
+      ret = rdev->ops->list_voltage(rdev, sel);
+    }
+  else if (rdev->ops->get_voltage)
+    {
+      ret = rdev->ops->get_voltage(rdev);
+    }
+  else if (rdev->ops->list_voltage)
+    {
+      ret = rdev->ops->list_voltage(rdev, 0);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+
+  return ret;
+}
+
+static int _regulator_do_set_voltage(FAR struct regulator_dev_s *rdev,
+                                     int min_uv, int max_uv)
+{
+  FAR const struct regulator_ops_s *ops = rdev->ops;
+  unsigned int selector;
+  int new_uv = 0;
+  int old_uv = _regulator_get_voltage(rdev);
+  int ret = 0;
+  int delay = 0;
+  int best_val;
+
+  if (ops->set_voltage)
+    {
+      ret = ops->set_voltage(rdev, min_uv, max_uv, &selector);
+      if (ret >= 0)
+        {
+          if (ops->list_voltage)
+            {
+              new_uv = ops->list_voltage(rdev, selector);
+            }
+          else
+            {
+              new_uv = _regulator_get_voltage(rdev);
+            }
+        }
+    }
+  else if (ops->set_voltage_sel)
+    {
+      ret = regulator_map_voltage_iterate(rdev, min_uv, max_uv);
+      if (ret >= 0)
+        {
+          best_val = ops->list_voltage(rdev, ret);
+          if (min_uv <= best_val && max_uv >= best_val)
+            {
+              selector = ret;
+              ret = ops->set_voltage_sel(rdev, selector);
+            }
+        }
+      else
+        {
+          ret = -EINVAL;
+        }
+    }
+  else
+    {
+      ret = -EINVAL;
+    }
+
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  if (rdev->desc->ramp_delay)
+    {
+      delay = abs(new_uv - old_uv) / rdev->desc->ramp_delay + 1;
+    }
+
+  up_udelay(delay);
+
+  return ret;
+}
+
+static int _regulator_set_voltage_unlocked(FAR struct regulator_s *regulator,
+                                           int min_uv, int max_uv)
+{
+  FAR struct regulator_dev_s *rdev = regulator->rdev;
+  FAR const struct regulator_ops_s *ops = rdev->ops;
+  int old_min_uv;
+  int old_max_uv;
+  int ret = 0;
+
+  if (min_uv > max_uv)
+    {
+      pwrerr("invalid min %d max %d\n", min_uv, max_uv);
+      return -EINVAL;
+    }
+
+  if (regulator->min_uv == min_uv && regulator->max_uv == max_uv)
+    {
+      goto out;
+    }
+
+  if (!ops->set_voltage && !ops->set_voltage_sel)
+    {
+      pwrerr("set voltage is null\n");
+      ret = -EINVAL;
+      goto out;
+    }
+
+  if (max_uv > rdev->desc->max_uv)
+    {
+      max_uv = rdev->desc->max_uv;
+    }
+
+  if (min_uv < rdev->desc->min_uv)
+    {
+      min_uv = rdev->desc->min_uv;
+    }
+
+  if (min_uv > max_uv)
+    {
+      pwrerr("invalid min %d max %d\n", min_uv, max_uv);
+      ret = -EINVAL;
+      goto out;
+    }
+
+  old_min_uv = regulator->min_uv;
+  old_max_uv = regulator->max_uv;
+  regulator->min_uv = min_uv;
+  regulator->max_uv = max_uv;
+
+  ret = regulator_check_consumers(rdev, &min_uv, &max_uv);
+  if (ret < 0)
+    {
+      goto out2;
+    }
+
+  ret = _regulator_do_set_voltage(rdev, min_uv, max_uv);
+  if (ret < 0)
+    {
+      goto out2;
+    }
+
+out:
+  return ret;
+
+out2:
+  regulator->min_uv = old_min_uv;
+  regulator->max_uv = old_max_uv;
+
+  return ret;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: regulator_get
+ *
+ * Description:
+ *   Lookup and obtain a reference to a regulator.
+ *
+ * Input parameters:
+ *   id - Supply name or the regulator ID.
+ *
+ * Returned value:
+ *    A struct regulator_s pointer on success or NULL on failure
+ *
+ ****************************************************************************/
+
+FAR struct regulator_s *regulator_get(FAR const char *id)
+{
+  FAR struct regulator_dev_s *rdev;
+  FAR struct regulator_s *regulator = NULL;
+
+  if (id == NULL)
+    {
+      pwrerr("get() with no identifier\n");
+      return NULL;
+    }
+
+  rdev = regulator_dev_lookup(id);
+  if (rdev == NULL)
+    {
+      pwrerr("regulator %s not found\n", id);
+      return NULL;
+    }
+
+  regulator = kmm_zalloc(sizeof(struct regulator_s));
+  if (regulator == NULL)
+    {
+      pwrerr("failed to get memory\n");
+      return NULL;
+    }
+
+  regulator->rdev = rdev;
+  list_initialize(&regulator->list);
+
+  nxsem_wait_uninterruptible(&rdev->regulator_sem);
+  rdev->open_count++;
+  list_add_tail(&rdev->consumer_list, &regulator->list);
+  nxsem_post(&rdev->regulator_sem);
+
+  return regulator;
+}
+
+/****************************************************************************
+ * Name: regulator_put
+ *
+ * Description:
+ *   Free the regulator resource.
+ *
+ * Input parameters:
+ *   regulator - The regulator consumer representative
+ *
+ * Returned value:
+ *
+ ****************************************************************************/
+
+void regulator_put(FAR struct regulator_s *regulator)
+{
+  FAR struct regulator_dev_s *rdev;
+
+  if (regulator == NULL)
+    {
+      return;
+    }
+
+  rdev = regulator->rdev;
+
+  nxsem_wait_uninterruptible(&g_reg_sem);
+
+  nxsem_wait_uninterruptible(&rdev->regulator_sem);
+  list_delete(&regulator->list);
+  rdev->open_count--;
+  nxsem_post(&rdev->regulator_sem);
+
+  nxsem_post(&g_reg_sem);
+
+  kmm_free(regulator);
+}
+
+/****************************************************************************
+ * Name: regulator_is_enabled
+ *
+ * Description:
+ *   Is the regulator output enabled.
+ *
+ * Input parameters:
+ *   regulator - The regulator consumer representative
+ *
+ * Returned value:
+ *   1 is enabled and zero for disabled.
+ *
+ ****************************************************************************/
+
+int regulator_is_enabled(FAR struct regulator_s *regulator)
+{
+  FAR struct regulator_dev_s *rdev;
+  int ret = 0;
+
+  if (regulator == NULL)
+    {
+      pwrerr("regulator is null\n");
+      return -EINVAL;
+    }
+
+  rdev = regulator->rdev;
+
+  nxsem_wait_uninterruptible(&rdev->regulator_sem);
+  ret = _regulator_is_enabled(rdev);
+  nxsem_post(&rdev->regulator_sem);
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: regulator_enable
+ *
+ * Description:
+ *   Enable the regulator output.
+ *
+ * Input parameters:
+ *   regulator - The regulator consumer representative
+ *
+ * Returned value:
+ *   Zero on success or a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int regulator_enable(FAR struct regulator_s *regulator)
+{
+  FAR struct regulator_dev_s *rdev;
+  int ret = 0;
+
+  if (regulator == NULL)
+    {
+      pwrerr("enable regulator is null\n");
+      return -EINVAL;
+    }
+
+  rdev = regulator->rdev;
+
+  nxsem_wait_uninterruptible(&rdev->regulator_sem);
+  if (rdev->use_count == 0)
+    {
+      ret = _regulator_do_enable(rdev);
+      if (ret < 0)
+        {
+          return ret;
+        }
+    }
+
+  rdev->use_count++;
+  nxsem_post(&rdev->regulator_sem);
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: regulator_disable
+ *
+ * Description:
+ *   Disable the regulator output.
+ *
+ * Input parameters:
+ *   regulator - The regulator consumer representative
+ *
+ * Returned value:
+ *   Zero on success or a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int regulator_disable(FAR struct regulator_s *regulator)
+{
+  FAR struct regulator_dev_s *rdev;
+  int ret = 0;
+
+  if (regulator == NULL)
+    {
+      pwrerr("disable regulator is null\n");
+      return -EINVAL;
+    }
+
+  rdev = regulator->rdev;
+
+  nxsem_wait_uninterruptible(&rdev->regulator_sem);
+  if (rdev->use_count <= 0)
+    {
+      ret = -EIO;
+      goto err;
+    }
+
+  if (rdev->use_count == 1)
+    {
+      ret = _regulator_do_disable(rdev);
+      if (ret < 0)
+        {
+          goto err;
+        }
+    }
+
+  rdev->use_count--;
+
+err:
+  nxsem_post(&rdev->regulator_sem);
+  return ret;
+}
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: regulator_set_voltage
+ *
+ * Description:
+ *   Set the regulator output voltage.
+ *
+ * Input parameters:
+ *   regulator - The regulator consumer representative
+ *   min_uv - Minimum required voltage in uv
+ *   max_uv - Maximum acceptable voltage in uv
+ *
+ * Returned value:
+ *   Zero on success or a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int regulator_set_voltage(FAR struct regulator_s *regulator,
+                          int min_uv, int max_uv)
+{
+  FAR struct regulator_dev_s *rdev;
+  int ret = 0;
+
+  if (regulator == NULL)
+    {
+      pwrerr("get regulator is null\n");
+      return -EINVAL;
+    }
+
+  rdev = regulator->rdev;
+
+  nxsem_wait_uninterruptible(&rdev->regulator_sem);
+  ret = _regulator_set_voltage_unlocked(regulator, min_uv, max_uv);
+  nxsem_post(&rdev->regulator_sem);
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: regulator_get_voltage
+ *
+ * Description:
+ *   Obtain the regulator output voltage.
+ *
+ * Input parameters:
+ *   regulator - The regulator consumer representative
+ *
+ * Returned value:
+ *   Positive on success or a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int regulator_get_voltage(FAR struct regulator_s *regulator)
+{
+  FAR struct regulator_dev_s *rdev;
+  int ret = 0;
+
+  if (regulator == NULL)
+    {
+      pwrerr("get regulator is null\n");
+      return -EINVAL;
+    }
+
+  rdev = regulator->rdev;
+
+  nxsem_wait_uninterruptible(&rdev->regulator_sem);
+  ret = _regulator_get_voltage(rdev);
+  nxsem_post(&rdev->regulator_sem);
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: regulator_register
+ *
+ * Description:
+ *   This routine is called by the specific regulator drivers to register a
+ *   regulator.
+ *
+ ****************************************************************************/
+
+FAR struct regulator_dev_s *
+regulator_register(const FAR struct regulator_desc_s *regulator_desc,
+                   const struct regulator_ops_s *regulator_ops,
+                   void *priv)
+{
+  FAR struct regulator_dev_s *rdev;
+
+  if (regulator_desc == NULL)
+    {
+      pwrerr("regulator desc is null\n");
+      return NULL;
+    }
+
+  if (regulator_desc->name == NULL || regulator_ops == NULL)
+    {
+      pwrerr("regulator name or ops is null\n");
+      return NULL;
+    }
+
+  if (regulator_ops->get_voltage && regulator_ops->get_voltage_sel)
+    {
+      pwrerr("get_voltage and get_voltage_sel are assigned\n");
+      return NULL;
+    }
+
+  if (regulator_ops->set_voltage && regulator_ops->set_voltage_sel)
+    {
+      pwrerr("set_voltage and set_voltage_sel are assigned\n");
+      return NULL;
+    }
+
+  if (regulator_ops->get_voltage_sel && !regulator_ops->list_voltage)
+    {
+      pwrerr("list voltage is null\n");
+      return NULL;
+    }
+
+  if (regulator_ops->set_voltage_sel && !regulator_ops->list_voltage)
+    {
+      pwrerr("list voltage is null\n");
+      return NULL;
+    }
+
+  rdev = kmm_zalloc(sizeof(struct regulator_dev_s));
+  if (rdev == NULL)
+    {
+      pwrerr("failed to get memory\n");
+      return NULL;
+    }
+
+  rdev->desc = regulator_desc;
+  rdev->ops = regulator_ops;
+  rdev->priv = priv;
+  nxsem_init(&rdev->regulator_sem, 0, 1);
+  list_initialize(&rdev->consumer_list);
+  list_initialize(&rdev->list);
+
+  if (rdev->desc->boot_on && !_regulator_is_enabled(rdev))
+    {
+      _regulator_do_enable(rdev);
+    }
+  else if (!rdev->desc->boot_on && _regulator_is_enabled(rdev))
+    {
+      _regulator_do_disable(rdev);
+    }
+
+  if (rdev->desc->apply_uv)
+    {
+      _regulator_do_set_voltage(rdev, rdev->desc->apply_uv,
+                                rdev->desc->apply_uv);
+    }
+
+  nxsem_wait_uninterruptible(&g_reg_sem);
+  list_add_tail(&g_reg_list, &rdev->list);
+  nxsem_post(&g_reg_sem);
+
+  return rdev;
+}
+
+/****************************************************************************
+ * Name: regulator_unregister
+ *
+ * Description:
+ *   This routine is called by the specific regulator drivers to unregister a
+ *   regulator.
+ *
+ ****************************************************************************/
+
+void regulator_unregister(FAR struct regulator_dev_s *rdev)
+{
+  if (rdev == NULL)
+    {
+      return;
+    }
+
+  nxsem_wait_uninterruptible(&g_reg_sem);
+  if (rdev->open_count)
+    {
+      pwrerr("unregister, open %PRIu32\n", rdev->open_count);
+      nxsem_post(&g_reg_sem);
+      return;
+    }
+
+  list_delete(&rdev->list);
+  nxsem_post(&g_reg_sem);
+
+  kmm_free(rdev);
+}
diff --git a/include/nuttx/power/consumer.h b/include/nuttx/power/consumer.h
new file mode 100644
index 0000000..534a0a7
--- /dev/null
+++ b/include/nuttx/power/consumer.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+ * include/nuttx/power/consumer.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __INCLUDE_NUTTX_POWER_CONSUMER_H
+#define __INCLUDE_NUTTX_POWER_CONSUMER_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdbool.h>
+#include <semaphore.h>
+#include <nuttx/power/regulator.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#ifndef __ASSEMBLY__
+
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+FAR struct regulator_s *regulator_get(const char *id);
+void regulator_put(FAR struct regulator_s *regulator);
+int regulator_is_enabled(FAR struct regulator_s *regulator);
+int regulator_enable(FAR struct regulator_s *regulator);
+int regulator_disable(FAR struct regulator_s *regulator);
+int regulator_set_voltage(FAR struct regulator_s *regulator, int min_uv,
+                          int max_uv);
+int regulator_get_voltage(FAR struct regulator_s *regulator);
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ASSEMBLY__ */
+#endif /* __INCLUDE_NUTTX_POWER_CONSUMER_H */
diff --git a/include/nuttx/power/regulator.h b/include/nuttx/power/regulator.h
new file mode 100644
index 0000000..e1f41c0
--- /dev/null
+++ b/include/nuttx/power/regulator.h
@@ -0,0 +1,162 @@
+/****************************************************************************
+ * include/nuttx/power/regulator.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __INCLUDE_NUTTX_POWER_REGULATOR_H
+#define __INCLUDE_NUTTX_POWER_REGULATOR_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdbool.h>
+#include <semaphore.h>
+
+#include <nuttx/list.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+struct regulator_dev_s;
+
+struct regulator_s
+{
+  int min_uv;
+  int max_uv;
+  struct list_node list;
+  struct regulator_dev_s *rdev;
+};
+
+struct regulator_ops_s
+{
+  CODE int (*list_voltage)(FAR struct regulator_dev_s *rdev,
+                           unsigned selector);
+  CODE int (*set_voltage)(FAR struct regulator_dev_s *rdev, int min_uv,
+                          int max_uv, FAR unsigned *selector);
+  CODE int (*set_voltage_sel)(FAR struct regulator_dev_s *rdev,
+                              unsigned selector);
+  CODE int (*get_voltage)(FAR struct regulator_dev_s *rdev);
+  CODE int (*get_voltage_sel)(FAR struct regulator_dev_s *rdev);
+  CODE int (*enable)(FAR struct regulator_dev_s *rdev);
+  CODE int (*is_enabled)(FAR struct regulator_dev_s *rdev);
+  CODE int (*disable)(FAR struct regulator_dev_s *rdev);
+};
+
+/* This structure defines the regulator state structure */
+
+struct regulator_desc_s
+{
+  const char *name;
+  unsigned int n_voltages;
+  unsigned int vsel_reg;
+  unsigned int vsel_mask;
+  unsigned int enable_reg;
+  unsigned int enable_mask;
+  unsigned int enable_time;
+  unsigned int ramp_delay;
+  unsigned int uv_step;
+  unsigned int min_uv;
+  unsigned int max_uv;
+  unsigned int apply_uv;
+  bool boot_on;
+};
+
+struct regulator_dev_s
+{
+  FAR const struct regulator_desc_s *desc;
+  FAR const struct regulator_ops_s *ops;
+  uint32_t use_count;
+  uint32_t open_count;
+  sem_t regulator_sem;
+  struct list_node list;
+  struct list_node consumer_list;
+
+  FAR void *priv;
+};
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#ifndef __ASSEMBLY__
+
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: regulator_register
+ *
+ * Description:
+ *   Register a lower half regulator driver with the common, upper-half
+ *   regulator driver.
+ *
+ * Input parameters:
+ *   desc - The regulator descriptor struct.
+ *   ops  - The regulator operations pointer
+ *
+ * Returned value:
+ *    The pointer to struct regulator_dev_s on success or NULL on failure.
+ *
+ ****************************************************************************/
+
+struct regulator_dev_s *
+regulator_register(FAR const struct regulator_desc_s *desc,
+                   FAR const struct regulator_ops_s *ops,
+                   FAR void *priv);
+
+/****************************************************************************
+ * Name: regulator_unregister
+ *
+ * Description:
+ *   Unregister a lower half regulator driver with the common, upper-half
+ *   regulator driver.
+ *
+ * Input parameters:
+ *   rdev - The regulator dev pointer.
+ *
+ * Returned value:
+ *    N/A
+ *
+ ****************************************************************************/
+
+void regulator_unregister(FAR struct regulator_dev_s *rdev);
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ASSEMBLY__ */
+#endif /* __INCLUDE_NUTTX_POWER_REGULATOR_H */