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(®ulator->list);
+
+ nxsem_wait_uninterruptible(&rdev->regulator_sem);
+ rdev->open_count++;
+ list_add_tail(&rdev->consumer_list, ®ulator->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(®ulator->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 */