[U-Boot] [PATCH 36/37] dm: pmic: add da9063 PMIC driver and regulators

Robert Beckett
2019-10-15T15:53:49Z

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

Signed-off-by: Robert Beckett <bob.beckett@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