diff options
Diffstat (limited to 'roms/u-boot/drivers/power/pmic/pmic-uclass.c')
-rw-r--r-- | roms/u-boot/drivers/power/pmic/pmic-uclass.c | 200 |
1 files changed, 200 insertions, 0 deletions
diff --git a/roms/u-boot/drivers/power/pmic/pmic-uclass.c b/roms/u-boot/drivers/power/pmic/pmic-uclass.c new file mode 100644 index 000000000..79166b8bb --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/pmic-uclass.c @@ -0,0 +1,200 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2014-2015 Samsung Electronics + * Przemyslaw Marczak <p.marczak@samsung.com> + */ + +#include <common.h> +#include <fdtdec.h> +#include <errno.h> +#include <dm.h> +#include <log.h> +#include <vsprintf.h> +#include <dm/lists.h> +#include <dm/device-internal.h> +#include <dm/uclass-internal.h> +#include <power/pmic.h> +#include <linux/ctype.h> + +#if CONFIG_IS_ENABLED(PMIC_CHILDREN) +int pmic_bind_children(struct udevice *pmic, ofnode parent, + const struct pmic_child_info *child_info) +{ + const struct pmic_child_info *info; + struct driver *drv; + struct udevice *child; + const char *node_name; + const char *reg_name; + int bind_count = 0; + ofnode node; + int prefix_len; + int ret; + + debug("%s for '%s' at node offset: %d\n", __func__, pmic->name, + dev_of_offset(pmic)); + + ofnode_for_each_subnode(node, parent) { + node_name = ofnode_get_name(node); + + debug("* Found child node: '%s'\n", node_name); + + child = NULL; + for (info = child_info; info->prefix && info->driver; info++) { + debug(" - compatible prefix: '%s'\n", info->prefix); + + prefix_len = strlen(info->prefix); + if (strncmp(info->prefix, node_name, prefix_len)) { + reg_name = ofnode_read_string(node, + "regulator-name"); + if (!reg_name) + continue; + if (strncmp(info->prefix, reg_name, prefix_len)) + continue; + } + + drv = lists_driver_lookup_name(info->driver); + if (!drv) { + debug(" - driver: '%s' not found!\n", + info->driver); + continue; + } + + debug(" - found child driver: '%s'\n", drv->name); + + ret = device_bind_with_driver_data(pmic, drv, node_name, + 0, node, &child); + if (ret) { + debug(" - child binding error: %d\n", ret); + continue; + } + + debug(" - bound child device: '%s'\n", child->name); + + child->driver_data = trailing_strtol(node_name); + + debug(" - set 'child->driver_data': %lu\n", + child->driver_data); + break; + } + + if (child) + bind_count++; + else + debug(" - compatible prefix not found\n"); + } + + debug("Bound: %d children for PMIC: '%s'\n", bind_count, pmic->name); + return bind_count; +} +#endif + +int pmic_get(const char *name, struct udevice **devp) +{ + return uclass_get_device_by_name(UCLASS_PMIC, name, devp); +} + +int pmic_reg_count(struct udevice *dev) +{ + const struct dm_pmic_ops *ops = dev_get_driver_ops(dev); + + if (!ops || !ops->reg_count) + return -ENOSYS; + + return ops->reg_count(dev); +} + +int pmic_read(struct udevice *dev, uint reg, uint8_t *buffer, int len) +{ + const struct dm_pmic_ops *ops = dev_get_driver_ops(dev); + + if (!buffer) + return -EFAULT; + + if (!ops || !ops->read) + return -ENOSYS; + + return ops->read(dev, reg, buffer, len); +} + +int pmic_write(struct udevice *dev, uint reg, const uint8_t *buffer, int len) +{ + const struct dm_pmic_ops *ops = dev_get_driver_ops(dev); + + if (!buffer) + return -EFAULT; + + if (!ops || !ops->write) + return -ENOSYS; + + return ops->write(dev, reg, buffer, len); +} + +int pmic_reg_read(struct udevice *dev, uint reg) +{ + struct uc_pmic_priv *priv = dev_get_uclass_priv(dev); + u32 val = 0; + int ret; + + if (priv->trans_len < 1 || priv->trans_len > sizeof(val)) { + debug("Wrong transmission size [%d]\n", priv->trans_len); + return -EINVAL; + } + + debug("%s: reg=%x priv->trans_len:%d", __func__, reg, priv->trans_len); + ret = pmic_read(dev, reg, (uint8_t *)&val, priv->trans_len); + debug(", value=%x, ret=%d\n", val, ret); + + return ret ? ret : val; +} + +int pmic_reg_write(struct udevice *dev, uint reg, uint value) +{ + struct uc_pmic_priv *priv = dev_get_uclass_priv(dev); + int ret; + + if (priv->trans_len < 1 || priv->trans_len > sizeof(value)) { + debug("Wrong transmission size [%d]\n", priv->trans_len); + return -EINVAL; + } + + debug("%s: reg=%x, value=%x priv->trans_len:%d", __func__, reg, value, + priv->trans_len); + ret = pmic_write(dev, reg, (uint8_t *)&value, priv->trans_len); + debug(", ret=%d\n", ret); + + return ret; +} + +int pmic_clrsetbits(struct udevice *dev, uint reg, uint clr, uint set) +{ + struct uc_pmic_priv *priv = dev_get_uclass_priv(dev); + u32 val = 0; + int ret; + + if (priv->trans_len < 1 || priv->trans_len > sizeof(val)) { + debug("Wrong transmission size [%d]\n", priv->trans_len); + return -EINVAL; + } + + ret = pmic_read(dev, reg, (uint8_t *)&val, priv->trans_len); + if (ret < 0) + return ret; + + val = (val & ~clr) | set; + return pmic_write(dev, reg, (uint8_t *)&val, priv->trans_len); +} + +static int pmic_pre_probe(struct udevice *dev) +{ + struct uc_pmic_priv *pmic_priv = dev_get_uclass_priv(dev); + + pmic_priv->trans_len = 1; + return 0; +} + +UCLASS_DRIVER(pmic) = { + .id = UCLASS_PMIC, + .name = "pmic", + .pre_probe = pmic_pre_probe, + .per_device_auto = sizeof(struct uc_pmic_priv), +}; |