Add DM driver to support Dialog DA9063.
Currently it support binding regulator children.

Signed-off-by: Robert Beckett <bob.beck...@collabora.com>
---
 drivers/power/pmic/Kconfig       |   8 +
 drivers/power/pmic/Makefile      |   1 +
 drivers/power/pmic/da9063.c      | 270 ++++++++++++++++++++++++++
 drivers/power/regulator/Kconfig  |   7 +
 drivers/power/regulator/Makefile |   1 +
 drivers/power/regulator/da9063.c | 320 +++++++++++++++++++++++++++++++
 include/power/da9063_pmic.h      | 303 +++++++++++++++++++++++++++++
 7 files changed, 910 insertions(+)
 create mode 100644 drivers/power/pmic/da9063.c
 create mode 100644 drivers/power/regulator/da9063.c
 create mode 100644 include/power/da9063_pmic.h

diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig
index 586772fdec..6dd7b1bf76 100644
--- a/drivers/power/pmic/Kconfig
+++ b/drivers/power/pmic/Kconfig
@@ -267,3 +267,11 @@ config SPL_PMIC_LP87565
        help
        The LP87565 is a PMIC containing a bunch of SMPS.
        This driver binds the pmic children in SPL.
+
+config DM_PMIC_DA9063
+       bool "Enable support for Dialog DA9063 PMIC"
+       depends on DM_PMIC && (DM_I2C || DM_SPI)
+       help
+       The DA9063 is a PMIC providing 6 BUCK converters and 11 LDO regulators.
+       It can be accessed via I2C or SPI.
+       This driver binds the pmic children.
diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile
index 888dbb2857..9be9d5d9a0 100644
--- a/drivers/power/pmic/Makefile
+++ b/drivers/power/pmic/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_$(SPL_)PMIC_PALMAS) += palmas.o
 obj-$(CONFIG_$(SPL_)PMIC_LP873X) += lp873x.o
 obj-$(CONFIG_$(SPL_)PMIC_LP87565) += lp87565.o
 obj-$(CONFIG_PMIC_STPMIC1) += stpmic1.o
+obj-$(CONFIG_DM_PMIC_DA9063) += da9063.o
 
 obj-$(CONFIG_POWER_LTC3676) += pmic_ltc3676.o
 obj-$(CONFIG_POWER_MAX77696) += pmic_max77696.o
diff --git a/drivers/power/pmic/da9063.c b/drivers/power/pmic/da9063.c
new file mode 100644
index 0000000000..81a7803b09
--- /dev/null
+++ b/drivers/power/pmic/da9063.c
@@ -0,0 +1,270 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2019 Collabora
+ * (C) Copyright 2019 GE
+ */
+
+#define DEBUG 1
+#include <common.h>
+#include <fdtdec.h>
+#include <errno.h>
+#include <dm.h>
+#include <i2c.h>
+#include <spi.h>
+#include <linux/bitfield.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <power/da9063_pmic.h>
+
+static const struct pmic_child_info pmic_children_info[] = {
+       { .prefix = "bcore", .driver = DA9063_BUCK_DRIVER },
+       { .prefix = "bpro", .driver = DA9063_BUCK_DRIVER },
+       { .prefix = "bmem", .driver = DA9063_BUCK_DRIVER },
+       { .prefix = "bio", .driver = DA9063_BUCK_DRIVER },
+       { .prefix = "bperi", .driver = DA9063_BUCK_DRIVER },
+       { .prefix = "ldo", .driver = DA9063_LDO_DRIVER },
+       { },
+};
+
+static int da9063_reg_count(struct udevice *dev)
+{
+       return DA9063_NUM_OF_REGS;
+}
+
+#if defined(CONFIG_DM_I2C)
+static int da9063_i2c_read(struct udevice *dev, uint reg, uint8_t *buff,
+                          int len)
+{
+       int ret;
+
+       /* only support single reg accesses */
+       if (len != 1)
+               return -EINVAL;
+
+       ret = dm_i2c_read(dev, reg, buff, len);
+       if (ret) {
+               pr_err("%s: unable to read reg %#x: %d\n", __func__, reg, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int da9063_i2c_write(struct udevice *dev, uint reg, const uint8_t *buff,
+                           int len)
+{
+       int ret;
+
+       /* only support single reg accesses */
+       if (len != 1)
+               return -EINVAL;
+
+       ret = dm_i2c_write(dev, reg, buff, len);
+       if (ret) {
+               pr_err("%s: unable to write reg %#x: %d\n", __func__, reg, ret);
+               return ret;
+       }
+
+       return 0;
+}
+#endif
+
+#if defined(CONFIG_DM_SPI)
+static int da9063_spi_read(struct udevice *dev, uint reg, uint8_t *buff,
+                          int len)
+{
+       u8 page;
+       u8 data[2];
+       int ret;
+
+       /* only support single reg accesses */
+       if (len != 1)
+               return -EINVAL;
+
+       page = FIELD_GET(DA9063_REG_PAGE_MASK, reg);
+       reg = FIELD_GET(DA9063_REG_ADDR_MASK, reg);
+
+       ret = dm_spi_claim_bus(dev);
+       if (ret)
+               return ret;
+       /* set page */
+       data[0] = FIELD_PREP(DA9063_PROTO_ADDR_MASK, DA9063_PAGE_CON) |
+                 FIELD_PREP(DA9063_PROTO_RW_MASK, DA9063_PROTO_WRITE);
+       data[1] = FIELD_PREP(DA9063_PAGE_CON_PAGE, page);
+       ret = dm_spi_xfer(dev, DA9063_PROTO_LEN, data, NULL, SPI_XFER_ONCE);
+       if (ret) {
+               pr_err("%s: unable to set page: %d\n", __func__, ret);
+               goto err_page;
+       }
+
+       /* set target reg */
+       data[0] = FIELD_PREP(DA9063_PROTO_ADDR_MASK, reg) |
+                 FIELD_PREP(DA9063_PROTO_RW_MASK, DA9063_PROTO_READ);
+       data[1] = 0;
+       ret = dm_spi_xfer(dev, DA9063_PROTO_LEN, data, data, SPI_XFER_ONCE);
+       if (ret) {
+               pr_err("%s: unable to read reg %#x: %d\n", __func__, reg, ret);
+               goto err_reg;
+       }
+       dm_spi_release_bus(dev);
+
+       *buff = data[1];
+
+       return 0;
+
+err_page:
+err_reg:
+       dm_spi_release_bus(dev);
+
+       return ret;
+}
+
+static int da9063_spi_write(struct udevice *dev, uint reg, const uint8_t *buff,
+                           int len)
+{
+       u8 page;
+       u8 data[2];
+       int ret;
+
+       /* only support single reg accesses */
+       if (len != 1)
+               return -EINVAL;
+
+       page = FIELD_GET(DA9063_REG_PAGE_MASK, reg);
+       reg = FIELD_GET(DA9063_REG_ADDR_MASK, reg);
+
+       ret = dm_spi_claim_bus(dev);
+       if (ret)
+               return ret;
+       /* set page */
+       data[0] = FIELD_PREP(DA9063_PROTO_ADDR_MASK, DA9063_PAGE_CON) |
+                 FIELD_PREP(DA9063_PROTO_RW_MASK, DA9063_PROTO_WRITE);
+       data[1] = FIELD_PREP(DA9063_PAGE_CON_PAGE, page);
+       ret = dm_spi_xfer(dev, DA9063_PROTO_LEN, data, NULL, SPI_XFER_ONCE);
+       if (ret) {
+               pr_err("%s: unable to set page: %d\n", __func__, ret);
+               goto err_page;
+       }
+
+       /* set target reg */
+       data[0] = FIELD_PREP(DA9063_PROTO_ADDR_MASK, reg) |
+                 FIELD_PREP(DA9063_PROTO_RW_MASK, DA9063_PROTO_WRITE);
+       data[1] = *buff;
+       ret = dm_spi_xfer(dev, DA9063_PROTO_LEN, data, NULL, SPI_XFER_ONCE);
+       if (ret) {
+               pr_err("%s: unable to write reg %#x: %d\n", __func__, reg, ret);
+               goto err_reg;
+       }
+       dm_spi_release_bus(dev);
+
+       return 0;
+
+err_page:
+err_reg:
+       dm_spi_release_bus(dev);
+
+       return ret;
+}
+#endif
+
+struct da9063_priv {
+       int (*read)(struct udevice *dev, uint reg, uint8_t *buffer, int len);
+       int (*write)(struct udevice *dev, uint reg, const uint8_t *buffer,
+                    int len);
+};
+
+static int da9063_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
+{
+       struct da9063_priv *priv = dev_get_priv(dev);
+
+       return priv->read(dev, reg, buff, len);
+}
+
+static int da9063_write(struct udevice *dev, uint reg, const uint8_t *buff,
+                       int len)
+{
+       struct da9063_priv *priv = dev_get_priv(dev);
+
+       return priv->write(dev, reg, buff, len);
+}
+
+static struct dm_pmic_ops da9063_ops = {
+       .reg_count = da9063_reg_count,
+       .read = da9063_read,
+       .write = da9063_write,
+};
+
+static int da9063_bind(struct udevice *dev)
+{
+       ofnode regulators_node;
+       int children;
+
+       regulators_node = dev_read_subnode(dev, "regulators");
+       if (!ofnode_valid(regulators_node)) {
+               pr_debug("%s: %s regulators subnode not found!\n", __func__,
+                        dev->name);
+               return -ENXIO;
+       }
+
+       pr_debug("%s: '%s' - found regulators subnode\n", __func__, dev->name);
+
+       children = pmic_bind_children(dev, regulators_node, pmic_children_info);
+       if (!children)
+               pr_debug("%s: %s - no child found\n", __func__, dev->name);
+
+       return 0;
+}
+
+static int da9063_probe(struct udevice *dev)
+{
+       struct da9063_priv *priv = dev_get_priv(dev);
+       int ret;
+
+       if (device_get_uclass_id(dev->parent) == UCLASS_I2C) {
+#if defined(CONFIG_DM_I2C)
+               i2c_set_chip_addr_offset_mask(dev, 0x1);
+               priv->read = da9063_i2c_read;
+               priv->write = da9063_i2c_write;
+#else
+               return -ENODEV;
+#endif
+       } else if (device_get_uclass_id(dev->parent) == UCLASS_SPI) {
+#if defined(CONFIG_DM_SPI)
+               priv->read = da9063_spi_read;
+               priv->write = da9063_spi_write;
+#else
+               return -ENODEV;
+#endif
+       } else {
+               pr_err("%s: invalid bus\n", __func__);
+               return -ENODEV;
+       }
+
+       ret = pmic_reg_read(dev, DA9063_CHIP_ID);
+       if (ret < 0) {
+               pr_debug("%s: unable to read chip id: %d\n", __func__, ret);
+               return ret;
+       }
+
+       if (ret != DA9063_CHIP_ID_DA9063) {
+               pr_debug("%s: unknown chip id: %#x\n", __func__, ret);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static const struct udevice_id da9063_ids[] = {
+       { .compatible = "dlg,da9063" },
+       { }
+};
+
+U_BOOT_DRIVER(pmic_da9063) = {
+       .name = "da9063_pmic",
+       .id = UCLASS_PMIC,
+       .of_match = da9063_ids,
+       .bind = da9063_bind,
+       .ops = &da9063_ops,
+       .priv_auto_alloc_size = sizeof(struct da9063_priv),
+       .probe = da9063_probe,
+};
diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig
index 9aa00fad42..e87cccdb82 100644
--- a/drivers/power/regulator/Kconfig
+++ b/drivers/power/regulator/Kconfig
@@ -313,3 +313,10 @@ config SPL_DM_REGULATOR_LP873X
        This enables implementation of driver-model regulator uclass
        features for REGULATOR LP873X and the family of LP873X PMICs.
        The driver implements get/set api for: value and enable in SPL.
+
+config DM_REGULATOR_DA9063
+       bool "Enable support for DA9063 regulators"
+       help
+       Enable support the regulator functions of the DA9063 PMIC.
+       The driver support voltage set/get and enable/disable for LDOs and
+       BUCKs, and mode get/set for BUCKs.
diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile
index 6a3d4bbee4..f0926614cb 100644
--- a/drivers/power/regulator/Makefile
+++ b/drivers/power/regulator/Makefile
@@ -27,3 +27,4 @@ obj-$(CONFIG_$(SPL_)DM_REGULATOR_LP87565) += 
lp87565_regulator.o
 obj-$(CONFIG_$(SPL_)DM_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o
 obj-$(CONFIG_DM_REGULATOR_TPS65910) += tps65910_regulator.o
 obj-$(CONFIG_$(SPL_)DM_REGULATOR_STPMIC1) += stpmic1.o
+obj-$(CONFIG_DM_REGULATOR_DA9063) += da9063.o
diff --git a/drivers/power/regulator/da9063.c b/drivers/power/regulator/da9063.c
new file mode 100644
index 0000000000..68036a3951
--- /dev/null
+++ b/drivers/power/regulator/da9063.c
@@ -0,0 +1,320 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2019 Collabora
+ * (C) Copyright 2019 GE
+ */
+
+#include <common.h>
+#include <fdtdec.h>
+#include <dm.h>
+#include <linux/bitfield.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <power/da9063_pmic.h>
+
+enum {
+       DA9063_ID_BCORE1 = 0,
+       DA9063_ID_BCORE2,
+       DA9063_ID_BPRO,
+       DA9063_ID_BMEM,
+       DA9063_ID_BIO,
+       DA9063_ID_BPERI,
+};
+
+struct buck_info {
+       int min_uV;
+       int max_uV;
+       int step_uV;
+       int ctrl_reg;
+       int volt_reg;
+       int mode_reg;
+};
+
+#define to_buck_info(dev) (struct buck_info *)dev->driver_data
+
+#define DA9063_BUCK(name, min_mV, max_mV, step_mV) \
+{ \
+       .min_uV = min_mV * 1000, \
+       .max_uV = max_mV * 1000, \
+       .step_uV = step_mV * 1000, \
+       .ctrl_reg = DA9063_##name##_CONT, \
+       .volt_reg = DA9063_V##name##_A, \
+       .mode_reg = DA9063_##name##_CFG, \
+}
+
+static const struct buck_info da9063_buck_info[] = {
+       [DA9063_ID_BCORE1] = DA9063_BUCK(BCORE1, 300, 1570, 10),
+       [DA9063_ID_BCORE2] = DA9063_BUCK(BCORE2, 300, 1570, 10),
+       [DA9063_ID_BPRO]   = DA9063_BUCK(BPRO, 530, 1800, 10),
+       [DA9063_ID_BMEM]   = DA9063_BUCK(BMEM, 800, 3340, 20),
+       [DA9063_ID_BIO]    = DA9063_BUCK(BIO, 800, 3340, 20),
+       [DA9063_ID_BPERI]  = DA9063_BUCK(BPERI, 800, 3340, 20),
+};
+
+/* Buck converters can either be in auto mode or sync mode.
+ * Auto uses PWM or PFM depending on load current.
+ * Sync mode uses PFM unless output voltage is < 0.7V.
+ */
+static struct dm_regulator_mode da9063_buck_modes[] = {
+       {
+               .id = DA9063_OPMODE_AUTO,
+               .register_value = DA9063_BUCK_MODE_AUTO,
+               .name = "AUTO",
+       },
+       {
+               .id = DA9063_OPMODE_SYNC,
+               .register_value = DA9063_BUCK_MODE_SYNC,
+               .name = "SYNC",
+       },
+};
+
+static int da9063_buck_get_mode(struct udevice *dev)
+{
+       struct buck_info *info = to_buck_info(dev);
+       int mode = pmic_reg_read(dev_get_parent(dev), info->mode_reg);
+
+       if (mode < 0)
+               return mode;
+
+       mode = FIELD_GET(DA9063_BUCK_MODE, mode);
+
+       switch (mode) {
+       case DA9063_BUCK_MODE_AUTO:
+               return DA9063_OPMODE_AUTO;
+       case DA9063_BUCK_MODE_SYNC:
+               return DA9063_OPMODE_SYNC;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int da9063_buck_set_mode(struct udevice *dev, int rmode)
+{
+       struct buck_info *info = to_buck_info(dev);
+       int mode = pmic_reg_read(dev_get_parent(dev), info->mode_reg);
+
+       mode &= ~DA9063_BUCK_MODE;
+
+       switch (rmode) {
+       case DA9063_OPMODE_AUTO:
+               mode |= FIELD_PREP(DA9063_BUCK_MODE, DA9063_BUCK_MODE_AUTO);
+               break;
+       case DA9063_OPMODE_SYNC:
+               mode |= FIELD_PREP(DA9063_BUCK_MODE, DA9063_BUCK_MODE_SYNC);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return pmic_reg_write(dev_get_parent(dev), info->mode_reg, mode);
+}
+
+static int da9063_buck_get_value(struct udevice *dev)
+{
+       struct buck_info *info = to_buck_info(dev);
+       int sel = pmic_reg_read(dev_get_parent(dev), info->volt_reg);
+
+       if (sel < 0)
+               return sel;
+       sel = FIELD_GET(DA9063_BUCK_VSEL, sel);
+       return info->min_uV + (info->step_uV * sel);
+}
+
+static int da9063_buck_set_value(struct udevice *dev, int uV)
+{
+       struct buck_info *info = to_buck_info(dev);
+       int sel = pmic_reg_read(dev_get_parent(dev), info->volt_reg);
+
+       if (sel < 0)
+               return sel;
+       sel &= ~DA9063_BUCK_VSEL;
+       sel |= FIELD_PREP(DA9063_BUCK_VSEL,
+                         DIV_ROUND_UP(uV - info->min_uV, info->step_uV));
+
+       return pmic_reg_write(dev_get_parent(dev), info->volt_reg, sel);
+}
+
+static int da9063_buck_get_enable(struct udevice *dev)
+{
+       struct buck_info *info = to_buck_info(dev);
+       int cont = pmic_reg_read(dev_get_parent(dev), info->ctrl_reg);
+
+       if (cont < 0)
+               return cont;
+
+       return FIELD_GET(DA9063_BUCK_ENABLE, cont);
+}
+
+static int da9063_buck_set_enable(struct udevice *dev, bool enable)
+{
+       struct buck_info *info = to_buck_info(dev);
+       int cont = pmic_reg_read(dev_get_parent(dev), info->ctrl_reg);
+
+       if (cont < 0)
+               return cont;
+
+       cont &= ~DA9063_BUCK_ENABLE;
+       cont |= FIELD_PREP(DA9063_BUCK_ENABLE, enable);
+
+       return pmic_reg_write(dev_get_parent(dev), info->ctrl_reg, cont);
+}
+
+static int da9063_buck_probe(struct udevice *dev)
+{
+       struct dm_regulator_uclass_platdata *uc_pdata;
+
+       uc_pdata = dev_get_uclass_platdata(dev);
+
+       if (!strcmp(uc_pdata->name, "bcore1"))
+               dev->driver_data = (ulong)&da9063_buck_info[DA9063_ID_BCORE1];
+       else if (!strcmp(uc_pdata->name, "bcore2"))
+               dev->driver_data = (ulong)&da9063_buck_info[DA9063_ID_BCORE2];
+       else if (!strcmp(uc_pdata->name, "bpro"))
+               dev->driver_data = (ulong)&da9063_buck_info[DA9063_ID_BPRO];
+       else if (!strcmp(uc_pdata->name, "bmem"))
+               dev->driver_data = (ulong)&da9063_buck_info[DA9063_ID_BMEM];
+       else if (!strcmp(uc_pdata->name, "bio"))
+               dev->driver_data = (ulong)&da9063_buck_info[DA9063_ID_BIO];
+       else if (!strcmp(uc_pdata->name, "bperi"))
+               dev->driver_data = (ulong)&da9063_buck_info[DA9063_ID_BPERI];
+       else
+               return -ENODEV;
+
+       uc_pdata->type = REGULATOR_TYPE_BUCK;
+       uc_pdata->mode_count = ARRAY_SIZE(da9063_buck_modes);
+       uc_pdata->mode = da9063_buck_modes;
+
+       return 0;
+}
+
+static const struct dm_regulator_ops da9063_buck_ops = {
+       .get_value  = da9063_buck_get_value,
+       .set_value  = da9063_buck_set_value,
+       .get_enable = da9063_buck_get_enable,
+       .set_enable = da9063_buck_set_enable,
+       .get_mode   = da9063_buck_get_mode,
+       .set_mode   = da9063_buck_set_mode,
+};
+
+U_BOOT_DRIVER(da9063_buck) = {
+       .name  = DA9063_BUCK_DRIVER,
+       .id    = UCLASS_REGULATOR,
+       .ops   = &da9063_buck_ops,
+       .probe = da9063_buck_probe,
+};
+
+struct ldo_info {
+       int min_uV;
+       int max_uV;
+       int step_uV;
+       int ctrl_reg;
+       int volt_reg;
+};
+
+#define to_ldo_info(dev) (struct ldo_info *)dev->driver_data
+
+#define DA9063_LDO(idx, min_mV, max_mV, step_mV) \
+{ \
+       .min_uV = min_mV * 1000, \
+       .max_uV = max_mV * 1000, \
+       .step_uV = step_mV * 1000, \
+       .ctrl_reg = DA9063_LDO##idx##_CONT, \
+       .volt_reg = DA9063_VLDO##idx##_A, \
+}
+
+static const struct ldo_info da9063_ldo_info[] = {
+       DA9063_LDO(1, 600, 1860, 20),
+       DA9063_LDO(2, 600, 1860, 20),
+       DA9063_LDO(3, 900, 3440, 20),
+       DA9063_LDO(4, 900, 3440, 20),
+       DA9063_LDO(5, 900, 3600, 50),
+       DA9063_LDO(6, 900, 3600, 50),
+       DA9063_LDO(7, 900, 3600, 50),
+       DA9063_LDO(8, 900, 3600, 50),
+       DA9063_LDO(9, 950, 3600, 50),
+       DA9063_LDO(10, 900, 3600, 50),
+       DA9063_LDO(11, 900, 3600, 50),
+};
+
+static int da9063_ldo_get_value(struct udevice *dev)
+{
+       struct ldo_info *info = to_ldo_info(dev);
+       int sel;
+
+       sel = pmic_reg_read(dev_get_parent(dev), info->volt_reg);
+       if (sel < 0)
+               return sel;
+       sel = FIELD_GET(DA9063_LDO_VSEL, sel);
+       return info->min_uV + (info->step_uV * sel);
+}
+
+static int da9063_ldo_set_value(struct udevice *dev, int uV)
+{
+       struct ldo_info *info = to_ldo_info(dev);
+       int sel;
+
+       sel = pmic_reg_read(dev_get_parent(dev), info->volt_reg);
+       if (sel < 0)
+               return sel;
+       sel &= ~DA9063_LDO_VSEL;
+       sel |= FIELD_PREP(DA9063_LDO_VSEL,
+                         DIV_ROUND_UP(uV - info->min_uV, info->step_uV));
+
+       return pmic_reg_write(dev_get_parent(dev), info->volt_reg, sel);
+}
+
+static int da9063_ldo_get_enable(struct udevice *dev)
+{
+       struct ldo_info *info = to_ldo_info(dev);
+       int cont = pmic_reg_read(dev_get_parent(dev), info->ctrl_reg);
+
+       if (cont < 0)
+               return cont;
+
+       return FIELD_GET(DA9063_LDO_ENABLE, cont);
+}
+
+static int da9063_ldo_set_enable(struct udevice *dev, bool enable)
+{
+       struct ldo_info *info = to_ldo_info(dev);
+       int cont = pmic_reg_read(dev_get_parent(dev), info->ctrl_reg);
+
+       if (cont < 0)
+               return cont;
+
+       cont &= ~DA9063_LDO_ENABLE;
+       cont |= FIELD_PREP(DA9063_LDO_ENABLE, enable);
+
+       return pmic_reg_write(dev_get_parent(dev), info->ctrl_reg, cont);
+}
+
+static int da9063_ldo_probe(struct udevice *dev)
+{
+       struct dm_regulator_uclass_platdata *uc_pdata;
+
+       if (dev->driver_data < 1 ||
+           dev->driver_data > ARRAY_SIZE(da9063_ldo_info))
+               return -EINVAL;
+
+       uc_pdata = dev_get_uclass_platdata(dev);
+
+       dev->driver_data = (ulong)&da9063_ldo_info[dev->driver_data - 1];
+       uc_pdata->type = REGULATOR_TYPE_LDO;
+       uc_pdata->mode_count = 0;
+
+       return 0;
+}
+
+static const struct dm_regulator_ops da9063_ldo_ops = {
+       .get_value = da9063_ldo_get_value,
+       .set_value = da9063_ldo_set_value,
+       .get_enable = da9063_ldo_get_enable,
+       .set_enable = da9063_ldo_set_enable,
+};
+
+U_BOOT_DRIVER(da9063_ldo) = {
+       .name = DA9063_LDO_DRIVER,
+       .id = UCLASS_REGULATOR,
+       .ops = &da9063_ldo_ops,
+       .probe = da9063_ldo_probe,
+};
diff --git a/include/power/da9063_pmic.h b/include/power/da9063_pmic.h
new file mode 100644
index 0000000000..7258987ae3
--- /dev/null
+++ b/include/power/da9063_pmic.h
@@ -0,0 +1,303 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2019 Collabora
+ * (C) Copyright 2019 GE
+ */
+
+#ifndef __DA9063_PMIC_H_
+#define __DA9063_PMIC_H_
+
+#include <linux/bitops.h>
+#include <power/pmic.h>
+
+enum {
+       DA9063_PAGE_CON                 = 0x0,
+
+       /* System Control and Event Registers */
+       DA9063_STATUS_A,
+       DA9063_STATUS_B,
+       DA9063_STATUS_C,
+       DA9063_STATUS_D,
+       DA9063_FAULT_LOG,
+       DA9063_EVENT_A,
+       DA9063_EVENT_B,
+       DA9063_EVENT_C,
+       DA9063_EVENT_D,
+       DA9063_IRQ_MASK_A,
+       DA9063_IRQ_MASK_B,
+       DA9063_IRQ_MASK_C,
+       DA9063_IRQ_MASK_D,
+       DA9063_CONTROL_A,
+       DA9063_CONTROL_B,
+       DA9063_CONTROL_C,
+       DA9063_CONTROL_D,
+       DA9063_CONTROL_E,
+       DA9063_CONTROL_F,
+       DA9063_PD_DIS,
+
+       /* GPIO Control Registers */
+       DA9063_GPIO_0_1,
+       DA9063_GPIO_2_3,
+       DA9063_GPIO_4_5,
+       DA9063_GPIO_6_7,
+       DA9063_GPIO_8_9,
+       DA9063_GPIO_10_11,
+       DA9063_GPIO_12_13,
+       DA9063_GPIO_14_15,
+       DA9063_GPIO_MODE0_7,
+       DA9063_GPIO_MODE8_15,
+       DA9063_SWITCH_CONT,
+
+       /* Regulator Control Registers */
+       DA9063_BCORE2_CONT,
+       DA9063_BCORE1_CONT,
+       DA9063_BPRO_CONT,
+       DA9063_BMEM_CONT,
+       DA9063_BIO_CONT,
+       DA9063_BPERI_CONT,
+       DA9063_LDO1_CONT,
+       DA9063_LDO2_CONT,
+       DA9063_LDO3_CONT,
+       DA9063_LDO4_CONT,
+       DA9063_LDO5_CONT,
+       DA9063_LDO6_CONT,
+       DA9063_LDO7_CONT,
+       DA9063_LDO8_CONT,
+       DA9063_LDO9_CONT,
+       DA9063_LDO10_CONT,
+       DA9063_LDO11_CONT,
+       DA9063_SUPPLIES,
+       DA9063_DVC_1,
+       DA9063_DVC_2,
+
+       /* GP-ADC Control Registers */
+       DA9063_ADC_MAN,
+       DA9063_ADC_CONT,
+       DA9063_VSYS_MON,
+       DA9063_ADC_RES_L,
+       DA9063_ADC_RES_H,
+       DA9063_VSYS_RES,
+       DA9063_ADCIN1_RES,
+       DA9063_ADCIN2_RES,
+       DA9063_ADCIN3_RES,
+       DA9063_MON_A8_RES,
+       DA9063_MON_A9_RES,
+       DA9063_MON_A10_RES,
+
+       /* RTC Calendar and Alarm Registers */
+       DA9063_COUNT_S,
+       DA9063_COUNT_MI,
+       DA9063_COUNT_H,
+       DA9063_COUNT_D,
+       DA9063_COUNT_MO,
+       DA9063_COUNT_Y,
+
+       DA9063_ALARM_S,
+       DA9063_ALARM_MI,
+       DA9063_ALARM_H,
+       DA9063_ALARM_D,
+       DA9063_ALARM_MO,
+       DA9063_ALARM_Y,
+       DA9063_SECOND_A,
+       DA9063_SECOND_B,
+       DA9063_SECOND_C,
+       DA9063_SECOND_D,
+
+       /* Sequencer Control Registers */
+       DA9063_SEQ                      = 0x81,
+       DA9063_SEQ_TIMER,
+       DA9063_ID_2_1,
+       DA9063_ID_4_3,
+       DA9063_ID_6_5,
+       DA9063_ID_8_7,
+       DA9063_ID_10_9,
+       DA9063_ID_12_11,
+       DA9063_ID_14_13,
+       DA9063_ID_16_15,
+       DA9063_ID_18_17,
+       DA9063_ID_20_19,
+       DA9063_ID_22_21,
+       DA9063_ID_24_23,
+       DA9063_ID_26_25,
+       DA9063_ID_28_27,
+       DA9063_ID_30_29,
+       DA9063_ID_32_31,
+       DA9063_SEQ_A,
+       DA9063_SEQ_B,
+       DA9063_WAIT,
+       DA9063_EN_32K,
+       DA9063_RESET,
+
+       /* Regulator Setting Registers */
+       DA9063_BUCK_ILIM_A,
+       DA9063_BUCK_ILIM_B,
+       DA9063_BUCK_ILIM_C,
+       DA9063_BCORE2_CFG,
+       DA9063_BCORE1_CFG,
+       DA9063_BPRO_CFG,
+       DA9063_BIO_CFG,
+       DA9063_BMEM_CFG,
+       DA9063_BPERI_CFG,
+       DA9063_VBCORE2_A,
+       DA9063_VBCORE1_A,
+       DA9063_VBPRO_A,
+       DA9063_VBMEM_A,
+       DA9063_VBIO_A,
+       DA9063_VBPERI_A,
+       DA9063_VLDO1_A,
+       DA9063_VLDO2_A,
+       DA9063_VLDO3_A,
+       DA9063_VLDO4_A,
+       DA9063_VLDO5_A,
+       DA9063_VLDO6_A,
+       DA9063_VLDO7_A,
+       DA9063_VLDO8_A,
+       DA9063_VLDO9_A,
+       DA9063_VLDO10_A,
+       DA9063_VLDO11_A,
+       DA9063_VBCORE2_B,
+       DA9063_VBCORE1_B,
+       DA9063_VBPRO_B,
+       DA9063_VBMEM_B,
+       DA9063_VBIO_B,
+       DA9063_VBPERI_B,
+       DA9063_VLDO1_B,
+       DA9063_VLDO2_B,
+       DA9063_VLDO3_B,
+       DA9063_VLDO4_B,
+       DA9063_VLDO5_B,
+       DA9063_VLDO6_B,
+       DA9063_VLDO7_B,
+       DA9063_VLDO8_B,
+       DA9063_VLDO9_B,
+       DA9063_VLDO10_B,
+       DA9063_VLDO11_B,
+
+       /* Backup Battery Charger Control Register */
+       DA9063_BBAT_CONT,
+
+       /* GPIO PWM (LED) */
+       DA9063_GPO11_LED,
+       DA9063_GPO14_LED,
+       DA9063_GPO15_LED,
+
+       /* GP-ADC Threshold Registers */
+       DA9063_ADC_CFG,
+       DA9063_AUTO1_HIGH,
+       DA9063_AUTO1_LOW,
+       DA9063_AUTO2_HIGH,
+       DA9063_AUTO2_LOW,
+       DA9063_AUTO3_HIGH,
+       DA9063_AUTO3_LOW,
+
+       /* DA9063 Configuration registers */
+       /* OTP */
+       DA9063_OTP_CONT                 = 0x101,
+       DA9063_OTP_ADDR,
+       DA9063_OTP_DATA,
+
+       /* Customer Trim and Configuration */
+       DA9063_T_OFFSET,
+       DA9063_INTERFACE,
+       DA9063_CONFIG_A,
+       DA9063_CONFIG_B,
+       DA9063_CONFIG_C,
+       DA9063_CONFIG_D,
+       DA9063_CONFIG_E,
+       DA9063_CONFIG_F,
+       DA9063_CONFIG_G,
+       DA9063_CONFIG_H,
+       DA9063_CONFIG_I,
+       DA9063_CONFIG_J,
+       DA9063_CONFIG_K,
+       DA9063_CONFIG_L,
+
+       DA9063_CONFIG_M,
+       DA9063_CONFIG_N,
+
+       DA9063_MON_REG_1,
+       DA9063_MON_REG_2,
+       DA9063_MON_REG_3,
+       DA9063_MON_REG_4,
+       DA9063_MON_REG_5                = 0x11E,
+       DA9063_MON_REG_6,
+       DA9063_TRIM_CLDR,
+       /* General Purpose Registers */
+       DA9063_GP_ID_0,
+       DA9063_GP_ID_1,
+       DA9063_GP_ID_2,
+       DA9063_GP_ID_3,
+       DA9063_GP_ID_4,
+       DA9063_GP_ID_5,
+       DA9063_GP_ID_6,
+       DA9063_GP_ID_7,
+       DA9063_GP_ID_8,
+       DA9063_GP_ID_9,
+       DA9063_GP_ID_10,
+       DA9063_GP_ID_11,
+       DA9063_GP_ID_12,
+       DA9063_GP_ID_13,
+       DA9063_GP_ID_14,
+       DA9063_GP_ID_15,
+       DA9063_GP_ID_16,
+       DA9063_GP_ID_17,
+       DA9063_GP_ID_18,
+       DA9063_GP_ID_19,
+
+       /* Chip ID and variant */
+       DA9063_CHIP_ID                  = 0x181,
+       DA9063_CHIP_VARIANT,
+
+       DA9063_NUM_OF_REGS,
+};
+
+#define DA9063_REG_PAGE_MASK           GENMASK(8, 7)
+#define DA9063_REG_ADDR_MASK           GENMASK(6, 0)
+
+#define DA9063_PROTO_ADDR_MASK         GENMASK(7, 1)
+#define DA9063_PROTO_RW_MASK           BIT(0)
+#define DA9063_PROTO_READ              1
+#define DA9063_PROTO_WRITE             0
+#define DA9063_PROTO_LEN               16
+
+/* DA9063_PAGE_CON - 0x0 */
+#define DA9063_PAGE_CON_PAGE                   GENMASK(2, 0)
+#define DA9063_PAGE_CON_WRITE_MODE             BIT(6)
+#define DA9063_PAGE_CON_WRITE_MODE_PAGE                0
+#define DA9063_PAGE_CON_WRITE_MODE_REPEAT      1
+#define DA9063_PAGE_CON_REVERT                 BIT(7)
+
+/* DA9063_B<x>_CONT - 0x20 - 0x25 */
+#define DA9063_BUCK_ENABLE     BIT(0)
+
+/* DA9063_LDO<x>_CONT - 0x26 - 0x30 */
+#define DA9063_LDO_ENABLE      BIT(0)
+
+/* DA9063_B<x>_CFG - 0x9D - 0xA2 */
+#define DA9063_BUCK_MODE       GENMASK(7, 6)
+#define DA9063_BUCK_MODE_MANUAL        0
+#define DA9063_BUCK_MODE_SLEEP 1
+#define DA9063_BUCK_MODE_SYNC  2
+#define DA9063_BUCK_MODE_AUTO  3
+
+/* DA9063_VB<x>_A - 0xA3 - 0xA8 */
+#define DA9063_BUCK_VSEL       GENMASK(6, 0)
+
+/* DA9063_VLDO<x>_A - 0xA9 - 0xB3 */
+#define DA9063_LDO_VSEL                GENMASK(5, 0)
+
+/* DA9063_CHIP_ID - 0x181 */
+#define DA9063_CHIP_ID_DA9063  0x61
+
+/* regulator operating modes */
+enum {
+       DA9063_OPMODE_AUTO,
+       DA9063_OPMODE_SYNC,
+};
+
+/* Drivers name */
+#define DA9063_LDO_DRIVER      "da9063_ldo"
+#define DA9063_BUCK_DRIVER     "da9063_buck"
+
+#endif /* __DA9063_PMIC_H_ */
+
-- 
2.20.1

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
https://lists.denx.de/listinfo/u-boot

Reply via email to