diff options
author | Martin Fuzzey <martin.fuzzey@flowbird.group> | 2020-01-14 15:56:16 +0000 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2020-01-27 19:54:20 -0500 |
commit | 483880c490b0fbd4e4be5a93f55947a42066f825 (patch) | |
tree | 1c9b3487a512da48ff542f5f46eaab35804be72e /drivers/power | |
parent | e1d26a7642253a4b745a69c5faef494dd0b5c01a (diff) |
power: pmic: add driver for Dialog DA9063 PMIC
This adds the basic register access operations and child regulator
binding (if a regulator driver exists).
Robert Beckett: simplify accesses by using bottom bit of address as
offset overflow. This avoids the need to track which page we are on.
Add an option CONFIG_SPL_DM_PMIC_DA9063.
Signed-off-by: Martin Fuzzey <martin.fuzzey@flowbird.group>
Signed-off-by: Robert Beckett <bob.beckett@collabora.com>
Diffstat (limited to 'drivers/power')
-rw-r--r-- | drivers/power/pmic/Kconfig | 14 | ||||
-rw-r--r-- | drivers/power/pmic/Makefile | 1 | ||||
-rw-r--r-- | drivers/power/pmic/da9063.c | 130 |
3 files changed, 145 insertions, 0 deletions
diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig index df9372c239..ef8bf49d49 100644 --- a/drivers/power/pmic/Kconfig +++ b/drivers/power/pmic/Kconfig @@ -40,6 +40,20 @@ config PMIC_ACT8846 functions. It uses an I2C interface and is designed for use with tablets and smartphones. +config DM_PMIC_DA9063 + bool "Enable Driver Model for the Dialog DA9063 PMIC" + depends on DM_PMIC + help + This config enables implementation of driver-model pmic uclass features + for PMIC DA9063. The driver implements read/write operations. + +config SPL_DM_PMIC_DA9063 + bool "Enable Driver Model for the Dialog DA9063 PMIC in SPL" + depends on DM_PMIC && SPL + help + This config enables implementation of driver-model pmic uclass features + for PMIC DA9063. The driver implements read/write operations. + config PMIC_AS3722 bool "Enable support for the Austria Micro Systems (AMS) AS7322 PMIC" help diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile index 7b6cb0ee1b..9cd6c375c0 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_DM_PMIC) += pmic-uclass.o obj-$(CONFIG_DM_PMIC_FAN53555) += fan53555.o +obj-$(CONFIG_$(SPL_)DM_PMIC_DA9063) += da9063.o obj-$(CONFIG_DM_PMIC_MAX77686) += max77686.o obj-$(CONFIG_DM_PMIC_MAX8998) += max8998.o obj-$(CONFIG_DM_PMIC_MC34708) += mc34708.o diff --git a/drivers/power/pmic/da9063.c b/drivers/power/pmic/da9063.c new file mode 100644 index 0000000000..abda7a5a40 --- /dev/null +++ b/drivers/power/pmic/da9063.c @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018 Flowbird + * Martin Fuzzey <martin.fuzzey@flowbird.group> + */ + +#include <common.h> +#include <fdtdec.h> +#include <errno.h> +#include <dm.h> +#include <i2c.h> +#include <power/pmic.h> +#include <power/regulator.h> +#include <power/da9063_pmic.h> + +static const struct pmic_child_info pmic_children_info[] = { + { .prefix = "ldo", .driver = DA9063_LDO_DRIVER }, + { .prefix = "b", .driver = DA9063_BUCK_DRIVER }, + { }, +}; + +/* + * The register map is non contiguous and attempts to read in the holes fail. + * But "pmic dump" tries to dump the full register map. + * So define the holes here so we can fix that. + */ +struct da9063_reg_hole { + u16 first; + u16 last; +}; + +static const struct da9063_reg_hole da9063_reg_holes[] = { + DA9063_REG_HOLE_1, + DA9063_REG_HOLE_2, + DA9063_REG_HOLE_3, + /* These aren't readable. I can't see why from the datasheet but + * attempts to read fail and the kernel marks them unreadable too, + */ + {DA9063_REG_OTP_COUNT, DA9063_REG_OTP_DATA}, +}; + +static int da9063_reg_count(struct udevice *dev) +{ + return DA9063_NUM_OF_REGS; +} + +static bool da9063_reg_valid(uint reg) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(da9063_reg_holes); i++) { + const struct da9063_reg_hole *hole = &da9063_reg_holes[i]; + + if (reg >= hole->first && reg <= hole->last) + return false; + } + + return true; +} + +static int da9063_write(struct udevice *dev, uint reg, const uint8_t *buff, + int len) +{ + if (dm_i2c_write(dev, reg, buff, len)) { + pr_err("write error to device: %p register: %#x!", dev, reg); + return -EIO; + } + + return 0; +} + +static int da9063_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +{ + if (!da9063_reg_valid(reg)) + return -ENODATA; + + if (dm_i2c_read(dev, reg, buff, len)) { + pr_err("read error from device: %p register: %#x!", dev, reg); + return -EIO; + } + + return 0; +} + +static int da9063_bind(struct udevice *dev) +{ + ofnode regulators_node; + int children; + + regulators_node = dev_read_subnode(dev, "regulators"); + if (!ofnode_valid(regulators_node)) { + debug("%s: %s regulators subnode not found!", __func__, + dev->name); + return -ENXIO; + } + + debug("%s: '%s' - found regulators subnode\n", __func__, dev->name); + + children = pmic_bind_children(dev, regulators_node, pmic_children_info); + if (!children) + debug("%s: %s - no child found\n", __func__, dev->name); + + /* Always return success for this device */ + return 0; +} + +static int da9063_probe(struct udevice *dev) +{ + return i2c_set_chip_addr_offset_mask(dev, 0x1); +} + +static struct dm_pmic_ops da9063_ops = { + .reg_count = da9063_reg_count, + .read = da9063_read, + .write = da9063_write, +}; + +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, + .probe = da9063_probe, + .ops = &da9063_ops, +}; |