On Wed, 2019-10-16 at 07:24 +0000, Schrempf Frieder wrote: > Hi Robert, > > On 15.10.19 17:53, Robert Beckett wrote: > > Add DM driver to support Dialog DA9063. > > Currently it support binding regulator children. > > > > Signed-off-by: Robert Beckett <bob.beck...@collabora.com> > > I also have a board with DA9063 and was looking for support in U- > Boot. I > found patches from Martin Fuzzey [1] and pulled them in almost as is > and > found them to work just fine. > > Unfortunately I didn't have time to resend them yet, but you can > find > the rebased patches here: [2]. > > On a first glance your implementation looks different, so it seems > you > didn't use Martin's patches. Though the resulting features probably > will > be similar. > > I only had a very quick look and one difference seems to be that > your > regulator implementation supports the AUTO and SYNC mode, while > Martin's > version supports AUTO, SYNC and SLEEP. There might be other > differences. > > What do you think? Which version would be better?
(+cc Martin Fuzzey) Huh, I had not seen that. Martin's versions looks more complete than mine, so I would say go with that one. Martin: any objections to including your patches in here? I dont mind pushing it through and handling any review comments etc. I am keen to get get this upstreamed. > > Also find a few comments below, though I didn't do a full review, > yet. > > Thanks, > Frieder > > [1] https://patchwork.ozlabs.org/cover/979346/ > [2] https://github.com/fschrempf/u-boot/commits/da9063 > > > --- > > 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 > > It would be good to be able to enable the driver for U-Boot proper > and > SPL separately. So this should be CONFIG_$(SPL_)DM_PMIC_DA9063. > > > > > 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 > > This should not be here. > > > +#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 > > It would be good to be able to enable the driver for U-Boot proper > and > SPL separately. So this should be CONFIG_$(SPL_)DM_REGULATOR_DA9063. > > > 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_ */ > > + _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot