You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by GitBox <gi...@apache.org> on 2023/01/11 17:03:17 UTC

[GitHub] [nuttx] TimJTi opened a new pull request, #8088: Add ACT8945A power driver

TimJTi opened a new pull request, #8088:
URL: https://github.com/apache/nuttx/pull/8088

   ## Summary
   Adds device driver for Qorvo ACT8945A regulator. No battery charger or interrupt support at this time.
   
   Created as a draft because:
   
   1) This is possibly the first NuttX driver using the power/consumer/regulator model - I had nothing to base it on
   2) I am unsure if the spin_lock calls (needed when an independent battery charge driver is written as it "shares" the same I2C interface to the device) are in the right place
   3) The usual feedback needing corrections is expected
   
   ## Impact
   None expected
   
   ## Testing
   On custom board using SAMA5D27C-D1M processor using this regulator.
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [nuttx] xiaoxiang781216 commented on a diff in pull request #8088: Add ACT8945A power driver

Posted by GitBox <gi...@apache.org>.
xiaoxiang781216 commented on code in PR #8088:
URL: https://github.com/apache/nuttx/pull/8088#discussion_r1068463144


##########
drivers/power/supply/regulator_gpio.c:
##########
@@ -65,7 +65,9 @@ static const struct regulator_ops_s g_regulator_gpio_ops =
   NULL,                         /* get_voltage_sel */
   regulator_gpio_enable,        /* enable */
   regulator_gpio_is_enabled,    /* is_enabled */
-  regulator_gpio_disable        /* disable */
+  regulator_gpio_disable,       /* disable */
+  NULL,                         /* enable pulldown  if reg. disabled */

Review Comment:
   revert don't need change



##########
drivers/power/supply/regulator.c:
##########
@@ -236,6 +238,32 @@ static int _regulator_get_voltage(FAR struct regulator_dev_s *rdev)
   return ret;
 }
 
+static int _regulator_do_enable_pulldown(FAR struct regulator_dev_s *rdev)
+{
+  int ret;

Review Comment:
     int ret = 0;
   
     if (rdev->ops->enable_pulldown)
       {
         ret = rdev->ops->enable_pulldown(rdev);
         if (ret < 0)
           {
             pwrerr("failed to enable pulldown\n");
           }
       }
   
     return ret;
   



##########
drivers/power/supply/regulator.c:
##########
@@ -236,6 +238,32 @@ static int _regulator_get_voltage(FAR struct regulator_dev_s *rdev)
   return ret;
 }
 
+static int _regulator_do_enable_pulldown(FAR struct regulator_dev_s *rdev)
+{
+  int ret;
+
+  ret = rdev->ops->enable_pulldown(rdev);
+  if (ret < 0)
+    {
+      pwrerr("failed to get enable pulldown\n");
+    }
+
+  return ret;
+}
+
+static int _regulator_do_disable_pulldown(FAR struct regulator_dev_s *rdev)
+{
+  int ret;
+
+  ret = rdev->ops->disable_pulldown(rdev);

Review Comment:
   ditto



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [nuttx] TimJTi commented on a diff in pull request #8088: Add ACT8945A power driver

Posted by GitBox <gi...@apache.org>.
TimJTi commented on code in PR #8088:
URL: https://github.com/apache/nuttx/pull/8088#discussion_r1068271486


##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control enabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_disable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->pulldown_reg, &regval))
+    {
+      regval &= ~regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control disabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_write_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   value    - The value to write to the 4 scratch bits
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value)
+{
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, &regval))
+    {
+      regval &= ~ACT8945A_SCRATCH_MASK;
+      regval |= value & ACT8945A_SCRATCH_MASK;
+      if (!act8945a_putreg(priv, ACT8945A_SYS1, regval))
+        {
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_read_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev    - The regulator device pointer.
+ *   scratch - pointer to the scratch value read
+ *
+ * Returned Value: The scratch value read, and success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t *scratch)
+{
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, scratch))
+    {
+      return OK;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_set_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector to use for the regulator
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_set_voltage_sel(struct regulator_dev_s *rdev,
+                                    unsigned selector)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  if (selector >= ACT8945A_NUM_VOLTAGES)
+    {
+      return -EINVAL;
+    }
+  else
+    {
+      if (!act8945a_putreg(priv, regulator->vsel_reg,
+                           selector & regulator->vsel_mask))
+        {
+          pwrinfo("INFO: reg %s set to %d mV using selector %d \n",
+                   regulator->name, mv_list[selector], selector);
+          return OK;
+        }
+      else
+        {
+          return -EIO;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_get_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: The current selector from the device, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_get_voltage_sel(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      return regval;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      regval |= regulator->enable_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: reg %s enabled\n", regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_is_enabled
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Whether enabled or disabled, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_is_enabled(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      return (regval & regulator->enable_mask);
+    }
+  else
+    {
+      return -ENODEV;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_disable
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      regval &= ~regulator->enable_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: reg %s disabled\n", regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int act8945a_initialize(FAR struct i2c_master_s *i2c, unsigned int vsel)
+{
+  FAR struct regulator_act8945a_priv *priv;
+
+  uint8_t scratch;
+  int regnum;
+
+  DEBUGASSERT(vsel != 0 && vsel != 1);
+
+  if (!i2c)
+    {
+      return -EINVAL;

Review Comment:
   agreed. Done.



##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control enabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_disable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->pulldown_reg, &regval))
+    {
+      regval &= ~regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control disabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_write_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   value    - The value to write to the 4 scratch bits
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value)
+{
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, &regval))
+    {
+      regval &= ~ACT8945A_SCRATCH_MASK;
+      regval |= value & ACT8945A_SCRATCH_MASK;
+      if (!act8945a_putreg(priv, ACT8945A_SYS1, regval))
+        {
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_read_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev    - The regulator device pointer.
+ *   scratch - pointer to the scratch value read
+ *
+ * Returned Value: The scratch value read, and success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t *scratch)
+{
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, scratch))
+    {
+      return OK;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_set_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector to use for the regulator
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_set_voltage_sel(struct regulator_dev_s *rdev,
+                                    unsigned selector)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  if (selector >= ACT8945A_NUM_VOLTAGES)
+    {
+      return -EINVAL;
+    }
+  else
+    {
+      if (!act8945a_putreg(priv, regulator->vsel_reg,
+                           selector & regulator->vsel_mask))
+        {
+          pwrinfo("INFO: reg %s set to %d mV using selector %d \n",
+                   regulator->name, mv_list[selector], selector);
+          return OK;
+        }
+      else
+        {
+          return -EIO;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_get_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: The current selector from the device, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_get_voltage_sel(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      return regval;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      regval |= regulator->enable_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: reg %s enabled\n", regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_is_enabled
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Whether enabled or disabled, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_is_enabled(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      return (regval & regulator->enable_mask);
+    }
+  else
+    {
+      return -ENODEV;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_disable
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      regval &= ~regulator->enable_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: reg %s disabled\n", regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int act8945a_initialize(FAR struct i2c_master_s *i2c, unsigned int vsel)
+{
+  FAR struct regulator_act8945a_priv *priv;
+
+  uint8_t scratch;
+  int regnum;
+
+  DEBUGASSERT(vsel != 0 && vsel != 1);
+
+  if (!i2c)
+    {
+      return -EINVAL;
+    }
+
+  priv = kmm_zalloc(sizeof(struct regulator_act8945a_priv));
+
+  if (!priv)
+    {
+      return -ENOMEM;
+    }
+
+  priv->i2c      = i2c;
+  priv->i2c_addr = ACT8945A_SLAVE_ADDRESS;
+  priv->i2c_freq = ACT8945A_BUS_SPEED;
+
+  /* Early test to see if we can read the ACT8945A.
+   *
+   * We do this by writing a data pattern into the 4 scratch bits of SYS1
+   * register and making sure we can read it back OK.
+   */
+
+  if (!act8945a_write_scratch(priv, SCRATCH_TEST_VAL))

Review Comment:
   done



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [nuttx] acassis commented on a diff in pull request #8088: Add ACT8945A power driver

Posted by GitBox <gi...@apache.org>.
acassis commented on code in PR #8088:
URL: https://github.com/apache/nuttx/pull/8088#discussion_r1068110806


##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.

Review Comment:
   Please move the Returned Value's comment to the new line, following the style it good because in the future we can create some script to create documentation automatically from it.



##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *

Review Comment:
   Please add input parameters and return values



##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control enabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_disable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->pulldown_reg, &regval))
+    {
+      regval &= ~regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control disabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_write_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   value    - The value to write to the 4 scratch bits
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value)
+{
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, &regval))
+    {
+      regval &= ~ACT8945A_SCRATCH_MASK;
+      regval |= value & ACT8945A_SCRATCH_MASK;
+      if (!act8945a_putreg(priv, ACT8945A_SYS1, regval))
+        {
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_read_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev    - The regulator device pointer.
+ *   scratch - pointer to the scratch value read
+ *
+ * Returned Value: The scratch value read, and success or error code.

Review Comment:
   Ditto



##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control enabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_disable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->pulldown_reg, &regval))
+    {
+      regval &= ~regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control disabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_write_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   value    - The value to write to the 4 scratch bits
+ *
+ * Returned Value: Success or error code.

Review Comment:
   Ditto



##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control enabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_disable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->pulldown_reg, &regval))
+    {
+      regval &= ~regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control disabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_write_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   value    - The value to write to the 4 scratch bits
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value)
+{
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, &regval))
+    {
+      regval &= ~ACT8945A_SCRATCH_MASK;
+      regval |= value & ACT8945A_SCRATCH_MASK;
+      if (!act8945a_putreg(priv, ACT8945A_SYS1, regval))
+        {
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_read_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev    - The regulator device pointer.
+ *   scratch - pointer to the scratch value read
+ *
+ * Returned Value: The scratch value read, and success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t *scratch)
+{
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, scratch))

Review Comment:
   Please use comparison with value 0x00 because getreg() doesn't return boolean



##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control enabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_disable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->pulldown_reg, &regval))
+    {
+      regval &= ~regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control disabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_write_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   value    - The value to write to the 4 scratch bits
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value)
+{
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, &regval))
+    {
+      regval &= ~ACT8945A_SCRATCH_MASK;
+      regval |= value & ACT8945A_SCRATCH_MASK;
+      if (!act8945a_putreg(priv, ACT8945A_SYS1, regval))

Review Comment:
   Ditto



##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control enabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_disable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->pulldown_reg, &regval))
+    {
+      regval &= ~regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control disabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_write_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   value    - The value to write to the 4 scratch bits
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value)
+{
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, &regval))
+    {
+      regval &= ~ACT8945A_SCRATCH_MASK;
+      regval |= value & ACT8945A_SCRATCH_MASK;
+      if (!act8945a_putreg(priv, ACT8945A_SYS1, regval))
+        {
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_read_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev    - The regulator device pointer.
+ *   scratch - pointer to the scratch value read
+ *
+ * Returned Value: The scratch value read, and success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t *scratch)
+{
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, scratch))
+    {
+      return OK;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_set_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector to use for the regulator
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_set_voltage_sel(struct regulator_dev_s *rdev,
+                                    unsigned selector)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  if (selector >= ACT8945A_NUM_VOLTAGES)
+    {
+      return -EINVAL;
+    }
+  else
+    {
+      if (!act8945a_putreg(priv, regulator->vsel_reg,
+                           selector & regulator->vsel_mask))
+        {
+          pwrinfo("INFO: reg %s set to %d mV using selector %d \n",
+                   regulator->name, mv_list[selector], selector);
+          return OK;
+        }
+      else
+        {
+          return -EIO;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_get_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: The current selector from the device, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_get_voltage_sel(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      return regval;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))

Review Comment:
   Ditto



##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control enabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_disable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->pulldown_reg, &regval))
+    {
+      regval &= ~regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control disabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_write_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   value    - The value to write to the 4 scratch bits
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value)
+{
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, &regval))
+    {
+      regval &= ~ACT8945A_SCRATCH_MASK;
+      regval |= value & ACT8945A_SCRATCH_MASK;
+      if (!act8945a_putreg(priv, ACT8945A_SYS1, regval))
+        {
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_read_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev    - The regulator device pointer.
+ *   scratch - pointer to the scratch value read
+ *
+ * Returned Value: The scratch value read, and success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t *scratch)
+{
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, scratch))
+    {
+      return OK;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_set_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector to use for the regulator
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_set_voltage_sel(struct regulator_dev_s *rdev,
+                                    unsigned selector)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  if (selector >= ACT8945A_NUM_VOLTAGES)
+    {
+      return -EINVAL;
+    }
+  else
+    {
+      if (!act8945a_putreg(priv, regulator->vsel_reg,
+                           selector & regulator->vsel_mask))
+        {
+          pwrinfo("INFO: reg %s set to %d mV using selector %d \n",
+                   regulator->name, mv_list[selector], selector);
+          return OK;
+        }
+      else
+        {
+          return -EIO;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_get_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: The current selector from the device, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_get_voltage_sel(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      return regval;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      regval |= regulator->enable_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: reg %s enabled\n", regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_is_enabled
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Whether enabled or disabled, or error code.

Review Comment:
   Ditto



##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control enabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_disable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->pulldown_reg, &regval))
+    {
+      regval &= ~regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control disabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_write_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   value    - The value to write to the 4 scratch bits
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value)
+{
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, &regval))
+    {
+      regval &= ~ACT8945A_SCRATCH_MASK;
+      regval |= value & ACT8945A_SCRATCH_MASK;
+      if (!act8945a_putreg(priv, ACT8945A_SYS1, regval))
+        {
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_read_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev    - The regulator device pointer.
+ *   scratch - pointer to the scratch value read
+ *
+ * Returned Value: The scratch value read, and success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t *scratch)
+{
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, scratch))
+    {
+      return OK;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_set_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector to use for the regulator
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_set_voltage_sel(struct regulator_dev_s *rdev,
+                                    unsigned selector)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  if (selector >= ACT8945A_NUM_VOLTAGES)
+    {
+      return -EINVAL;
+    }
+  else
+    {
+      if (!act8945a_putreg(priv, regulator->vsel_reg,
+                           selector & regulator->vsel_mask))
+        {
+          pwrinfo("INFO: reg %s set to %d mV using selector %d \n",
+                   regulator->name, mv_list[selector], selector);
+          return OK;
+        }
+      else
+        {
+          return -EIO;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_get_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: The current selector from the device, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_get_voltage_sel(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      return regval;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      regval |= regulator->enable_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: reg %s enabled\n", regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_is_enabled
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Whether enabled or disabled, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_is_enabled(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      return (regval & regulator->enable_mask);
+    }
+  else
+    {
+      return -ENODEV;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_disable
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success, or error code.

Review Comment:
   Ditto



##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *

Review Comment:
   Please add input parameters and return values
   



##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.

Review Comment:
   Ditto: move Returned Value comment to new line instead putting everything in a single line.



##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control enabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_disable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->pulldown_reg, &regval))

Review Comment:
   Ditto



##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control enabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_disable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->pulldown_reg, &regval))
+    {
+      regval &= ~regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control disabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_write_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   value    - The value to write to the 4 scratch bits
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value)
+{
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, &regval))
+    {
+      regval &= ~ACT8945A_SCRATCH_MASK;
+      regval |= value & ACT8945A_SCRATCH_MASK;
+      if (!act8945a_putreg(priv, ACT8945A_SYS1, regval))
+        {
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_read_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev    - The regulator device pointer.
+ *   scratch - pointer to the scratch value read
+ *
+ * Returned Value: The scratch value read, and success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t *scratch)
+{
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, scratch))
+    {
+      return OK;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_set_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector to use for the regulator
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_set_voltage_sel(struct regulator_dev_s *rdev,
+                                    unsigned selector)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  if (selector >= ACT8945A_NUM_VOLTAGES)
+    {
+      return -EINVAL;
+    }
+  else
+    {
+      if (!act8945a_putreg(priv, regulator->vsel_reg,
+                           selector & regulator->vsel_mask))
+        {
+          pwrinfo("INFO: reg %s set to %d mV using selector %d \n",
+                   regulator->name, mv_list[selector], selector);
+          return OK;
+        }
+      else
+        {
+          return -EIO;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_get_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: The current selector from the device, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_get_voltage_sel(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      return regval;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      regval |= regulator->enable_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: reg %s enabled\n", regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_is_enabled
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Whether enabled or disabled, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_is_enabled(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      return (regval & regulator->enable_mask);
+    }
+  else
+    {
+      return -ENODEV;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_disable
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      regval &= ~regulator->enable_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: reg %s disabled\n", regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int act8945a_initialize(FAR struct i2c_master_s *i2c, unsigned int vsel)
+{
+  FAR struct regulator_act8945a_priv *priv;
+
+  uint8_t scratch;
+  int regnum;
+
+  DEBUGASSERT(vsel != 0 && vsel != 1);
+
+  if (!i2c)
+    {
+      return -EINVAL;
+    }
+
+  priv = kmm_zalloc(sizeof(struct regulator_act8945a_priv));
+
+  if (!priv)
+    {
+      return -ENOMEM;
+    }
+
+  priv->i2c      = i2c;
+  priv->i2c_addr = ACT8945A_SLAVE_ADDRESS;
+  priv->i2c_freq = ACT8945A_BUS_SPEED;
+
+  /* Early test to see if we can read the ACT8945A.
+   *
+   * We do this by writing a data pattern into the 4 scratch bits of SYS1
+   * register and making sure we can read it back OK.
+   */
+
+  if (!act8945a_write_scratch(priv, SCRATCH_TEST_VAL))
+    {
+      if (!act8945a_read_scratch(priv, &scratch))

Review Comment:
   Ditto



##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))

Review Comment:
   Same here, act8945a_putreg doesn't return boolean, use value comparison



##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control enabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_disable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->pulldown_reg, &regval))
+    {
+      regval &= ~regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control disabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_write_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   value    - The value to write to the 4 scratch bits
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value)
+{
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, &regval))

Review Comment:
   Ditto



##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control enabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_disable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.

Review Comment:
   Ditto



##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control enabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_disable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->pulldown_reg, &regval))
+    {
+      regval &= ~regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control disabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_write_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   value    - The value to write to the 4 scratch bits
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value)
+{
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, &regval))
+    {
+      regval &= ~ACT8945A_SCRATCH_MASK;
+      regval |= value & ACT8945A_SCRATCH_MASK;
+      if (!act8945a_putreg(priv, ACT8945A_SYS1, regval))
+        {
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_read_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev    - The regulator device pointer.
+ *   scratch - pointer to the scratch value read
+ *
+ * Returned Value: The scratch value read, and success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t *scratch)
+{
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, scratch))
+    {
+      return OK;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_set_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector to use for the regulator
+ *
+ * Returned Value: Success or error code.

Review Comment:
   Ditto



##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control enabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_disable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->pulldown_reg, &regval))
+    {
+      regval &= ~regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control disabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_write_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   value    - The value to write to the 4 scratch bits
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value)
+{
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, &regval))
+    {
+      regval &= ~ACT8945A_SCRATCH_MASK;
+      regval |= value & ACT8945A_SCRATCH_MASK;
+      if (!act8945a_putreg(priv, ACT8945A_SYS1, regval))
+        {
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_read_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev    - The regulator device pointer.
+ *   scratch - pointer to the scratch value read
+ *
+ * Returned Value: The scratch value read, and success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t *scratch)
+{
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, scratch))
+    {
+      return OK;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_set_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector to use for the regulator
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_set_voltage_sel(struct regulator_dev_s *rdev,
+                                    unsigned selector)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  if (selector >= ACT8945A_NUM_VOLTAGES)
+    {
+      return -EINVAL;
+    }
+  else
+    {
+      if (!act8945a_putreg(priv, regulator->vsel_reg,

Review Comment:
   Ditto



##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control enabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_disable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->pulldown_reg, &regval))
+    {
+      regval &= ~regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control disabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_write_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   value    - The value to write to the 4 scratch bits
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value)
+{
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, &regval))
+    {
+      regval &= ~ACT8945A_SCRATCH_MASK;
+      regval |= value & ACT8945A_SCRATCH_MASK;
+      if (!act8945a_putreg(priv, ACT8945A_SYS1, regval))
+        {
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_read_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev    - The regulator device pointer.
+ *   scratch - pointer to the scratch value read
+ *
+ * Returned Value: The scratch value read, and success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t *scratch)
+{
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, scratch))
+    {
+      return OK;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_set_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector to use for the regulator
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_set_voltage_sel(struct regulator_dev_s *rdev,
+                                    unsigned selector)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  if (selector >= ACT8945A_NUM_VOLTAGES)
+    {
+      return -EINVAL;
+    }
+  else
+    {
+      if (!act8945a_putreg(priv, regulator->vsel_reg,
+                           selector & regulator->vsel_mask))
+        {
+          pwrinfo("INFO: reg %s set to %d mV using selector %d \n",
+                   regulator->name, mv_list[selector], selector);
+          return OK;
+        }
+      else
+        {
+          return -EIO;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_get_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: The current selector from the device, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_get_voltage_sel(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))

Review Comment:
   Ditto



##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control enabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_disable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->pulldown_reg, &regval))
+    {
+      regval &= ~regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control disabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_write_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   value    - The value to write to the 4 scratch bits
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value)
+{
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, &regval))
+    {
+      regval &= ~ACT8945A_SCRATCH_MASK;
+      regval |= value & ACT8945A_SCRATCH_MASK;
+      if (!act8945a_putreg(priv, ACT8945A_SYS1, regval))
+        {
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_read_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev    - The regulator device pointer.
+ *   scratch - pointer to the scratch value read
+ *
+ * Returned Value: The scratch value read, and success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t *scratch)
+{
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, scratch))
+    {
+      return OK;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_set_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector to use for the regulator
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_set_voltage_sel(struct regulator_dev_s *rdev,
+                                    unsigned selector)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  if (selector >= ACT8945A_NUM_VOLTAGES)
+    {
+      return -EINVAL;
+    }
+  else
+    {
+      if (!act8945a_putreg(priv, regulator->vsel_reg,
+                           selector & regulator->vsel_mask))
+        {
+          pwrinfo("INFO: reg %s set to %d mV using selector %d \n",
+                   regulator->name, mv_list[selector], selector);
+          return OK;
+        }
+      else
+        {
+          return -EIO;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_get_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: The current selector from the device, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_get_voltage_sel(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      return regval;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      regval |= regulator->enable_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))

Review Comment:
   Ditto



##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control enabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_disable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->pulldown_reg, &regval))
+    {
+      regval &= ~regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control disabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_write_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   value    - The value to write to the 4 scratch bits
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value)
+{
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, &regval))
+    {
+      regval &= ~ACT8945A_SCRATCH_MASK;
+      regval |= value & ACT8945A_SCRATCH_MASK;
+      if (!act8945a_putreg(priv, ACT8945A_SYS1, regval))
+        {
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_read_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev    - The regulator device pointer.
+ *   scratch - pointer to the scratch value read
+ *
+ * Returned Value: The scratch value read, and success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t *scratch)
+{
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, scratch))
+    {
+      return OK;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_set_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector to use for the regulator
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_set_voltage_sel(struct regulator_dev_s *rdev,
+                                    unsigned selector)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  if (selector >= ACT8945A_NUM_VOLTAGES)
+    {
+      return -EINVAL;
+    }
+  else
+    {
+      if (!act8945a_putreg(priv, regulator->vsel_reg,
+                           selector & regulator->vsel_mask))
+        {
+          pwrinfo("INFO: reg %s set to %d mV using selector %d \n",
+                   regulator->name, mv_list[selector], selector);
+          return OK;
+        }
+      else
+        {
+          return -EIO;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_get_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: The current selector from the device, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_get_voltage_sel(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      return regval;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      regval |= regulator->enable_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: reg %s enabled\n", regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_is_enabled
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Whether enabled or disabled, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_is_enabled(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      return (regval & regulator->enable_mask);
+    }
+  else
+    {
+      return -ENODEV;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_disable
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      regval &= ~regulator->enable_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))

Review Comment:
   Ditto



##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control enabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_disable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->pulldown_reg, &regval))
+    {
+      regval &= ~regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control disabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_write_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   value    - The value to write to the 4 scratch bits
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value)
+{
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, &regval))
+    {
+      regval &= ~ACT8945A_SCRATCH_MASK;
+      regval |= value & ACT8945A_SCRATCH_MASK;
+      if (!act8945a_putreg(priv, ACT8945A_SYS1, regval))
+        {
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_read_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev    - The regulator device pointer.
+ *   scratch - pointer to the scratch value read
+ *
+ * Returned Value: The scratch value read, and success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t *scratch)
+{
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, scratch))
+    {
+      return OK;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_set_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector to use for the regulator
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_set_voltage_sel(struct regulator_dev_s *rdev,
+                                    unsigned selector)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  if (selector >= ACT8945A_NUM_VOLTAGES)
+    {
+      return -EINVAL;
+    }
+  else
+    {
+      if (!act8945a_putreg(priv, regulator->vsel_reg,
+                           selector & regulator->vsel_mask))
+        {
+          pwrinfo("INFO: reg %s set to %d mV using selector %d \n",
+                   regulator->name, mv_list[selector], selector);
+          return OK;
+        }
+      else
+        {
+          return -EIO;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_get_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: The current selector from the device, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_get_voltage_sel(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      return regval;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      regval |= regulator->enable_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: reg %s enabled\n", regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_is_enabled
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Whether enabled or disabled, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_is_enabled(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      return (regval & regulator->enable_mask);
+    }
+  else
+    {
+      return -ENODEV;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_disable
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))

Review Comment:
   Ditto



##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control enabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_disable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->pulldown_reg, &regval))
+    {
+      regval &= ~regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control disabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_write_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   value    - The value to write to the 4 scratch bits
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value)
+{
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, &regval))
+    {
+      regval &= ~ACT8945A_SCRATCH_MASK;
+      regval |= value & ACT8945A_SCRATCH_MASK;
+      if (!act8945a_putreg(priv, ACT8945A_SYS1, regval))
+        {
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_read_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev    - The regulator device pointer.
+ *   scratch - pointer to the scratch value read
+ *
+ * Returned Value: The scratch value read, and success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t *scratch)
+{
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, scratch))
+    {
+      return OK;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_set_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector to use for the regulator
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_set_voltage_sel(struct regulator_dev_s *rdev,
+                                    unsigned selector)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  if (selector >= ACT8945A_NUM_VOLTAGES)
+    {
+      return -EINVAL;
+    }
+  else
+    {
+      if (!act8945a_putreg(priv, regulator->vsel_reg,
+                           selector & regulator->vsel_mask))
+        {
+          pwrinfo("INFO: reg %s set to %d mV using selector %d \n",
+                   regulator->name, mv_list[selector], selector);
+          return OK;
+        }
+      else
+        {
+          return -EIO;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_get_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: The current selector from the device, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_get_voltage_sel(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      return regval;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      regval |= regulator->enable_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: reg %s enabled\n", regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_is_enabled
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Whether enabled or disabled, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_is_enabled(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))

Review Comment:
   Ditto



##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control enabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_disable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->pulldown_reg, &regval))
+    {
+      regval &= ~regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control disabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_write_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   value    - The value to write to the 4 scratch bits
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value)
+{
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, &regval))
+    {
+      regval &= ~ACT8945A_SCRATCH_MASK;
+      regval |= value & ACT8945A_SCRATCH_MASK;
+      if (!act8945a_putreg(priv, ACT8945A_SYS1, regval))
+        {
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_read_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev    - The regulator device pointer.
+ *   scratch - pointer to the scratch value read
+ *
+ * Returned Value: The scratch value read, and success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t *scratch)
+{
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, scratch))
+    {
+      return OK;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_set_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector to use for the regulator
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_set_voltage_sel(struct regulator_dev_s *rdev,
+                                    unsigned selector)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  if (selector >= ACT8945A_NUM_VOLTAGES)
+    {
+      return -EINVAL;
+    }
+  else
+    {
+      if (!act8945a_putreg(priv, regulator->vsel_reg,
+                           selector & regulator->vsel_mask))
+        {
+          pwrinfo("INFO: reg %s set to %d mV using selector %d \n",
+                   regulator->name, mv_list[selector], selector);
+          return OK;
+        }
+      else
+        {
+          return -EIO;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_get_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: The current selector from the device, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_get_voltage_sel(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      return regval;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      regval |= regulator->enable_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: reg %s enabled\n", regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_is_enabled
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Whether enabled or disabled, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_is_enabled(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      return (regval & regulator->enable_mask);
+    }
+  else
+    {
+      return -ENODEV;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_disable
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      regval &= ~regulator->enable_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: reg %s disabled\n", regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int act8945a_initialize(FAR struct i2c_master_s *i2c, unsigned int vsel)
+{
+  FAR struct regulator_act8945a_priv *priv;
+
+  uint8_t scratch;
+  int regnum;
+
+  DEBUGASSERT(vsel != 0 && vsel != 1);
+
+  if (!i2c)
+    {
+      return -EINVAL;

Review Comment:
   Maybe -ENODEV return is more meaningful in this case



##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control enabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_disable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->pulldown_reg, &regval))
+    {
+      regval &= ~regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control disabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_write_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   value    - The value to write to the 4 scratch bits
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value)
+{
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, &regval))
+    {
+      regval &= ~ACT8945A_SCRATCH_MASK;
+      regval |= value & ACT8945A_SCRATCH_MASK;
+      if (!act8945a_putreg(priv, ACT8945A_SYS1, regval))
+        {
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_read_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev    - The regulator device pointer.
+ *   scratch - pointer to the scratch value read
+ *
+ * Returned Value: The scratch value read, and success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t *scratch)
+{
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, scratch))
+    {
+      return OK;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_set_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector to use for the regulator
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_set_voltage_sel(struct regulator_dev_s *rdev,
+                                    unsigned selector)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  if (selector >= ACT8945A_NUM_VOLTAGES)
+    {
+      return -EINVAL;
+    }
+  else
+    {
+      if (!act8945a_putreg(priv, regulator->vsel_reg,
+                           selector & regulator->vsel_mask))
+        {
+          pwrinfo("INFO: reg %s set to %d mV using selector %d \n",
+                   regulator->name, mv_list[selector], selector);
+          return OK;
+        }
+      else
+        {
+          return -EIO;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_get_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: The current selector from the device, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_get_voltage_sel(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      return regval;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      regval |= regulator->enable_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: reg %s enabled\n", regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_is_enabled
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Whether enabled or disabled, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_is_enabled(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      return (regval & regulator->enable_mask);
+    }
+  else
+    {
+      return -ENODEV;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_disable
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      regval &= ~regulator->enable_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: reg %s disabled\n", regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int act8945a_initialize(FAR struct i2c_master_s *i2c, unsigned int vsel)
+{
+  FAR struct regulator_act8945a_priv *priv;
+
+  uint8_t scratch;
+  int regnum;
+
+  DEBUGASSERT(vsel != 0 && vsel != 1);
+
+  if (!i2c)
+    {
+      return -EINVAL;
+    }
+
+  priv = kmm_zalloc(sizeof(struct regulator_act8945a_priv));
+
+  if (!priv)
+    {
+      return -ENOMEM;
+    }
+
+  priv->i2c      = i2c;
+  priv->i2c_addr = ACT8945A_SLAVE_ADDRESS;
+  priv->i2c_freq = ACT8945A_BUS_SPEED;
+
+  /* Early test to see if we can read the ACT8945A.
+   *
+   * We do this by writing a data pattern into the 4 scratch bits of SYS1
+   * register and making sure we can read it back OK.
+   */
+
+  if (!act8945a_write_scratch(priv, SCRATCH_TEST_VAL))

Review Comment:
   Ditto



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [nuttx] TimJTi commented on a diff in pull request #8088: Add ACT8945A power driver

Posted by GitBox <gi...@apache.org>.
TimJTi commented on code in PR #8088:
URL: https://github.com/apache/nuttx/pull/8088#discussion_r1068271819


##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control enabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_disable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->pulldown_reg, &regval))
+    {
+      regval &= ~regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control disabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_write_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   value    - The value to write to the 4 scratch bits
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value)
+{
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, &regval))
+    {
+      regval &= ~ACT8945A_SCRATCH_MASK;
+      regval |= value & ACT8945A_SCRATCH_MASK;
+      if (!act8945a_putreg(priv, ACT8945A_SYS1, regval))
+        {
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_read_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev    - The regulator device pointer.
+ *   scratch - pointer to the scratch value read
+ *
+ * Returned Value: The scratch value read, and success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t *scratch)
+{
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, scratch))
+    {
+      return OK;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_set_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector to use for the regulator
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_set_voltage_sel(struct regulator_dev_s *rdev,
+                                    unsigned selector)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  if (selector >= ACT8945A_NUM_VOLTAGES)
+    {
+      return -EINVAL;
+    }
+  else
+    {
+      if (!act8945a_putreg(priv, regulator->vsel_reg,
+                           selector & regulator->vsel_mask))
+        {
+          pwrinfo("INFO: reg %s set to %d mV using selector %d \n",
+                   regulator->name, mv_list[selector], selector);
+          return OK;
+        }
+      else
+        {
+          return -EIO;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_get_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: The current selector from the device, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_get_voltage_sel(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      return regval;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      regval |= regulator->enable_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: reg %s enabled\n", regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_is_enabled
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Whether enabled or disabled, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_is_enabled(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      return (regval & regulator->enable_mask);
+    }
+  else
+    {
+      return -ENODEV;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_disable
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      regval &= ~regulator->enable_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: reg %s disabled\n", regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int act8945a_initialize(FAR struct i2c_master_s *i2c, unsigned int vsel)
+{
+  FAR struct regulator_act8945a_priv *priv;
+
+  uint8_t scratch;
+  int regnum;
+
+  DEBUGASSERT(vsel != 0 && vsel != 1);
+
+  if (!i2c)
+    {
+      return -EINVAL;
+    }
+
+  priv = kmm_zalloc(sizeof(struct regulator_act8945a_priv));
+
+  if (!priv)
+    {
+      return -ENOMEM;
+    }
+
+  priv->i2c      = i2c;
+  priv->i2c_addr = ACT8945A_SLAVE_ADDRESS;
+  priv->i2c_freq = ACT8945A_BUS_SPEED;
+
+  /* Early test to see if we can read the ACT8945A.
+   *
+   * We do this by writing a data pattern into the 4 scratch bits of SYS1
+   * register and making sure we can read it back OK.
+   */
+
+  if (!act8945a_write_scratch(priv, SCRATCH_TEST_VAL))
+    {
+      if (!act8945a_read_scratch(priv, &scratch))

Review Comment:
   done



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [nuttx] TimJTi commented on a diff in pull request #8088: Add ACT8945A power driver

Posted by "TimJTi (via GitHub)" <gi...@apache.org>.
TimJTi commented on code in PR #8088:
URL: https://github.com/apache/nuttx/pull/8088#discussion_r1088309783


##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,1081 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_SYSTRST_MASK                     (0x80)
+#define ACT8945A_SYSMODE_MASK                     (0x40)
+#define ACT8945A_SYSLEV_MASK                      (0x0f)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_TRST_64
+#  define ACT8945A_TRST                           (0x80) /* 64ms*/
+#else
+#  define ACT8945A_TRST                           (0)    /* 260ms */
+#endif
+
+#ifdef CONFIG_ACT8945A_SYSLEV_MODE_INTERRUPT
+#  define ACT8945A_SYSLEV_MODE                    (0x40) /* Interrupt */
+#else
+#  define ACT8945A_SYSLEV_MODE                    (0)    /* Shutdown */
+#endif
+
+#if defined(CONFIG_ACT8945A_SYSLEV_2300)
+#  define ACT8945A_SYSLEV 0
+#elif defined(CONFIG_ACT8945A_SYSLEV_2400)
+#  define ACT8945A_SYSLEV 1
+#elif defined(CONFIG_ACT8945A_SYSLEV_2500)
+#  define ACT8945A_SYSLEV 2
+#elif defined(CONFIG_ACT8945A_SYSLEV_2600)
+#  define ACT8945A_SYSLEV 3
+#elif defined(CONFIG_ACT8945A_SYSLEV_2700)
+#  define ACT8945A_SYSLEV 4
+#elif defined(CONFIG_ACT8945A_SYSLEV_2800)
+#  define ACT8945A_SYSLEV 5
+#elif defined(CONFIG_ACT8945A_SYSLEV_2900)
+#  define ACT8945A_SYSLEV 6
+#elif defined(CONFIG_ACT8945A_SYSLEV_3000)
+#  define ACT8945A_SYSLEV 7
+#elif defined(CONFIG_ACT8945A_SYSLEV_3100)
+#  define ACT8945A_SYSLEV 8
+#elif defined(CONFIG_ACT8945A_SYSLEV_3200)
+#  define ACT8945A_SYSLEV 9
+#elif defined(CONFIG_ACT8945A_SYSLEV_3300)
+#  define ACT8945A_SYSLEV 10
+#elif defined(CONFIG_ACT8945A_SYSLEV_3400)
+#  define ACT8945A_SYSLEV 11
+#elif defined(CONFIG_ACT8945A_SYSLEV_3500)
+#  define ACT8945A_SYSLEV 12
+#elif defined(CONFIG_ACT8945A_SYSLEV_3600)
+#  define ACT8945A_SYSLEV 13
+#elif defined(CONFIG_ACT8945A_SYSLEV_3700)
+#  define ACT8945A_SYSLEV 14
+#elif defined(CONFIG_ACT8945A_SYSLEV_3800)
+#  define ACT8945A_SYSLEV 15
+#else
+#  error No act8945a sys level detect threshold defined
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }

Review Comment:
   Which of this is C89 incompatible? I was so pleased to have eventually worked out how the ## worked, after seeing it on an Android driver, that I just had to use it!



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [nuttx] TimJTi commented on a diff in pull request #8088: Add ACT8945A power driver

Posted by GitBox <gi...@apache.org>.
TimJTi commented on code in PR #8088:
URL: https://github.com/apache/nuttx/pull/8088#discussion_r1069539632


##########
drivers/power/supply/regulator.c:
##########
@@ -236,6 +238,32 @@ static int _regulator_get_voltage(FAR struct regulator_dev_s *rdev)
   return ret;
 }
 
+static int _regulator_do_enable_pulldown(FAR struct regulator_dev_s *rdev)
+{
+  int ret;

Review Comment:
   done



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [nuttx] acassis commented on pull request #8088: Add ACT8945A power driver

Posted by GitBox <gi...@apache.org>.
acassis commented on PR #8088:
URL: https://github.com/apache/nuttx/pull/8088#issuecomment-1380358558

   Hi @TimJTi your drive seems in good shape, only simple/small fixes. After that you can remove the Draft flag


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [nuttx] TimJTi commented on a diff in pull request #8088: Add ACT8945A power driver

Posted by GitBox <gi...@apache.org>.
TimJTi commented on code in PR #8088:
URL: https://github.com/apache/nuttx/pull/8088#discussion_r1068260072


##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.

Review Comment:
   done



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [nuttx] TimJTi commented on a diff in pull request #8088: Add ACT8945A power driver

Posted by GitBox <gi...@apache.org>.
TimJTi commented on code in PR #8088:
URL: https://github.com/apache/nuttx/pull/8088#discussion_r1068509330


##########
drivers/power/supply/regulator_gpio.c:
##########
@@ -65,7 +65,9 @@ static const struct regulator_ops_s g_regulator_gpio_ops =
   NULL,                         /* get_voltage_sel */
   regulator_gpio_enable,        /* enable */
   regulator_gpio_is_enabled,    /* is_enabled */
-  regulator_gpio_disable        /* disable */
+  regulator_gpio_disable,       /* disable */
+  NULL,                         /* enable pulldown  if reg. disabled */

Review Comment:
   It's not a revert though unless I'm missing something? The original file didn't have the last 2 NULLs and the struct's last line was without the comma. As I added the two extra NULLs as this driver doesn't have the pulldown methods I added the comma.
   
   Or is it something else?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [nuttx] TimJTi commented on a diff in pull request #8088: Add ACT8945A power driver

Posted by GitBox <gi...@apache.org>.
TimJTi commented on code in PR #8088:
URL: https://github.com/apache/nuttx/pull/8088#discussion_r1068569223


##########
drivers/power/supply/regulator_gpio.c:
##########
@@ -65,7 +65,9 @@ static const struct regulator_ops_s g_regulator_gpio_ops =
   NULL,                         /* get_voltage_sel */
   regulator_gpio_enable,        /* enable */
   regulator_gpio_is_enabled,    /* is_enabled */
-  regulator_gpio_disable        /* disable */
+  regulator_gpio_disable,       /* disable */
+  NULL,                         /* enable pulldown  if reg. disabled */

Review Comment:
   Isn't it better to include them for completeness now? It's not wrong as such and means this driver matches the header file? Or is there some knock-on effect that I don't know of?
   
   Happy either way.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [nuttx] TimJTi commented on a diff in pull request #8088: Add ACT8945A power driver

Posted by GitBox <gi...@apache.org>.
TimJTi commented on code in PR #8088:
URL: https://github.com/apache/nuttx/pull/8088#discussion_r1068268850


##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control enabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_disable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->pulldown_reg, &regval))
+    {
+      regval &= ~regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control disabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_write_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   value    - The value to write to the 4 scratch bits
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value)
+{
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, &regval))
+    {
+      regval &= ~ACT8945A_SCRATCH_MASK;
+      regval |= value & ACT8945A_SCRATCH_MASK;
+      if (!act8945a_putreg(priv, ACT8945A_SYS1, regval))

Review Comment:
   done



##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control enabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_disable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->pulldown_reg, &regval))
+    {
+      regval &= ~regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control disabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_write_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   value    - The value to write to the 4 scratch bits
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value)
+{
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, &regval))
+    {
+      regval &= ~ACT8945A_SCRATCH_MASK;
+      regval |= value & ACT8945A_SCRATCH_MASK;
+      if (!act8945a_putreg(priv, ACT8945A_SYS1, regval))
+        {
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_read_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev    - The regulator device pointer.
+ *   scratch - pointer to the scratch value read
+ *
+ * Returned Value: The scratch value read, and success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t *scratch)
+{
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, scratch))
+    {
+      return OK;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_set_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector to use for the regulator
+ *
+ * Returned Value: Success or error code.

Review Comment:
   done



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [nuttx] TimJTi commented on a diff in pull request #8088: Add ACT8945A power driver

Posted by GitBox <gi...@apache.org>.
TimJTi commented on code in PR #8088:
URL: https://github.com/apache/nuttx/pull/8088#discussion_r1068261726


##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control enabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_disable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->pulldown_reg, &regval))
+    {
+      regval &= ~regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control disabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_write_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   value    - The value to write to the 4 scratch bits
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value)
+{
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, &regval))
+    {
+      regval &= ~ACT8945A_SCRATCH_MASK;
+      regval |= value & ACT8945A_SCRATCH_MASK;
+      if (!act8945a_putreg(priv, ACT8945A_SYS1, regval))
+        {
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_read_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev    - The regulator device pointer.
+ *   scratch - pointer to the scratch value read
+ *
+ * Returned Value: The scratch value read, and success or error code.

Review Comment:
   done



##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control enabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_disable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->pulldown_reg, &regval))
+    {
+      regval &= ~regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control disabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_write_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   value    - The value to write to the 4 scratch bits
+ *
+ * Returned Value: Success or error code.

Review Comment:
   done



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [nuttx] TimJTi commented on a diff in pull request #8088: Add ACT8945A power driver

Posted by GitBox <gi...@apache.org>.
TimJTi commented on code in PR #8088:
URL: https://github.com/apache/nuttx/pull/8088#discussion_r1068261155


##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control enabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_disable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.

Review Comment:
   done



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [nuttx] TimJTi commented on a diff in pull request #8088: Add ACT8945A power driver

Posted by GitBox <gi...@apache.org>.
TimJTi commented on code in PR #8088:
URL: https://github.com/apache/nuttx/pull/8088#discussion_r1068269103


##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control enabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_disable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->pulldown_reg, &regval))
+    {
+      regval &= ~regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control disabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_write_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   value    - The value to write to the 4 scratch bits
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value)
+{
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, &regval))
+    {
+      regval &= ~ACT8945A_SCRATCH_MASK;
+      regval |= value & ACT8945A_SCRATCH_MASK;
+      if (!act8945a_putreg(priv, ACT8945A_SYS1, regval))
+        {
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_read_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev    - The regulator device pointer.
+ *   scratch - pointer to the scratch value read
+ *
+ * Returned Value: The scratch value read, and success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t *scratch)
+{
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, scratch))
+    {
+      return OK;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_set_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector to use for the regulator
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_set_voltage_sel(struct regulator_dev_s *rdev,
+                                    unsigned selector)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  if (selector >= ACT8945A_NUM_VOLTAGES)
+    {
+      return -EINVAL;
+    }
+  else
+    {
+      if (!act8945a_putreg(priv, regulator->vsel_reg,

Review Comment:
   done



##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control enabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_disable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->pulldown_reg, &regval))
+    {
+      regval &= ~regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control disabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_write_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   value    - The value to write to the 4 scratch bits
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value)
+{
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, &regval))
+    {
+      regval &= ~ACT8945A_SCRATCH_MASK;
+      regval |= value & ACT8945A_SCRATCH_MASK;
+      if (!act8945a_putreg(priv, ACT8945A_SYS1, regval))
+        {
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_read_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev    - The regulator device pointer.
+ *   scratch - pointer to the scratch value read
+ *
+ * Returned Value: The scratch value read, and success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t *scratch)
+{
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, scratch))
+    {
+      return OK;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_set_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector to use for the regulator
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_set_voltage_sel(struct regulator_dev_s *rdev,
+                                    unsigned selector)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  if (selector >= ACT8945A_NUM_VOLTAGES)
+    {
+      return -EINVAL;
+    }
+  else
+    {
+      if (!act8945a_putreg(priv, regulator->vsel_reg,
+                           selector & regulator->vsel_mask))
+        {
+          pwrinfo("INFO: reg %s set to %d mV using selector %d \n",
+                   regulator->name, mv_list[selector], selector);
+          return OK;
+        }
+      else
+        {
+          return -EIO;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_get_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: The current selector from the device, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_get_voltage_sel(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))

Review Comment:
   done



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [nuttx] pkarashchenko commented on a diff in pull request #8088: Add ACT8945A power driver

Posted by "pkarashchenko (via GitHub)" <gi...@apache.org>.
pkarashchenko commented on code in PR #8088:
URL: https://github.com/apache/nuttx/pull/8088#discussion_r1088431637


##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,1081 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_SYSTRST_MASK                     (0x80)
+#define ACT8945A_SYSMODE_MASK                     (0x40)
+#define ACT8945A_SYSLEV_MASK                      (0x0f)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_TRST_64
+#  define ACT8945A_TRST                           (0x80) /* 64ms*/
+#else
+#  define ACT8945A_TRST                           (0)    /* 260ms */
+#endif
+
+#ifdef CONFIG_ACT8945A_SYSLEV_MODE_INTERRUPT
+#  define ACT8945A_SYSLEV_MODE                    (0x40) /* Interrupt */
+#else
+#  define ACT8945A_SYSLEV_MODE                    (0)    /* Shutdown */
+#endif
+
+#if defined(CONFIG_ACT8945A_SYSLEV_2300)
+#  define ACT8945A_SYSLEV 0
+#elif defined(CONFIG_ACT8945A_SYSLEV_2400)
+#  define ACT8945A_SYSLEV 1
+#elif defined(CONFIG_ACT8945A_SYSLEV_2500)
+#  define ACT8945A_SYSLEV 2
+#elif defined(CONFIG_ACT8945A_SYSLEV_2600)
+#  define ACT8945A_SYSLEV 3
+#elif defined(CONFIG_ACT8945A_SYSLEV_2700)
+#  define ACT8945A_SYSLEV 4
+#elif defined(CONFIG_ACT8945A_SYSLEV_2800)
+#  define ACT8945A_SYSLEV 5
+#elif defined(CONFIG_ACT8945A_SYSLEV_2900)
+#  define ACT8945A_SYSLEV 6
+#elif defined(CONFIG_ACT8945A_SYSLEV_3000)
+#  define ACT8945A_SYSLEV 7
+#elif defined(CONFIG_ACT8945A_SYSLEV_3100)
+#  define ACT8945A_SYSLEV 8
+#elif defined(CONFIG_ACT8945A_SYSLEV_3200)
+#  define ACT8945A_SYSLEV 9
+#elif defined(CONFIG_ACT8945A_SYSLEV_3300)
+#  define ACT8945A_SYSLEV 10
+#elif defined(CONFIG_ACT8945A_SYSLEV_3400)
+#  define ACT8945A_SYSLEV 11
+#elif defined(CONFIG_ACT8945A_SYSLEV_3500)
+#  define ACT8945A_SYSLEV 12
+#elif defined(CONFIG_ACT8945A_SYSLEV_3600)
+#  define ACT8945A_SYSLEV 13
+#elif defined(CONFIG_ACT8945A_SYSLEV_3700)
+#  define ACT8945A_SYSLEV 14
+#elif defined(CONFIG_ACT8945A_SYSLEV_3800)
+#  define ACT8945A_SYSLEV 15
+#else
+#  error No act8945a sys level detect threshold defined
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }

Review Comment:
   designated initializer is C99



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [nuttx] TimJTi commented on a diff in pull request #8088: Add ACT8945A power driver

Posted by "TimJTi (via GitHub)" <gi...@apache.org>.
TimJTi commented on code in PR #8088:
URL: https://github.com/apache/nuttx/pull/8088#discussion_r1126387513


##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,1081 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_SYSTRST_MASK                     (0x80)
+#define ACT8945A_SYSMODE_MASK                     (0x40)
+#define ACT8945A_SYSLEV_MASK                      (0x0f)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_TRST_64
+#  define ACT8945A_TRST                           (0x80) /* 64ms*/
+#else
+#  define ACT8945A_TRST                           (0)    /* 260ms */
+#endif
+
+#ifdef CONFIG_ACT8945A_SYSLEV_MODE_INTERRUPT
+#  define ACT8945A_SYSLEV_MODE                    (0x40) /* Interrupt */
+#else
+#  define ACT8945A_SYSLEV_MODE                    (0)    /* Shutdown */
+#endif
+
+#if defined(CONFIG_ACT8945A_SYSLEV_2300)
+#  define ACT8945A_SYSLEV 0
+#elif defined(CONFIG_ACT8945A_SYSLEV_2400)
+#  define ACT8945A_SYSLEV 1
+#elif defined(CONFIG_ACT8945A_SYSLEV_2500)
+#  define ACT8945A_SYSLEV 2
+#elif defined(CONFIG_ACT8945A_SYSLEV_2600)
+#  define ACT8945A_SYSLEV 3
+#elif defined(CONFIG_ACT8945A_SYSLEV_2700)
+#  define ACT8945A_SYSLEV 4
+#elif defined(CONFIG_ACT8945A_SYSLEV_2800)
+#  define ACT8945A_SYSLEV 5
+#elif defined(CONFIG_ACT8945A_SYSLEV_2900)
+#  define ACT8945A_SYSLEV 6
+#elif defined(CONFIG_ACT8945A_SYSLEV_3000)
+#  define ACT8945A_SYSLEV 7
+#elif defined(CONFIG_ACT8945A_SYSLEV_3100)
+#  define ACT8945A_SYSLEV 8
+#elif defined(CONFIG_ACT8945A_SYSLEV_3200)
+#  define ACT8945A_SYSLEV 9
+#elif defined(CONFIG_ACT8945A_SYSLEV_3300)
+#  define ACT8945A_SYSLEV 10
+#elif defined(CONFIG_ACT8945A_SYSLEV_3400)
+#  define ACT8945A_SYSLEV 11
+#elif defined(CONFIG_ACT8945A_SYSLEV_3500)
+#  define ACT8945A_SYSLEV 12
+#elif defined(CONFIG_ACT8945A_SYSLEV_3600)
+#  define ACT8945A_SYSLEV 13
+#elif defined(CONFIG_ACT8945A_SYSLEV_3700)
+#  define ACT8945A_SYSLEV 14
+#elif defined(CONFIG_ACT8945A_SYSLEV_3800)
+#  define ACT8945A_SYSLEV 15
+#else
+#  error No act8945a sys level detect threshold defined
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }

Review Comment:
   See #8742 



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [nuttx] TimJTi commented on a diff in pull request #8088: Add ACT8945A power driver

Posted by GitBox <gi...@apache.org>.
TimJTi commented on code in PR #8088:
URL: https://github.com/apache/nuttx/pull/8088#discussion_r1068259355


##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *

Review Comment:
   done



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [nuttx] xiaoxiang781216 commented on a diff in pull request #8088: Add ACT8945A power driver

Posted by GitBox <gi...@apache.org>.
xiaoxiang781216 commented on code in PR #8088:
URL: https://github.com/apache/nuttx/pull/8088#discussion_r1068582765


##########
drivers/power/supply/regulator_gpio.c:
##########
@@ -65,7 +65,9 @@ static const struct regulator_ops_s g_regulator_gpio_ops =
   NULL,                         /* get_voltage_sel */
   regulator_gpio_enable,        /* enable */
   regulator_gpio_is_enabled,    /* is_enabled */
-  regulator_gpio_disable        /* disable */
+  regulator_gpio_disable,       /* disable */
+  NULL,                         /* enable pulldown  if reg. disabled */

Review Comment:
   Since there are patches to remove the unnecessary initialization: https://github.com/apache/nuttx/pull/8016



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [nuttx] TimJTi commented on a diff in pull request #8088: Add ACT8945A power driver

Posted by GitBox <gi...@apache.org>.
TimJTi commented on code in PR #8088:
URL: https://github.com/apache/nuttx/pull/8088#discussion_r1068269417


##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control enabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_disable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->pulldown_reg, &regval))
+    {
+      regval &= ~regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control disabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_write_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   value    - The value to write to the 4 scratch bits
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value)
+{
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, &regval))
+    {
+      regval &= ~ACT8945A_SCRATCH_MASK;
+      regval |= value & ACT8945A_SCRATCH_MASK;
+      if (!act8945a_putreg(priv, ACT8945A_SYS1, regval))
+        {
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_read_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev    - The regulator device pointer.
+ *   scratch - pointer to the scratch value read
+ *
+ * Returned Value: The scratch value read, and success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t *scratch)
+{
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, scratch))
+    {
+      return OK;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_set_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector to use for the regulator
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_set_voltage_sel(struct regulator_dev_s *rdev,
+                                    unsigned selector)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  if (selector >= ACT8945A_NUM_VOLTAGES)
+    {
+      return -EINVAL;
+    }
+  else
+    {
+      if (!act8945a_putreg(priv, regulator->vsel_reg,
+                           selector & regulator->vsel_mask))
+        {
+          pwrinfo("INFO: reg %s set to %d mV using selector %d \n",
+                   regulator->name, mv_list[selector], selector);
+          return OK;
+        }
+      else
+        {
+          return -EIO;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_get_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: The current selector from the device, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_get_voltage_sel(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      return regval;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))

Review Comment:
   done



##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control enabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_disable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->pulldown_reg, &regval))
+    {
+      regval &= ~regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control disabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_write_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   value    - The value to write to the 4 scratch bits
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value)
+{
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, &regval))
+    {
+      regval &= ~ACT8945A_SCRATCH_MASK;
+      regval |= value & ACT8945A_SCRATCH_MASK;
+      if (!act8945a_putreg(priv, ACT8945A_SYS1, regval))
+        {
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_read_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev    - The regulator device pointer.
+ *   scratch - pointer to the scratch value read
+ *
+ * Returned Value: The scratch value read, and success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t *scratch)
+{
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, scratch))
+    {
+      return OK;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_set_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector to use for the regulator
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_set_voltage_sel(struct regulator_dev_s *rdev,
+                                    unsigned selector)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  if (selector >= ACT8945A_NUM_VOLTAGES)
+    {
+      return -EINVAL;
+    }
+  else
+    {
+      if (!act8945a_putreg(priv, regulator->vsel_reg,
+                           selector & regulator->vsel_mask))
+        {
+          pwrinfo("INFO: reg %s set to %d mV using selector %d \n",
+                   regulator->name, mv_list[selector], selector);
+          return OK;
+        }
+      else
+        {
+          return -EIO;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_get_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: The current selector from the device, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_get_voltage_sel(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      return regval;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      regval |= regulator->enable_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))

Review Comment:
   done



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [nuttx] TimJTi commented on a diff in pull request #8088: Add ACT8945A power driver

Posted by GitBox <gi...@apache.org>.
TimJTi commented on code in PR #8088:
URL: https://github.com/apache/nuttx/pull/8088#discussion_r1068257664


##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *

Review Comment:
   done



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [nuttx] TimJTi commented on a diff in pull request #8088: Add ACT8945A power driver

Posted by GitBox <gi...@apache.org>.
TimJTi commented on code in PR #8088:
URL: https://github.com/apache/nuttx/pull/8088#discussion_r1068268596


##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control enabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_disable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->pulldown_reg, &regval))

Review Comment:
   done



##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control enabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_disable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->pulldown_reg, &regval))
+    {
+      regval &= ~regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control disabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_write_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   value    - The value to write to the 4 scratch bits
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value)
+{
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, &regval))

Review Comment:
   done



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [nuttx] TimJTi commented on a diff in pull request #8088: Add ACT8945A power driver

Posted by GitBox <gi...@apache.org>.
TimJTi commented on code in PR #8088:
URL: https://github.com/apache/nuttx/pull/8088#discussion_r1069539233


##########
drivers/power/supply/regulator_gpio.c:
##########
@@ -65,7 +65,9 @@ static const struct regulator_ops_s g_regulator_gpio_ops =
   NULL,                         /* get_voltage_sel */
   regulator_gpio_enable,        /* enable */
   regulator_gpio_is_enabled,    /* is_enabled */
-  regulator_gpio_disable        /* disable */
+  regulator_gpio_disable,       /* disable */
+  NULL,                         /* enable pulldown  if reg. disabled */

Review Comment:
   done



##########
drivers/power/supply/regulator.c:
##########
@@ -236,6 +238,32 @@ static int _regulator_get_voltage(FAR struct regulator_dev_s *rdev)
   return ret;
 }
 
+static int _regulator_do_enable_pulldown(FAR struct regulator_dev_s *rdev)
+{
+  int ret;
+
+  ret = rdev->ops->enable_pulldown(rdev);
+  if (ret < 0)
+    {
+      pwrerr("failed to get enable pulldown\n");
+    }
+
+  return ret;
+}
+
+static int _regulator_do_disable_pulldown(FAR struct regulator_dev_s *rdev)
+{
+  int ret;
+
+  ret = rdev->ops->disable_pulldown(rdev);

Review Comment:
   done



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [nuttx] pkarashchenko commented on a diff in pull request #8088: Add ACT8945A power driver

Posted by "pkarashchenko (via GitHub)" <gi...@apache.org>.
pkarashchenko commented on code in PR #8088:
URL: https://github.com/apache/nuttx/pull/8088#discussion_r1087276703


##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,1081 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_SYSTRST_MASK                     (0x80)
+#define ACT8945A_SYSMODE_MASK                     (0x40)
+#define ACT8945A_SYSLEV_MASK                      (0x0f)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_TRST_64
+#  define ACT8945A_TRST                           (0x80) /* 64ms*/
+#else
+#  define ACT8945A_TRST                           (0)    /* 260ms */
+#endif
+
+#ifdef CONFIG_ACT8945A_SYSLEV_MODE_INTERRUPT
+#  define ACT8945A_SYSLEV_MODE                    (0x40) /* Interrupt */
+#else
+#  define ACT8945A_SYSLEV_MODE                    (0)    /* Shutdown */
+#endif
+
+#if defined(CONFIG_ACT8945A_SYSLEV_2300)
+#  define ACT8945A_SYSLEV 0
+#elif defined(CONFIG_ACT8945A_SYSLEV_2400)
+#  define ACT8945A_SYSLEV 1
+#elif defined(CONFIG_ACT8945A_SYSLEV_2500)
+#  define ACT8945A_SYSLEV 2
+#elif defined(CONFIG_ACT8945A_SYSLEV_2600)
+#  define ACT8945A_SYSLEV 3
+#elif defined(CONFIG_ACT8945A_SYSLEV_2700)
+#  define ACT8945A_SYSLEV 4
+#elif defined(CONFIG_ACT8945A_SYSLEV_2800)
+#  define ACT8945A_SYSLEV 5
+#elif defined(CONFIG_ACT8945A_SYSLEV_2900)
+#  define ACT8945A_SYSLEV 6
+#elif defined(CONFIG_ACT8945A_SYSLEV_3000)
+#  define ACT8945A_SYSLEV 7
+#elif defined(CONFIG_ACT8945A_SYSLEV_3100)
+#  define ACT8945A_SYSLEV 8
+#elif defined(CONFIG_ACT8945A_SYSLEV_3200)
+#  define ACT8945A_SYSLEV 9
+#elif defined(CONFIG_ACT8945A_SYSLEV_3300)
+#  define ACT8945A_SYSLEV 10
+#elif defined(CONFIG_ACT8945A_SYSLEV_3400)
+#  define ACT8945A_SYSLEV 11
+#elif defined(CONFIG_ACT8945A_SYSLEV_3500)
+#  define ACT8945A_SYSLEV 12
+#elif defined(CONFIG_ACT8945A_SYSLEV_3600)
+#  define ACT8945A_SYSLEV 13
+#elif defined(CONFIG_ACT8945A_SYSLEV_3700)
+#  define ACT8945A_SYSLEV 14
+#elif defined(CONFIG_ACT8945A_SYSLEV_3800)
+#  define ACT8945A_SYSLEV 15
+#else
+#  error No act8945a sys level detect threshold defined
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }

Review Comment:
   C89 incompatible



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [nuttx] TimJTi commented on a diff in pull request #8088: Add ACT8945A power driver

Posted by GitBox <gi...@apache.org>.
TimJTi commented on code in PR #8088:
URL: https://github.com/apache/nuttx/pull/8088#discussion_r1068270343


##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control enabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_disable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->pulldown_reg, &regval))
+    {
+      regval &= ~regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control disabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_write_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   value    - The value to write to the 4 scratch bits
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value)
+{
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, &regval))
+    {
+      regval &= ~ACT8945A_SCRATCH_MASK;
+      regval |= value & ACT8945A_SCRATCH_MASK;
+      if (!act8945a_putreg(priv, ACT8945A_SYS1, regval))
+        {
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_read_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev    - The regulator device pointer.
+ *   scratch - pointer to the scratch value read
+ *
+ * Returned Value: The scratch value read, and success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t *scratch)
+{
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, scratch))
+    {
+      return OK;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_set_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector to use for the regulator
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_set_voltage_sel(struct regulator_dev_s *rdev,
+                                    unsigned selector)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  if (selector >= ACT8945A_NUM_VOLTAGES)
+    {
+      return -EINVAL;
+    }
+  else
+    {
+      if (!act8945a_putreg(priv, regulator->vsel_reg,
+                           selector & regulator->vsel_mask))
+        {
+          pwrinfo("INFO: reg %s set to %d mV using selector %d \n",
+                   regulator->name, mv_list[selector], selector);
+          return OK;
+        }
+      else
+        {
+          return -EIO;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_get_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: The current selector from the device, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_get_voltage_sel(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      return regval;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      regval |= regulator->enable_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: reg %s enabled\n", regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_is_enabled
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Whether enabled or disabled, or error code.

Review Comment:
   done



##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control enabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_disable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->pulldown_reg, &regval))
+    {
+      regval &= ~regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control disabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_write_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   value    - The value to write to the 4 scratch bits
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value)
+{
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, &regval))
+    {
+      regval &= ~ACT8945A_SCRATCH_MASK;
+      regval |= value & ACT8945A_SCRATCH_MASK;
+      if (!act8945a_putreg(priv, ACT8945A_SYS1, regval))
+        {
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_read_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev    - The regulator device pointer.
+ *   scratch - pointer to the scratch value read
+ *
+ * Returned Value: The scratch value read, and success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t *scratch)
+{
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, scratch))
+    {
+      return OK;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_set_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector to use for the regulator
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_set_voltage_sel(struct regulator_dev_s *rdev,
+                                    unsigned selector)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  if (selector >= ACT8945A_NUM_VOLTAGES)
+    {
+      return -EINVAL;
+    }
+  else
+    {
+      if (!act8945a_putreg(priv, regulator->vsel_reg,
+                           selector & regulator->vsel_mask))
+        {
+          pwrinfo("INFO: reg %s set to %d mV using selector %d \n",
+                   regulator->name, mv_list[selector], selector);
+          return OK;
+        }
+      else
+        {
+          return -EIO;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_get_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: The current selector from the device, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_get_voltage_sel(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      return regval;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      regval |= regulator->enable_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: reg %s enabled\n", regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_is_enabled
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Whether enabled or disabled, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_is_enabled(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      return (regval & regulator->enable_mask);
+    }
+  else
+    {
+      return -ENODEV;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_disable
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))

Review Comment:
   done



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [nuttx] TimJTi commented on a diff in pull request #8088: Add ACT8945A power driver

Posted by GitBox <gi...@apache.org>.
TimJTi commented on code in PR #8088:
URL: https://github.com/apache/nuttx/pull/8088#discussion_r1068270776


##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control enabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_disable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->pulldown_reg, &regval))
+    {
+      regval &= ~regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control disabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_write_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   value    - The value to write to the 4 scratch bits
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value)
+{
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, &regval))
+    {
+      regval &= ~ACT8945A_SCRATCH_MASK;
+      regval |= value & ACT8945A_SCRATCH_MASK;
+      if (!act8945a_putreg(priv, ACT8945A_SYS1, regval))
+        {
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_read_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev    - The regulator device pointer.
+ *   scratch - pointer to the scratch value read
+ *
+ * Returned Value: The scratch value read, and success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t *scratch)
+{
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, scratch))
+    {
+      return OK;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_set_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector to use for the regulator
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_set_voltage_sel(struct regulator_dev_s *rdev,
+                                    unsigned selector)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  if (selector >= ACT8945A_NUM_VOLTAGES)
+    {
+      return -EINVAL;
+    }
+  else
+    {
+      if (!act8945a_putreg(priv, regulator->vsel_reg,
+                           selector & regulator->vsel_mask))
+        {
+          pwrinfo("INFO: reg %s set to %d mV using selector %d \n",
+                   regulator->name, mv_list[selector], selector);
+          return OK;
+        }
+      else
+        {
+          return -EIO;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_get_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: The current selector from the device, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_get_voltage_sel(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      return regval;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      regval |= regulator->enable_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: reg %s enabled\n", regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_is_enabled
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Whether enabled or disabled, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_is_enabled(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      return (regval & regulator->enable_mask);
+    }
+  else
+    {
+      return -ENODEV;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_disable
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      regval &= ~regulator->enable_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))

Review Comment:
   done



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [nuttx] xiaoxiang781216 commented on a diff in pull request #8088: Add ACT8945A power driver

Posted by GitBox <gi...@apache.org>.
xiaoxiang781216 commented on code in PR #8088:
URL: https://github.com/apache/nuttx/pull/8088#discussion_r1068541261


##########
drivers/power/supply/regulator_gpio.c:
##########
@@ -65,7 +65,9 @@ static const struct regulator_ops_s g_regulator_gpio_ops =
   NULL,                         /* get_voltage_sel */
   regulator_gpio_enable,        /* enable */
   regulator_gpio_is_enabled,    /* is_enabled */
-  regulator_gpio_disable        /* disable */
+  regulator_gpio_disable,       /* disable */
+  NULL,                         /* enable pulldown  if reg. disabled */

Review Comment:
   compiler will auto initialize the last two unassigned fields to zero (NULL) automatically, so we don't need change anything here.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [nuttx] TimJTi commented on a diff in pull request #8088: Add ACT8945A power driver

Posted by GitBox <gi...@apache.org>.
TimJTi commented on code in PR #8088:
URL: https://github.com/apache/nuttx/pull/8088#discussion_r1068590963


##########
drivers/power/supply/regulator_gpio.c:
##########
@@ -65,7 +65,9 @@ static const struct regulator_ops_s g_regulator_gpio_ops =
   NULL,                         /* get_voltage_sel */
   regulator_gpio_enable,        /* enable */
   regulator_gpio_is_enabled,    /* is_enabled */
-  regulator_gpio_disable        /* disable */
+  regulator_gpio_disable,       /* disable */
+  NULL,                         /* enable pulldown  if reg. disabled */

Review Comment:
   OK. I got caught out today by extra fields added to a struct in code I'd written a year ago (but as yet haven't submitted as a PR). New CODE fields had been between existing ones...so I'm not 100% convinced having a mismatch between the definitions and declarations is actually that good an idea. Is there an actual downside to those NULLs?
   
   However I will revert the change.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [nuttx] xiaoxiang781216 merged pull request #8088: Add ACT8945A power driver

Posted by GitBox <gi...@apache.org>.
xiaoxiang781216 merged PR #8088:
URL: https://github.com/apache/nuttx/pull/8088


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [nuttx] TimJTi commented on a diff in pull request #8088: Add ACT8945A power driver

Posted by GitBox <gi...@apache.org>.
TimJTi commented on code in PR #8088:
URL: https://github.com/apache/nuttx/pull/8088#discussion_r1068260751


##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.

Review Comment:
   done



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [nuttx] TimJTi commented on a diff in pull request #8088: Add ACT8945A power driver

Posted by GitBox <gi...@apache.org>.
TimJTi commented on code in PR #8088:
URL: https://github.com/apache/nuttx/pull/8088#discussion_r1068502969


##########
drivers/power/supply/regulator.c:
##########
@@ -236,6 +238,32 @@ static int _regulator_get_voltage(FAR struct regulator_dev_s *rdev)
   return ret;
 }
 
+static int _regulator_do_enable_pulldown(FAR struct regulator_dev_s *rdev)
+{
+  int ret;
+
+  ret = rdev->ops->enable_pulldown(rdev);
+  if (ret < 0)
+    {
+      pwrerr("failed to get enable pulldown\n");
+    }
+
+  return ret;
+}
+
+static int _regulator_do_disable_pulldown(FAR struct regulator_dev_s *rdev)
+{
+  int ret;
+
+  ret = rdev->ops->disable_pulldown(rdev);

Review Comment:
   ditto to the ditto



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [nuttx] TimJTi commented on a diff in pull request #8088: Add ACT8945A power driver

Posted by GitBox <gi...@apache.org>.
TimJTi commented on code in PR #8088:
URL: https://github.com/apache/nuttx/pull/8088#discussion_r1068502653


##########
drivers/power/supply/regulator.c:
##########
@@ -236,6 +238,32 @@ static int _regulator_get_voltage(FAR struct regulator_dev_s *rdev)
   return ret;
 }
 
+static int _regulator_do_enable_pulldown(FAR struct regulator_dev_s *rdev)
+{
+  int ret;

Review Comment:
   Yes, of course. Sloppy - will sort.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [nuttx] TimJTi commented on a diff in pull request #8088: Add ACT8945A power driver

Posted by GitBox <gi...@apache.org>.
TimJTi commented on code in PR #8088:
URL: https://github.com/apache/nuttx/pull/8088#discussion_r1068269803


##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control enabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_disable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->pulldown_reg, &regval))
+    {
+      regval &= ~regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control disabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_write_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   value    - The value to write to the 4 scratch bits
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value)
+{
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, &regval))
+    {
+      regval &= ~ACT8945A_SCRATCH_MASK;
+      regval |= value & ACT8945A_SCRATCH_MASK;
+      if (!act8945a_putreg(priv, ACT8945A_SYS1, regval))
+        {
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_read_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev    - The regulator device pointer.
+ *   scratch - pointer to the scratch value read
+ *
+ * Returned Value: The scratch value read, and success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t *scratch)
+{
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, scratch))
+    {
+      return OK;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_set_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector to use for the regulator
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_set_voltage_sel(struct regulator_dev_s *rdev,
+                                    unsigned selector)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  if (selector >= ACT8945A_NUM_VOLTAGES)
+    {
+      return -EINVAL;
+    }
+  else
+    {
+      if (!act8945a_putreg(priv, regulator->vsel_reg,
+                           selector & regulator->vsel_mask))
+        {
+          pwrinfo("INFO: reg %s set to %d mV using selector %d \n",
+                   regulator->name, mv_list[selector], selector);
+          return OK;
+        }
+      else
+        {
+          return -EIO;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_get_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: The current selector from the device, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_get_voltage_sel(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      return regval;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      regval |= regulator->enable_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: reg %s enabled\n", regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_is_enabled
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Whether enabled or disabled, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_is_enabled(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))

Review Comment:
   done



##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control enabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_disable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->pulldown_reg, &regval))
+    {
+      regval &= ~regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control disabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_write_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   value    - The value to write to the 4 scratch bits
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value)
+{
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, &regval))
+    {
+      regval &= ~ACT8945A_SCRATCH_MASK;
+      regval |= value & ACT8945A_SCRATCH_MASK;
+      if (!act8945a_putreg(priv, ACT8945A_SYS1, regval))
+        {
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_read_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev    - The regulator device pointer.
+ *   scratch - pointer to the scratch value read
+ *
+ * Returned Value: The scratch value read, and success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t *scratch)
+{
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, scratch))
+    {
+      return OK;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_set_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector to use for the regulator
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_set_voltage_sel(struct regulator_dev_s *rdev,
+                                    unsigned selector)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  if (selector >= ACT8945A_NUM_VOLTAGES)
+    {
+      return -EINVAL;
+    }
+  else
+    {
+      if (!act8945a_putreg(priv, regulator->vsel_reg,
+                           selector & regulator->vsel_mask))
+        {
+          pwrinfo("INFO: reg %s set to %d mV using selector %d \n",
+                   regulator->name, mv_list[selector], selector);
+          return OK;
+        }
+      else
+        {
+          return -EIO;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_get_voltage_sel
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: The current selector from the device, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_get_voltage_sel(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      return regval;
+    }
+  else
+    {
+      return -EIO;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->vsel_reg, &regval))
+    {
+      regval |= regulator->enable_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: reg %s enabled\n", regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_is_enabled
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Whether enabled or disabled, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_is_enabled(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      return (regval & regulator->enable_mask);
+    }
+  else
+    {
+      return -ENODEV;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_disable
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success, or error code.

Review Comment:
   done



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [nuttx] TimJTi commented on a diff in pull request #8088: Add ACT8945A power driver

Posted by GitBox <gi...@apache.org>.
TimJTi commented on code in PR #8088:
URL: https://github.com/apache/nuttx/pull/8088#discussion_r1068268259


##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control enabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_disable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->pulldown_reg, &regval))
+    {
+      regval &= ~regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->enable_reg, regval))
+        {
+          pwrinfo("INFO: Output discharge control disabled %s\n",
+                   regulator->name);
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_write_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   value    - The value to write to the 4 scratch bits
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value)
+{
+  uint8_t regval;
+
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, &regval))
+    {
+      regval &= ~ACT8945A_SCRATCH_MASK;
+      regval |= value & ACT8945A_SCRATCH_MASK;
+      if (!act8945a_putreg(priv, ACT8945A_SYS1, regval))
+        {
+          return OK;
+        }
+    }
+
+  return -EIO;
+}
+
+/****************************************************************************
+ * Name: act8945a_read_scratch
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev    - The regulator device pointer.
+ *   scratch - pointer to the scratch value read
+ *
+ * Returned Value: The scratch value read, and success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t *scratch)
+{
+  if (!act8945a_getreg(priv, ACT8945A_SYS1, scratch))

Review Comment:
   done



##########
drivers/power/supply/act8945a.c:
##########
@@ -0,0 +1,872 @@
+/****************************************************************************
+ * drivers/power/supply/act8945a.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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/power/regulator.h>
+#include <nuttx/power/act8945a.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define ACT8945A_BUS_SPEED                        300000
+#define ACT8945A_SLAVE_ADDRESS                    0x5b
+
+#ifdef CONFIG_DEBUG_POWER_ERROR
+#  define act8945a_err(x, ...)        _err(x, ##__VA_ARGS__)
+#else
+#  define act8945a_err(x, ...)        uerr(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_WARN
+#  define act8945a_warn(x, ...)       _warn(x, ##__VA_ARGS__)
+#else
+#  define act8945a_warn(x, ...)       uwarn(x, ##__VA_ARGS__)
+#endif
+#ifdef CONFIG_DEBUG_POWER_INFO
+#  define act8945a_info(x, ...)       _info(x, ##__VA_ARGS__)
+#else
+#  define act8945a_info(x, ...)       uinfo(x, ##__VA_ARGS__)
+#endif
+
+#define ACT8945A_NUM_VOLTAGES                     64
+
+#define ACT8945A_SYS0                             (0x00)
+#define ACT8945A_SYS1                             (0x01)
+
+#define ACT8945A_DCDC1_VSET0                      (0x20)
+#define ACT8945A_DCDC1_VSET1                      (0x21)
+#define ACT8945A_DCDC1_CONTROL                    (0x22)
+#define ACT8945A_DCDC2_VSET0                      (0x30)
+#define ACT8945A_DCDC2_VSET1                      (0x31)
+#define ACT8945A_DCDC2_CONTROL                    (0x32)
+#define ACT8945A_DCDC3_VSET0                      (0x40)
+#define ACT8945A_DCDC3_VSET1                      (0x41)
+#define ACT8945A_DCDC3_CONTROL                    (0x42)
+#define ACT8945A_LDO1_VSET                        (0x50)
+#define ACT8945A_LDO1_CONTROL                     (0x51)
+#define ACT8945A_LDO2_VSET                        (0x54)
+#define ACT8945A_LDO2_CONTROL                     (0x55)
+#define ACT8945A_LDO3_VSET                        (0x60)
+#define ACT8945A_LDO3_CONTROL                     (0x61)
+#define ACT8945A_LDO4_VSET                        (0x64)
+#define ACT8945A_LDO4_CONTROL                     (0x65)
+
+#define ACT8945A_VSET_MASK                        (0x3f)
+#define ACT8945A_EN_MASK                          (0x80)
+
+#define ACT8945A_SCRATCH_MASK                     (0x0f)
+#define SCRATCH_TEST_VAL                          (0x05)
+
+#define ACT8945A_PULLDOWN_MASK                    (0x40)
+
+#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
+#  define ACT8945A_DCDC1_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
+#  define ACT8945A_DCDC2_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
+#  define ACT8945A_DCDC3_BOOT_ON 1
+#else
+#  define ACT8945A_DCDC3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
+#  define ACT8945A_LDO1_BOOT_ON 1
+#else
+#  define ACT8945A_LDO1_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
+#  define ACT8945A_LDO2_BOOT_ON 1
+#else
+#  define ACT8945A_LDO2_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
+#  define ACT8945A_LDO3_BOOT_ON 1
+#else
+#  define ACT8945A_LDO3_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
+#  define ACT8945A_LDO4_BOOT_ON 1
+#else
+#  define ACT8945A_LDO4_BOOT_ON 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
+#  define ACT8945A_DCDC1_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
+#  define ACT8945A_DCDC2_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
+#  define ACT8945A_DCDC3_APPLY_UV 1
+#else
+#  define ACT8945A_DCDC3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
+#  define ACT8945A_LDO1_APPLY_UV 1
+#else
+#  define ACT8945A_LDO1_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
+#  define ACT8945A_LDO2_APPLY_UV 1
+#else
+#  define ACT8945A_LDO2_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
+#  define ACT8945A_LDO3_APPLY_UV 1
+#else
+#  define ACT8945A_LDO3_APPLY_UV 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
+#  define ACT8945A_LDO4_APPLY_UV 1
+#else
+#  define ACT8945A_LDO4_APPLY_UV 0
+#endif
+
+#define ACT8945A_DCDC1_PULLDOWN 0
+#define ACT8945A_DCDC2_PULLDOWN 0
+#define ACT8945A_DCDC3_PULLDOWN 0
+
+#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
+#  define ACT8945A_LDO1_PULLDOWN 1
+#else
+#  define ACT8945A_LDO1_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
+#  define ACT8945A_LDO2_PULLDOWN 1
+#else
+#  define ACT8945A_LDO2_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
+#  define ACT8945A_LDO3_PULLDOWN 1
+#else
+#  define ACT8945A_LDO3_PULLDOWN 0
+#endif
+
+#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
+#  define ACT8945A_LDO4_PULLDOWN 1
+#else
+#  define ACT8945A_LDO4_PULLDOWN 0
+#endif
+
+#define ACT8945A_REG(_id, _vsel)                      \
+  [ACT8945A_##_id] =                                  \
+  {                                                   \
+    .name          = CONFIG_ACT8945A_##_id##_NAME,    \
+    .id            = ACT8945A_##_id,                  \
+    .n_voltages    = ACT8945A_NUM_VOLTAGES,           \
+    .vsel_reg      = ACT8945A_##_id##_##_vsel,        \
+    .vsel_mask     = ACT8945A_VSET_MASK,              \
+    .enable_reg    = ACT8945A_##_id##_CONTROL,        \
+    .enable_mask   = ACT8945A_EN_MASK,                \
+    .boot_on       = ACT8945A_##_id##_BOOT_ON,        \
+    .min_uv        = CONFIG_ACT8945A_##_id##_MIN_UV,  \
+    .max_uv        = CONFIG_ACT8945A_##_id##_MAX_UV,  \
+    .apply_uv      = ACT8945A_##_id##_APPLY_UV,       \
+    .pulldown      = ACT8945A_##_id##_PULLDOWN,       \
+    .pulldown_reg  = ACT8945A_##_id##_CONTROL,        \
+    .pulldown_mask = ACT8945A_PULLDOWN_MASK,          \
+  }
+/****************************************************************************
+ * Private type
+ ****************************************************************************/
+
+struct regulator_act8945a_priv
+{
+  FAR struct       i2c_master_s     *i2c;
+  uint8_t                           i2c_addr;
+  int                               i2c_freq;
+  FAR const struct regulator_desc_s *regulators;
+  FAR struct       regulator_dev_s  *rdev;
+};
+
+struct act8945a_dev_s
+{
+  /* Common part of the regulator driver visible to the upper-half driver */
+
+  FAR struct regulator_desc_s  *regulator_desc_s;
+
+  /* Data fields specific to the lower half act8945a driver follow */
+
+  FAR struct i2c_master_s      *i2c;      /* I2C interface */
+  uint8_t                      addr;      /* I2C address */
+  uint32_t                     frequency; /* I2C frequency */
+};
+
+enum
+{
+  ACT8945A_DCDC1 = 0,
+  ACT8945A_DCDC2,
+  ACT8945A_DCDC3,
+  ACT8945A_LDO1,
+  ACT8945A_LDO2,
+  ACT8945A_LDO3,
+  ACT8945A_LDO4,
+  ACT8945A_MAX,
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Character driver methods */
+
+/* regulator lower half methods */
+
+static int act8945a_list_voltage(struct regulator_dev_s *rdev,
+                                 unsigned int selector);
+static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
+                                    unsigned int selector);
+static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
+static int act8945a_enable(struct regulator_dev_s *rdev);
+static int act8945a_is_enabled(struct regulator_dev_s *rdev);
+static int act8945a_disable(struct regulator_dev_s *rdev);
+static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
+                                  uint8_t value);
+static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
+                                 uint8_t * scratch);
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
+static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
+
+/* I2C support */
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval);
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const int mv_list[] =
+{
+  600,   625,  650,  675,  700,  725,  750,  775,
+  800,   825,  850,  875,  900,  925,  950,  975,
+  1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+  1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+  1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
+  2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
+  2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
+  3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
+};
+
+static const struct regulator_desc_s g_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET0),
+  ACT8945A_REG(DCDC2, VSET0),
+  ACT8945A_REG(DCDC3, VSET0),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+static const struct regulator_desc_s g_alt_act8945a_regulators[] =
+{
+  ACT8945A_REG(DCDC1, VSET1),
+  ACT8945A_REG(DCDC2, VSET1),
+  ACT8945A_REG(DCDC3, VSET1),
+  ACT8945A_REG(LDO1, VSET),
+  ACT8945A_REG(LDO2, VSET),
+  ACT8945A_REG(LDO3, VSET),
+  ACT8945A_REG(LDO4, VSET),
+};
+
+/* Regulator operations */
+
+static const struct regulator_ops_s g_act8945a_ops =
+{
+  act8945a_list_voltage,     /* list_voltage     */
+  NULL,                      /* set_voltage      */
+  act8945a_set_voltage_sel,  /* set_voltage_sel  */
+  NULL,                      /* get_voltage      */
+  act8945a_get_voltage_sel,  /* get_voltage_sel  */
+  act8945a_enable,           /* enable           */
+  act8945a_is_enabled,       /* is_enabled       */
+  act8945a_disable,          /* disable          */
+  act8945a_enable_pulldown,  /* enable pulldown if reg. disabled */
+  act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: act8945a_getreg
+ *
+ * Description:
+ *   Reads a single register from the ACT8945A PMIC.
+ *
+ ****************************************************************************/
+
+static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t *regval)
+{
+  struct i2c_config_s config;
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv   != NULL);
+  DEBUGASSERT(regval != NULL);
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  /* Restart and read 8 bits from the register */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
+  spin_unlock_irqrestore(NULL, flags);
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_read failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_putreg
+ *
+ * Description:
+ *   Writes a single byte to one of the ACT8945A registers.
+ *
+ ****************************************************************************/
+
+static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
+                           uint8_t regaddr, uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t             buffer[2];
+  int                 ret;
+  irqstate_t          flags;
+
+  /* Sanity check */
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set up a 2-byte message to send */
+
+  buffer[0] = regaddr;
+  buffer[1] = regval;
+
+  /* Set up the I2C configuration */
+
+  config.frequency = priv->i2c_freq;
+  config.address   = priv->i2c_addr;
+  config.addrlen   = 7;
+
+  /* Write the register address followed by the data (no RESTART) */
+
+  flags = spin_lock_irqsave(NULL);
+  ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
+  spin_unlock_irqrestore(NULL, flags);
+
+  if (ret < 0)
+    {
+      act8945a_err("ERROR: i2c_write failed: %d\n", ret);
+      return ret;
+    }
+
+  act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: act8945a_list_voltage
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *   selector - The selector for the voltage look-up
+ *
+ * Returned Value: The voltage for the selector, or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
+                                 unsigned int selector)
+{
+  if (selector < ACT8945A_NUM_VOLTAGES)
+    {
+      return (mv_list[selector]);
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: act8945a_enable_pulldown
+ *
+ * Description:
+ *
+ * Input Parameters:
+ *
+ *   rdev     - The regulator device pointer.
+ *
+ * Returned Value: Success or error code.
+ *
+ ****************************************************************************/
+
+static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
+{
+  FAR struct regulator_act8945a_priv *priv = rdev->priv;
+  FAR const struct regulator_desc_s *regulator = rdev->desc;
+
+  uint8_t regval;
+
+  /* for ease of code commonality we skip any calls for DCDC1-3 */
+
+  if (regulator->id < ACT8945A_LDO1)
+    {
+      return OK;
+    }
+
+  if (!act8945a_getreg(priv, regulator->enable_reg, &regval))
+    {
+      regval |= regulator->pulldown_mask;
+      if (!act8945a_putreg(priv, regulator->pulldown_reg, regval))

Review Comment:
   done



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org