uboot/drivers/power/pmic/pmic-uclass.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2014-2015 Samsung Electronics
   4 * Przemyslaw Marczak <p.marczak@samsung.com>
   5 */
   6
   7#define LOG_CATEGORY UCLASS_PMIC
   8
   9#include <common.h>
  10#include <fdtdec.h>
  11#include <errno.h>
  12#include <dm.h>
  13#include <log.h>
  14#include <vsprintf.h>
  15#include <dm/lists.h>
  16#include <dm/device-internal.h>
  17#include <dm/uclass-internal.h>
  18#include <power/pmic.h>
  19#include <linux/ctype.h>
  20
  21#if CONFIG_IS_ENABLED(PMIC_CHILDREN)
  22int pmic_bind_children(struct udevice *pmic, ofnode parent,
  23                       const struct pmic_child_info *child_info)
  24{
  25        const struct pmic_child_info *info;
  26        struct driver *drv;
  27        struct udevice *child;
  28        const char *node_name;
  29        const char *reg_name;
  30        int bind_count = 0;
  31        ofnode node;
  32        int prefix_len;
  33        int ret;
  34
  35        debug("%s for '%s' at node offset: %d\n", __func__, pmic->name,
  36              dev_of_offset(pmic));
  37
  38        ofnode_for_each_subnode(node, parent) {
  39                node_name = ofnode_get_name(node);
  40
  41                debug("* Found child node: '%s'\n", node_name);
  42
  43                child = NULL;
  44                for (info = child_info; info->prefix && info->driver; info++) {
  45                        debug("  - compatible prefix: '%s'\n", info->prefix);
  46
  47                        prefix_len = strlen(info->prefix);
  48                        if (strncmp(info->prefix, node_name, prefix_len)) {
  49                                reg_name = ofnode_read_string(node,
  50                                                              "regulator-name");
  51                                if (!reg_name)
  52                                        continue;
  53                                if (strncmp(info->prefix, reg_name, prefix_len))
  54                                        continue;
  55                        }
  56
  57                        drv = lists_driver_lookup_name(info->driver);
  58                        if (!drv) {
  59                                debug("  - driver: '%s' not found!\n",
  60                                      info->driver);
  61                                continue;
  62                        }
  63
  64                        debug("  - found child driver: '%s'\n", drv->name);
  65
  66                        ret = device_bind_with_driver_data(pmic, drv, node_name,
  67                                                           0, node, &child);
  68                        if (ret) {
  69                                debug("  - child binding error: %d\n", ret);
  70                                continue;
  71                        }
  72
  73                        debug("  - bound child device: '%s'\n", child->name);
  74
  75                        child->driver_data = trailing_strtol(node_name);
  76
  77                        debug("  - set 'child->driver_data': %lu\n",
  78                              child->driver_data);
  79                        break;
  80                }
  81
  82                if (child)
  83                        bind_count++;
  84                else
  85                        debug("  - compatible prefix not found\n");
  86        }
  87
  88        debug("Bound: %d children for PMIC: '%s'\n", bind_count, pmic->name);
  89        return bind_count;
  90}
  91#endif
  92
  93int pmic_get(const char *name, struct udevice **devp)
  94{
  95        return uclass_get_device_by_name(UCLASS_PMIC, name, devp);
  96}
  97
  98int pmic_reg_count(struct udevice *dev)
  99{
 100        const struct dm_pmic_ops *ops = dev_get_driver_ops(dev);
 101
 102        if (!ops || !ops->reg_count)
 103                return -ENOSYS;
 104
 105        return ops->reg_count(dev);
 106}
 107
 108int pmic_read(struct udevice *dev, uint reg, uint8_t *buffer, int len)
 109{
 110        const struct dm_pmic_ops *ops = dev_get_driver_ops(dev);
 111
 112        if (!buffer)
 113                return -EFAULT;
 114
 115        if (!ops || !ops->read)
 116                return -ENOSYS;
 117
 118        return ops->read(dev, reg, buffer, len);
 119}
 120
 121int pmic_write(struct udevice *dev, uint reg, const uint8_t *buffer, int len)
 122{
 123        const struct dm_pmic_ops *ops = dev_get_driver_ops(dev);
 124
 125        if (!buffer)
 126                return -EFAULT;
 127
 128        if (!ops || !ops->write)
 129                return -ENOSYS;
 130
 131        return ops->write(dev, reg, buffer, len);
 132}
 133
 134int pmic_reg_read(struct udevice *dev, uint reg)
 135{
 136        struct uc_pmic_priv *priv = dev_get_uclass_priv(dev);
 137        u32 val = 0;
 138        int ret;
 139
 140        if (priv->trans_len < 1 || priv->trans_len > sizeof(val)) {
 141                debug("Wrong transmission size [%d]\n", priv->trans_len);
 142                return -EINVAL;
 143        }
 144
 145        debug("%s: reg=%x priv->trans_len:%d", __func__, reg, priv->trans_len);
 146        ret = pmic_read(dev, reg, (uint8_t *)&val, priv->trans_len);
 147        debug(", value=%x, ret=%d\n", val, ret);
 148
 149        return ret ? ret : val;
 150}
 151
 152int pmic_reg_write(struct udevice *dev, uint reg, uint value)
 153{
 154        struct uc_pmic_priv *priv = dev_get_uclass_priv(dev);
 155        int ret;
 156
 157        if (priv->trans_len < 1 || priv->trans_len > sizeof(value)) {
 158                debug("Wrong transmission size [%d]\n", priv->trans_len);
 159                return -EINVAL;
 160        }
 161
 162        debug("%s: reg=%x, value=%x priv->trans_len:%d", __func__, reg, value,
 163              priv->trans_len);
 164        ret = pmic_write(dev, reg, (uint8_t *)&value, priv->trans_len);
 165        debug(", ret=%d\n", ret);
 166
 167        return ret;
 168}
 169
 170int pmic_clrsetbits(struct udevice *dev, uint reg, uint clr, uint set)
 171{
 172        struct uc_pmic_priv *priv = dev_get_uclass_priv(dev);
 173        u32 val = 0;
 174        int ret;
 175
 176        if (priv->trans_len < 1 || priv->trans_len > sizeof(val)) {
 177                debug("Wrong transmission size [%d]\n", priv->trans_len);
 178                return -EINVAL;
 179        }
 180
 181        ret = pmic_read(dev, reg, (uint8_t *)&val, priv->trans_len);
 182        if (ret < 0)
 183                return ret;
 184
 185        val = (val & ~clr) | set;
 186        return pmic_write(dev, reg, (uint8_t *)&val, priv->trans_len);
 187}
 188
 189static int pmic_pre_probe(struct udevice *dev)
 190{
 191        struct uc_pmic_priv *pmic_priv = dev_get_uclass_priv(dev);
 192
 193        pmic_priv->trans_len = 1;
 194        return 0;
 195}
 196
 197UCLASS_DRIVER(pmic) = {
 198        .id             = UCLASS_PMIC,
 199        .name           = "pmic",
 200        .pre_probe      = pmic_pre_probe,
 201        .per_device_auto        = sizeof(struct uc_pmic_priv),
 202};
 203