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:12 UTC

[incubator-nuttx] branch master updated (bec9058 -> 3e8a3c9)

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

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


    from bec9058  arch: lc823450: Replace the critical section with spinlock in lc823450_serial.c
     new c8f1a9e  driver:power:add regulator framework
     new eed6510  driver:power:add regulator remote proc
     new b7db430  driver/power: add gpio regulator
     new 3e8a3c9  driver:regulator: add delay feature

The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 drivers/power/Kconfig                              |  28 +
 drivers/power/Make.defs                            |  30 +
 drivers/power/regulator.c                          | 833 +++++++++++++++++++++
 .../power/regulator_gpio.c                         | 173 ++---
 drivers/power/regulator_rpmsg.c                    | 619 +++++++++++++++
 .../esp32/chip.h => include/nuttx/power/consumer.h |  42 +-
 include/nuttx/power/regulator.h                    | 222 ++++++
 7 files changed, 1831 insertions(+), 116 deletions(-)
 create mode 100644 drivers/power/regulator.c
 copy arch/arm/src/sama5/sam_ethernet.c => drivers/power/regulator_gpio.c (51%)
 create mode 100644 drivers/power/regulator_rpmsg.c
 copy arch/xtensa/include/esp32/chip.h => include/nuttx/power/consumer.h (70%)
 create mode 100644 include/nuttx/power/regulator.h

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

Posted by xi...@apache.org.
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 */

[incubator-nuttx] 04/04: driver:regulator: add delay feature

Posted by xi...@apache.org.
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 3e8a3c9cc2ee6d6a1a10379991165fa6ff8ea66a
Author: zhuyanlin <zh...@xiaomi.com>
AuthorDate: Fri Dec 3 17:41:58 2021 +0800

    driver:regulator: add delay feature
    
    N/A
---
 drivers/power/regulator.c       | 60 ++++++++++++++++++++++++++++++++++++++---
 include/nuttx/power/consumer.h  |  2 ++
 include/nuttx/power/regulator.h |  2 ++
 3 files changed, 61 insertions(+), 3 deletions(-)

diff --git a/drivers/power/regulator.c b/drivers/power/regulator.c
index 1ee1b73..e097d73 100644
--- a/drivers/power/regulator.c
+++ b/drivers/power/regulator.c
@@ -33,6 +33,7 @@
 #include <nuttx/arch.h>
 #include <nuttx/kmalloc.h>
 #include <nuttx/power/regulator.h>
+#include <nuttx/signal.h>
 
 /****************************************************************************
  * Private Function Prototypes
@@ -526,14 +527,44 @@ int regulator_enable(FAR struct regulator_s *regulator)
       ret = _regulator_do_enable(rdev);
       if (ret < 0)
         {
-          return ret;
+          goto err;
         }
     }
 
   rdev->use_count++;
+
+err:
   nxsem_post(&rdev->regulator_sem);
 
-  return 0;
+  return ret;
+}
+
+/****************************************************************************
+ * Name: regulator_enable_delay
+ *
+ * Description:
+ *   Enable the regulator output.
+ *
+ * Input parameters:
+ *   regulator - The regulator consumer representative
+ *   ms        - The delay ms after regulator enable
+ *
+ * Returned value:
+ *   Zero on success or a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int regulator_enable_delay(FAR struct regulator_s *regulator, int ms)
+{
+  int ret;
+
+  ret = regulator_enable(regulator);
+  if (!ret)
+    {
+      nxsig_usleep(1000 * ms);
+    }
+
+  return ret;
 }
 
 /****************************************************************************
@@ -586,7 +617,30 @@ err:
   return ret;
 }
 
-  return 0;
+/****************************************************************************
+ * Name: regulator_disable_deferred
+ *
+ * Description:
+ *   Disable the regulator after ms.
+ *
+ * Input parameters:
+ *   regulator - The regulator consumer representative
+ *   ms        - The delay ms before disable regulator
+ *
+ * Returned value:
+ *   Zero on success or a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int regulator_disable_deferred(FAR struct regulator_s *regulator, int ms)
+{
+  if (!regulator)
+    {
+      return -EINVAL;
+    }
+
+  return work_queue(LPWORK, (FAR struct work_s *)&regulator,
+                   (worker_t)regulator_disable, regulator, MSEC2TICK(ms));
 }
 
 /****************************************************************************
diff --git a/include/nuttx/power/consumer.h b/include/nuttx/power/consumer.h
index 534a0a7..5c3c0d2 100644
--- a/include/nuttx/power/consumer.h
+++ b/include/nuttx/power/consumer.h
@@ -61,7 +61,9 @@ 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_enable_delay(FAR struct regulator_s *regulator, int ms);
 int regulator_disable(FAR struct regulator_s *regulator);
+int regulator_disable_deferred(FAR struct regulator_s *regulator, int ms);
 int regulator_set_voltage(FAR struct regulator_s *regulator, int min_uv,
                           int max_uv);
 int regulator_get_voltage(FAR struct regulator_s *regulator);
diff --git a/include/nuttx/power/regulator.h b/include/nuttx/power/regulator.h
index 32ae249..9809cd2 100644
--- a/include/nuttx/power/regulator.h
+++ b/include/nuttx/power/regulator.h
@@ -31,6 +31,7 @@
 #include <semaphore.h>
 
 #include <nuttx/list.h>
+#include <nuttx/wqueue.h>
 
 /****************************************************************************
  * Pre-processor Definitions
@@ -44,6 +45,7 @@ struct regulator_dev_s;
 
 struct regulator_s
 {
+  struct work_s disable_work;
   int min_uv;
   int max_uv;
   struct list_node list;

[incubator-nuttx] 02/04: driver:power:add regulator remote proc

Posted by xi...@apache.org.
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 eed651020263b58e4c1e36ec811f7b16d2dba52c
Author: zhuyanlin <zh...@xiaomi.com>
AuthorDate: Thu Nov 25 17:48:58 2021 +0800

    driver:power:add regulator remote proc
    
    N/A
    
    Signed-off-by: zhuyanlin <zh...@xiaomi.com>
---
 drivers/power/Kconfig           |   9 +
 drivers/power/Make.defs         |  10 +
 drivers/power/regulator.c       |   7 +
 drivers/power/regulator_rpmsg.c | 619 ++++++++++++++++++++++++++++++++++++++++
 include/nuttx/power/regulator.h |  36 +++
 5 files changed, 681 insertions(+)

diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 2ac5c04..3dee0d1 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -351,6 +351,15 @@ config REGULATOR
 		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 REGULATOR_RPMSG
+	bool "Regulator rpmsg driver support"
+	default n
+	---help---
+		The rpmsg regulator driver implements the common regulator APIs, inside which
+		the regulator operations are sent from the client to the remote device via
+		the rpmsg channel. The remote device(namely server) is responsible for
+		the parse and the completion.
+
 config BATTERY_CHARGER
 	bool "Battery Charger support"
 	default n
diff --git a/drivers/power/Make.defs b/drivers/power/Make.defs
index 07e0be8..4962ca1 100644
--- a/drivers/power/Make.defs
+++ b/drivers/power/Make.defs
@@ -81,6 +81,16 @@ POWER_CFLAGS := ${shell $(INCDIR) "$(CC)" $(TOPDIR)$(DELIM)drivers$(DELIM)power}
 
 endif
 
+ifeq ($(CONFIG_REGULATOR_RPMSG), y)
+
+CSRCS += regulator_rpmsg.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
index 3223530..1ee1b73 100644
--- a/drivers/power/regulator.c
+++ b/drivers/power/regulator.c
@@ -161,6 +161,13 @@ static FAR struct regulator_dev_s *regulator_dev_lookup(const char *supply)
 
   nxsem_post(&g_reg_sem);
 
+#if defined(CONFIG_REGULATOR_RPMSG)
+  if (rdev_found == NULL)
+    {
+      rdev_found = regulator_rpmsg_get(supply);
+    }
+#endif
+
   return rdev_found;
 }
 
diff --git a/drivers/power/regulator_rpmsg.c b/drivers/power/regulator_rpmsg.c
new file mode 100644
index 0000000..b0b2cd8
--- /dev/null
+++ b/drivers/power/regulator_rpmsg.c
@@ -0,0 +1,619 @@
+/****************************************************************************
+ * drivers/power/regulator_rpmsg.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 <errno.h>
+#include <semaphore.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <nuttx/kmalloc.h>
+#include <nuttx/list.h>
+#include <nuttx/power/consumer.h>
+#include <nuttx/rptun/openamp.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifndef ARRAY_SIZE
+#  define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#endif
+
+#define REGULATOR_RPMSG_EPT_NAME    "rpmsg-regulator"
+
+#define REGULATOR_RPMSG_ENABLE      0
+#define REGULATOR_RPMSG_DISABLE     1
+#define REGULATOR_RPMSG_GET_VOLTAGE 2
+#define REGULATOR_RPMSG_SET_VOLTAGE 3
+#define REGULATOR_RPMSG_IS_ENABLED  4
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+begin_packed_struct struct regulator_rpmsg_header_s
+{
+  uint32_t                          command : 31;
+  uint32_t                          response : 1;
+  int32_t                           result;
+  uint64_t                          cookie;
+} end_packed_struct;
+
+begin_packed_struct struct regulator_rpmsg_enable_s
+{
+  struct regulator_rpmsg_header_s   header;
+  char                              name[0];
+} end_packed_struct;
+
+#define regulator_rpmsg_disable_s   regulator_rpmsg_enable_s
+#define regulator_rpmsg_isenabled_s regulator_rpmsg_enable_s
+#define regulator_rpmsg_getvol_s    regulator_rpmsg_enable_s
+
+begin_packed_struct struct regulator_rpmsg_setvol_s
+{
+  struct regulator_rpmsg_header_s   header;
+  int32_t                           min_uv;
+  int32_t                           max_uv;
+  char                              name[0];
+} end_packed_struct;
+
+struct regulator_rpmsg_cookie_s
+{
+  int32_t                           result;
+  sem_t                             sem;
+};
+
+struct regulator_rpmsg_priv_s
+{
+  struct rpmsg_endpoint             ept;
+  FAR const char                   *cpuname;
+  struct list_node                  node;
+  struct list_node                  regulator_list;
+};
+
+struct regulator_rpmsg_s
+{
+  FAR struct regulator_s           *regulator;
+  struct list_node                  node;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int regulator_rpmsg_ept_cb(FAR struct rpmsg_endpoint *ept,
+                                  FAR void *data, size_t len,
+                                  uint32_t src, FAR void *priv_);
+
+static int regulator_rpmsg_enable_handler(FAR struct rpmsg_endpoint *ept,
+                                          FAR void *data, size_t len,
+                                          uint32_t src, FAR void *priv_);
+static int regulator_rpmsg_disable_handler(FAR struct rpmsg_endpoint *ept,
+                                           FAR void *data, size_t len,
+                                           uint32_t src, FAR void *priv_);
+static int regulator_rpmsg_getvol_handler(FAR struct rpmsg_endpoint *ept,
+                                          FAR void *data, size_t len,
+                                          uint32_t src, FAR void *priv_);
+static int regulator_rpmsg_setvol_handler(FAR struct rpmsg_endpoint *ept,
+                                          FAR void *data, size_t len,
+                                          uint32_t src, FAR void *priv_);
+static int regulator_rpmsg_isenabled_handler(FAR struct rpmsg_endpoint *ept,
+                                             FAR void *data, size_t len,
+                                             uint32_t src, FAR void *priv_);
+
+static int regulator_rpmsg_set_voltage(FAR struct regulator_dev_s *rdev,
+                                       int min_uv, int max_uv,
+                                       FAR unsigned *selector);
+static int regulator_rpmsg_get_voltage(FAR struct regulator_dev_s *rdev);
+static int regulator_rpmsg_enable(FAR struct regulator_dev_s *rdev);
+static int regulator_rpmsg_disable(FAR struct regulator_dev_s *rdev);
+static int regulator_rpmsg_is_enabled(FAR struct regulator_dev_s *rdev);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static mutex_t g_regulator_rpmsg_lock          =  MUTEX_INITIALIZER;
+static struct list_node g_regulator_rpmsg_priv =
+          LIST_INITIAL_VALUE(g_regulator_rpmsg_priv);
+
+static const rpmsg_ept_cb g_regulator_rpmsg_handler[] =
+{
+  [REGULATOR_RPMSG_ENABLE]      = regulator_rpmsg_enable_handler,
+  [REGULATOR_RPMSG_DISABLE]     = regulator_rpmsg_disable_handler,
+  [REGULATOR_RPMSG_GET_VOLTAGE] = regulator_rpmsg_getvol_handler,
+  [REGULATOR_RPMSG_SET_VOLTAGE] = regulator_rpmsg_setvol_handler,
+  [REGULATOR_RPMSG_IS_ENABLED]  = regulator_rpmsg_isenabled_handler,
+};
+
+static const struct regulator_ops_s g_regulator_rpmsg_ops =
+{
+  .set_voltage = regulator_rpmsg_set_voltage,
+  .get_voltage = regulator_rpmsg_get_voltage,
+  .enable      = regulator_rpmsg_enable,
+  .disable     = regulator_rpmsg_disable,
+  .is_enabled  = regulator_rpmsg_is_enabled,
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static struct regulator_rpmsg_priv_s *
+regulator_rpmsg_get_priv(FAR const char *name)
+{
+  FAR struct regulator_rpmsg_priv_s *priv;
+
+  nxmutex_lock(&g_regulator_rpmsg_lock);
+
+  list_for_every_entry(&g_regulator_rpmsg_priv, priv,
+                       struct regulator_rpmsg_priv_s, node)
+    {
+      size_t len = strlen(priv->cpuname);
+
+      if (!strncmp(priv->cpuname, name, len) &&
+         (name[len] == '/' || name[len] == 0))
+        {
+          goto out; /* Find the target, exit */
+        }
+    }
+
+  priv = NULL;
+
+out:
+  nxmutex_unlock(&g_regulator_rpmsg_lock);
+  return priv;
+}
+
+static struct rpmsg_endpoint *regulator_rpmsg_get_ept(FAR const char **name)
+{
+  FAR struct regulator_rpmsg_priv_s *priv;
+
+  priv = regulator_rpmsg_get_priv(*name);
+  if (priv == NULL)
+    {
+      return NULL;
+    }
+
+  *name += strlen(priv->cpuname) + 1;
+
+  return &priv->ept;
+}
+
+static FAR struct regulator_s *
+regulator_rpmsg_get_reg(FAR struct rpmsg_endpoint *ept, FAR const char *name)
+{
+  FAR struct regulator_rpmsg_priv_s *priv = ept->priv;
+  FAR struct list_node *regulator_list = &priv->regulator_list;
+  FAR struct regulator_rpmsg_s *reg;
+
+  list_for_every_entry(regulator_list, reg,
+                       struct regulator_rpmsg_s, node)
+    {
+       if (reg && !strcmp(reg->regulator->rdev->desc->name, name))
+         {
+           return reg->regulator;
+         }
+    }
+
+  reg = kmm_zalloc(sizeof(*reg));
+  if (!reg)
+    {
+      return NULL;
+    }
+
+  reg->regulator = regulator_get(name);
+  if (!reg->regulator)
+    {
+      kmm_free(reg);
+      return NULL;
+    }
+
+  list_add_head(regulator_list, &reg->node);
+
+  return reg->regulator;
+}
+
+static void regulator_rpmsg_device_created(struct rpmsg_device *rdev,
+                                           FAR void *priv_)
+{
+  FAR struct regulator_rpmsg_priv_s *priv;
+  int ret;
+
+  priv = kmm_zalloc(sizeof(struct regulator_rpmsg_priv_s));
+  if (!priv)
+    {
+      return;
+    }
+
+  priv->ept.priv = priv;
+  priv->cpuname  = rpmsg_get_cpuname(rdev);
+
+  list_initialize(&priv->regulator_list);
+  nxmutex_lock(&g_regulator_rpmsg_lock);
+  list_add_head(&g_regulator_rpmsg_priv, &priv->node);
+  nxmutex_unlock(&g_regulator_rpmsg_lock);
+
+  ret = rpmsg_create_ept(&priv->ept, rdev, REGULATOR_RPMSG_EPT_NAME,
+                         RPMSG_ADDR_ANY, RPMSG_ADDR_ANY,
+                         regulator_rpmsg_ept_cb, NULL);
+  if (ret)
+    {
+      free(priv);
+    }
+}
+
+static void regulator_rpmsg_device_destroy(struct rpmsg_device *rdev,
+                                           FAR void *priv_)
+{
+  FAR struct regulator_rpmsg_priv_s *priv;
+  FAR struct regulator_rpmsg_s *reg;
+
+  priv = regulator_rpmsg_get_priv(rpmsg_get_cpuname(rdev));
+
+  if (!priv)
+    {
+      return;
+    }
+
+  list_for_every_entry(&priv->regulator_list, reg,
+                       struct regulator_rpmsg_s, node)
+    {
+      while (regulator_is_enabled(reg->regulator))
+        {
+          regulator_disable(reg->regulator);
+        }
+
+      regulator_put(reg->regulator);
+      list_delete(&reg->node);
+      kmm_free(reg);
+    }
+
+  nxmutex_lock(&g_regulator_rpmsg_lock);
+  list_delete(&priv->node);
+  nxmutex_unlock(&g_regulator_rpmsg_lock);
+
+  rpmsg_destroy_ept(&priv->ept);
+  kmm_free(priv);
+}
+
+static int regulator_rpmsg_ept_cb(FAR struct rpmsg_endpoint *ept,
+                                  FAR void *data, size_t len,
+                                  uint32_t src, FAR void *priv_)
+{
+  FAR struct regulator_rpmsg_header_s *header = data;
+  uint32_t cmd = header->command;
+  int ret = -EINVAL;
+
+  struct regulator_rpmsg_cookie_s *cookie =
+              (struct regulator_rpmsg_cookie_s *)(uintptr_t)header->cookie;
+
+  if (cookie && header->response)
+    {
+      cookie->result = header->result;
+      nxsem_post(&cookie->sem);
+      ret = 0;
+    }
+  else if (cmd < ARRAY_SIZE(g_regulator_rpmsg_handler)
+           && g_regulator_rpmsg_handler[cmd])
+    {
+      header->response = 1;
+      ret = g_regulator_rpmsg_handler[cmd](ept, data, len, src, priv_);
+    }
+
+  return ret;
+}
+
+static int regulator_rpmsg_enable_handler(FAR struct rpmsg_endpoint *ept,
+                                          FAR void *data, size_t len,
+                                          uint32_t src, FAR void *priv_)
+{
+  FAR struct regulator_rpmsg_enable_s *msg = data;
+  FAR struct regulator_s *regulator =
+                        regulator_rpmsg_get_reg(ept, msg->name);
+
+  msg->header.result = regulator_enable(regulator);
+
+  return rpmsg_send(ept, data, len);
+}
+
+static int regulator_rpmsg_disable_handler(FAR struct rpmsg_endpoint *ept,
+                                           FAR void *data, size_t len,
+                                           uint32_t src, FAR void *priv_)
+{
+  FAR struct regulator_rpmsg_disable_s *msg = data;
+  FAR struct regulator_s *regulator =
+                        regulator_rpmsg_get_reg(ept, msg->name);
+
+  msg->header.result = regulator_disable(regulator);
+  return rpmsg_send(ept, data, len);
+}
+
+static int regulator_rpmsg_getvol_handler(FAR struct rpmsg_endpoint *ept,
+                                          FAR void *data, size_t len,
+                                          uint32_t src, FAR void *priv_)
+{
+  FAR struct regulator_rpmsg_getvol_s *msg = data;
+  FAR struct regulator_s *regulator =
+                        regulator_rpmsg_get_reg(ept, msg->name);
+
+  msg->header.result = regulator_get_voltage(regulator);
+
+  return rpmsg_send(ept, data, len);
+}
+
+static int regulator_rpmsg_setvol_handler(FAR struct rpmsg_endpoint *ept,
+                                          FAR void *data, size_t len,
+                                          uint32_t src, FAR void *priv_)
+{
+  FAR struct regulator_rpmsg_setvol_s *msg = data;
+  FAR struct regulator_s *regulator =
+                        regulator_rpmsg_get_reg(ept, msg->name);
+
+  msg->header.result =
+    regulator_set_voltage(regulator, msg->min_uv, msg->max_uv);
+
+  return rpmsg_send(ept, data, len);
+}
+
+static int regulator_rpmsg_isenabled_handler(FAR struct rpmsg_endpoint *ept,
+                                             FAR void *data, size_t len,
+                                             uint32_t src, FAR void *priv_)
+{
+  FAR struct regulator_rpmsg_isenabled_s *msg = data;
+  FAR struct regulator_s *regulator =
+                        regulator_rpmsg_get_reg(ept, msg->name);
+
+  msg->header.result = regulator_is_enabled(regulator);
+
+  return rpmsg_send(ept, data, len);
+}
+
+static int regulator_rpmsg_sendrecv(FAR struct rpmsg_endpoint *ept,
+                                    uint32_t command,
+                                    FAR struct regulator_rpmsg_header_s *msg,
+                                    int len)
+{
+  struct regulator_rpmsg_cookie_s cookie =
+    {
+      0
+    };
+
+  int ret;
+
+  nxsem_init(&cookie.sem, 0, 0);
+  nxsem_set_protocol(&cookie.sem, SEM_PRIO_NONE);
+
+  msg->command = command;
+  msg->response = 0;
+  msg->result = -ENXIO;
+  msg->cookie = (uintptr_t)&cookie;
+
+  ret = rpmsg_send_nocopy(ept, msg, len);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  ret = nxsem_wait_uninterruptible(&cookie.sem);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  return cookie.result;
+}
+
+static int regulator_rpmsg_enable(FAR struct regulator_dev_s *rdev)
+{
+  FAR struct rpmsg_endpoint *ept;
+  FAR struct regulator_rpmsg_enable_s *msg;
+  FAR const char *name = rdev->desc->name;
+  uint32_t len;
+
+  ept = regulator_rpmsg_get_ept(&name);
+  if (!ept)
+    {
+      return -ENODEV;
+    }
+
+  len = sizeof(*msg) + strlen(name) + 1;
+  msg = rpmsg_get_tx_payload_buffer(ept, &len, true);
+  if (!msg)
+    {
+      return -ENOMEM;
+    }
+
+  strcpy(msg->name, name);
+  return regulator_rpmsg_sendrecv(ept, REGULATOR_RPMSG_ENABLE,
+                                 (struct regulator_rpmsg_header_s *)msg,
+                                  len);
+}
+
+static int regulator_rpmsg_disable(FAR struct regulator_dev_s *rdev)
+{
+  FAR struct rpmsg_endpoint *ept;
+  FAR struct regulator_rpmsg_disable_s *msg;
+  FAR const char *name = rdev->desc->name;
+  uint32_t len;
+
+  ept = regulator_rpmsg_get_ept(&name);
+  if (!ept)
+    {
+      return -ENODEV;
+    }
+
+  len = sizeof(*msg) + strlen(name) + 1;
+  msg = rpmsg_get_tx_payload_buffer(ept, &len, true);
+  if (!msg)
+    {
+      return -ENOMEM;
+    }
+
+  strcpy(msg->name, name);
+  return regulator_rpmsg_sendrecv(ept, REGULATOR_RPMSG_DISABLE,
+                                 (struct regulator_rpmsg_header_s *)msg,
+                                 len);
+}
+
+static int regulator_rpmsg_set_voltage(FAR struct regulator_dev_s *rdev,
+                                       int min_uv, int max_uv,
+                                       FAR unsigned *selector)
+{
+  FAR struct rpmsg_endpoint *ept;
+  FAR struct regulator_rpmsg_setvol_s *msg;
+  FAR const char *name = rdev->desc->name;
+  uint32_t len;
+
+  ept = regulator_rpmsg_get_ept(&name);
+  if (!ept)
+    {
+      return -ENODEV;
+    }
+
+  len = sizeof(*msg) + strlen(name) + 1;
+  msg = rpmsg_get_tx_payload_buffer(ept, &len, true);
+  if (!msg)
+    {
+      return -ENOMEM;
+    }
+
+  strcpy(msg->name, name);
+  msg->min_uv = min_uv;
+  msg->max_uv = max_uv;
+
+  return regulator_rpmsg_sendrecv(ept, REGULATOR_RPMSG_SET_VOLTAGE,
+                                 (struct regulator_rpmsg_header_s *)msg,
+                                 len);
+}
+
+static int regulator_rpmsg_get_voltage(FAR struct regulator_dev_s *rdev)
+{
+  FAR struct rpmsg_endpoint *ept;
+  FAR struct regulator_rpmsg_getvol_s *msg;
+  FAR const char *name = rdev->desc->name;
+  uint32_t len;
+
+  ept = regulator_rpmsg_get_ept(&name);
+  if (!ept)
+    {
+      return -ENODEV;
+    }
+
+  len = sizeof(*msg) + strlen(name) + 1;
+  msg = rpmsg_get_tx_payload_buffer(ept, &len, true);
+  if (!msg)
+    {
+      return -ENOMEM;
+    }
+
+  strcpy(msg->name, name);
+  return regulator_rpmsg_sendrecv(ept, REGULATOR_RPMSG_GET_VOLTAGE,
+                                 (struct regulator_rpmsg_header_s *)msg,
+                                  len);
+}
+
+static int regulator_rpmsg_is_enabled(FAR struct regulator_dev_s *rdev)
+{
+  FAR struct rpmsg_endpoint *ept;
+  FAR struct regulator_rpmsg_isenabled_s *msg;
+  FAR const char *name = rdev->desc->name;
+  uint32_t len;
+
+  ept = regulator_rpmsg_get_ept(&name);
+  if (!ept)
+    {
+      return -ENODEV;
+    }
+
+  len = sizeof(*msg) + strlen(name) + 1;
+  msg = rpmsg_get_tx_payload_buffer(ept, &len, true);
+  if (!msg)
+    {
+      return -ENOMEM;
+    }
+
+  strcpy(msg->name, name);
+  return regulator_rpmsg_sendrecv(ept, REGULATOR_RPMSG_IS_ENABLED,
+                                 (struct regulator_rpmsg_header_s *)msg,
+                                  len);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: regulator_rpmsg_get
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   name - the name for register the rpmsg regulator dev
+ *
+ * Returned Value:
+ *
+ *   Regulator dev pointer
+ *
+ ****************************************************************************/
+
+FAR struct regulator_dev_s *regulator_rpmsg_get(FAR const char *name)
+{
+  FAR struct regulator_desc_s *desc;
+
+  desc = kmm_zalloc(sizeof(struct regulator_desc_s));
+  if (!desc)
+    {
+      return NULL;
+    }
+
+  desc->name = name;
+
+  return regulator_register(desc, &g_regulator_rpmsg_ops, NULL);
+}
+
+/****************************************************************************
+ * Name: regulator_rpmsg_init
+ *
+ * Description:
+ *
+ *   Establish rpmsg channel for the operations of the remote regulator
+ *
+ * Input Parameters:
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+int regulator_rpmsg_init(void)
+{
+  return rpmsg_register_callback(NULL,
+                                 regulator_rpmsg_device_created,
+                                 regulator_rpmsg_device_destroy,
+                                 NULL);
+}
diff --git a/include/nuttx/power/regulator.h b/include/nuttx/power/regulator.h
index e1f41c0..cff3c23 100644
--- a/include/nuttx/power/regulator.h
+++ b/include/nuttx/power/regulator.h
@@ -153,6 +153,42 @@ regulator_register(FAR const struct regulator_desc_s *desc,
 
 void regulator_unregister(FAR struct regulator_dev_s *rdev);
 
+#if defined(CONFIG_REGULATOR_RPMSG)
+
+/****************************************************************************
+ * Name: regulator_rpmsg_get
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   name - the name for register the rpmsg regulator dev
+ *
+ * Returned Value:
+ *
+ *   Regulator dev pointer
+ *
+ ****************************************************************************/
+
+FAR struct regulator_dev_s *regulator_rpmsg_get(FAR const char *name);
+
+/****************************************************************************
+ * Name: regulator_rpmsg_init
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ * Returned Value:
+ *
+ *   Zero (OK) on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+int regulator_rpmsg_init(void);
+
+#endif
+
 #undef EXTERN
 #ifdef __cplusplus
 }

[incubator-nuttx] 03/04: driver/power: add gpio regulator

Posted by xi...@apache.org.
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 b7db4304d675895d069dfa57bc9bd67f0f1f6be6
Author: zhuyanlin <zh...@xiaomi.com>
AuthorDate: Thu Dec 2 10:36:49 2021 +0800

    driver/power: add gpio regulator
    
    N/A
    
    Signed-off-by: zhuyanlin <zh...@xiaomi.com>
---
 drivers/power/Kconfig           |  11 +++
 drivers/power/Make.defs         |  10 +++
 drivers/power/regulator_gpio.c  | 150 ++++++++++++++++++++++++++++++++++++++++
 include/nuttx/power/regulator.h |  22 ++++++
 4 files changed, 193 insertions(+)

diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 3dee0d1..eb1a3d4 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -360,6 +360,17 @@ config REGULATOR_RPMSG
 		the rpmsg channel. The remote device(namely server) is responsible for
 		the parse and the completion.
 
+if REGULATOR
+
+config REGULATOR_GPIO
+	bool "Regulator gpio driver support"
+	default n
+	---help---
+		The regulator gpio driver implements the lower regulator ops that use gpio to
+		control to regulator.
+
+endif
+
 config BATTERY_CHARGER
 	bool "Battery Charger support"
 	default n
diff --git a/drivers/power/Make.defs b/drivers/power/Make.defs
index 4962ca1..39636dc 100644
--- a/drivers/power/Make.defs
+++ b/drivers/power/Make.defs
@@ -91,6 +91,16 @@ POWER_CFLAGS := ${shell $(INCDIR) "$(CC)" $(TOPDIR)$(DELIM)drivers$(DELIM)power}
 
 endif
 
+ifeq ($(CONFIG_REGULATOR_GPIO), y)
+
+CSRCS += regulator_gpio.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_gpio.c b/drivers/power/regulator_gpio.c
new file mode 100644
index 0000000..4d92389
--- /dev/null
+++ b/drivers/power/regulator_gpio.c
@@ -0,0 +1,150 @@
+/****************************************************************************
+ * drivers/power/regulator_gpio.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 <errno.h>
+
+#include <nuttx/ioexpander/ioexpander.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/power/regulator.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private
+ ****************************************************************************/
+
+struct regulator_gpio_priv
+{
+  FAR struct ioexpander_dev_s *iodev;
+  FAR struct regulator_dev_s  *rdev;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int regulator_gpio_enable(FAR struct regulator_dev_s *rdev);
+static int regulator_gpio_disable(FAR struct regulator_dev_s *rdev);
+static int regulator_gpio_is_enabled(FAR struct regulator_dev_s *rdev);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct regulator_ops_s g_regulator_gpio_ops =
+{
+  .enable      = regulator_gpio_enable,
+  .disable     = regulator_gpio_disable,
+  .is_enabled  = regulator_gpio_is_enabled,
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static int regulator_gpio_enable(FAR struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_gpio_priv *priv = rdev->priv;
+
+  return IOEXP_WRITEPIN(priv->iodev, rdev->desc->enable_reg,
+                        !!rdev->desc->enable_mask);
+}
+
+static int regulator_gpio_disable(FAR struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_gpio_priv *priv = rdev->priv;
+
+  return IOEXP_WRITEPIN(priv->iodev, rdev->desc->enable_reg,
+                        !rdev->desc->enable_mask);
+}
+
+static int regulator_gpio_is_enabled(FAR struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_gpio_priv *priv = rdev->priv;
+  bool val;
+
+  if (!IOEXP_READPIN(priv->iodev, rdev->desc->enable_reg, &val))
+    {
+      return val ^ !rdev->desc->enable_mask;
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: regulator_gpio_init
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   iodev  - The ioexpander dev pointer.
+ *   desc   - The regulator desc pointer, must contain follow section
+ *            name          - The regulator name.
+ *            enable_reg    - The regulator gpio pin number.
+ *            enable_mask   -
+ *                            true : enable is high, disable is low
+ *                            false: enable is low,  disable is high
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+int regulator_gpio_init(FAR struct ioexpander_dev_s *iodev,
+                        FAR const struct regulator_desc_s *desc)
+{
+  FAR struct regulator_gpio_priv *priv;
+
+  if (!iodev || !desc)
+    {
+      return -EINVAL;
+    }
+
+  priv = kmm_zalloc(sizeof(struct regulator_gpio_priv));
+  if (!priv)
+    {
+      return -ENOMEM;
+    }
+
+  priv->iodev = iodev;
+  priv->rdev = regulator_register(desc, &g_regulator_gpio_ops,
+                                  priv);
+  if (!priv->rdev)
+    {
+      kmm_free(priv);
+      return -EINVAL;
+    }
+
+  return 0;
+}
diff --git a/include/nuttx/power/regulator.h b/include/nuttx/power/regulator.h
index cff3c23..32ae249 100644
--- a/include/nuttx/power/regulator.h
+++ b/include/nuttx/power/regulator.h
@@ -153,6 +153,28 @@ regulator_register(FAR const struct regulator_desc_s *desc,
 
 void regulator_unregister(FAR struct regulator_dev_s *rdev);
 
+/****************************************************************************
+ * Name: regulator_gpio_init
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   iodev  - The ioexpander dev pointer.
+ *   desc   - The regulator desc pointer, must contain follow section
+ *            name          - The regulator name.
+ *            enable_reg    - The regulator gpio pin number.
+ *            enable_mask   -
+ *                            true : enable is high, disable is low
+ *                            false: enable is low,  disable is high
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+int regulator_gpio_init(FAR struct ioexpander_dev_s *iodev,
+                        FAR const struct regulator_desc_s *desc);
+
 #if defined(CONFIG_REGULATOR_RPMSG)
 
 /****************************************************************************