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/12 13:28:43 UTC

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

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