uboot/drivers/power/regulator/regulator-uclass.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2014-2015 Samsung Electronics
   3 * Przemyslaw Marczak <p.marczak@samsung.com>
   4 *
   5 * SPDX-License-Identifier:     GPL-2.0+
   6 */
   7#include <common.h>
   8#include <fdtdec.h>
   9#include <errno.h>
  10#include <dm.h>
  11#include <dm/uclass-internal.h>
  12#include <power/pmic.h>
  13#include <power/regulator.h>
  14
  15DECLARE_GLOBAL_DATA_PTR;
  16
  17int regulator_mode(struct udevice *dev, struct dm_regulator_mode **modep)
  18{
  19        struct dm_regulator_uclass_platdata *uc_pdata;
  20
  21        *modep = NULL;
  22
  23        uc_pdata = dev_get_uclass_platdata(dev);
  24        if (!uc_pdata)
  25                return -ENXIO;
  26
  27        *modep = uc_pdata->mode;
  28        return uc_pdata->mode_count;
  29}
  30
  31int regulator_get_value(struct udevice *dev)
  32{
  33        const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
  34
  35        if (!ops || !ops->get_value)
  36                return -ENOSYS;
  37
  38        return ops->get_value(dev);
  39}
  40
  41int regulator_set_value(struct udevice *dev, int uV)
  42{
  43        const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
  44
  45        if (!ops || !ops->set_value)
  46                return -ENOSYS;
  47
  48        return ops->set_value(dev, uV);
  49}
  50
  51int regulator_get_current(struct udevice *dev)
  52{
  53        const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
  54
  55        if (!ops || !ops->get_current)
  56                return -ENOSYS;
  57
  58        return ops->get_current(dev);
  59}
  60
  61int regulator_set_current(struct udevice *dev, int uA)
  62{
  63        const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
  64
  65        if (!ops || !ops->set_current)
  66                return -ENOSYS;
  67
  68        return ops->set_current(dev, uA);
  69}
  70
  71bool regulator_get_enable(struct udevice *dev)
  72{
  73        const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
  74
  75        if (!ops || !ops->get_enable)
  76                return -ENOSYS;
  77
  78        return ops->get_enable(dev);
  79}
  80
  81int regulator_set_enable(struct udevice *dev, bool enable)
  82{
  83        const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
  84
  85        if (!ops || !ops->set_enable)
  86                return -ENOSYS;
  87
  88        return ops->set_enable(dev, enable);
  89}
  90
  91int regulator_get_mode(struct udevice *dev)
  92{
  93        const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
  94
  95        if (!ops || !ops->get_mode)
  96                return -ENOSYS;
  97
  98        return ops->get_mode(dev);
  99}
 100
 101int regulator_set_mode(struct udevice *dev, int mode)
 102{
 103        const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
 104
 105        if (!ops || !ops->set_mode)
 106                return -ENOSYS;
 107
 108        return ops->set_mode(dev, mode);
 109}
 110
 111int regulator_get_by_platname(const char *plat_name, struct udevice **devp)
 112{
 113        struct dm_regulator_uclass_platdata *uc_pdata;
 114        struct udevice *dev;
 115        int ret;
 116
 117        *devp = NULL;
 118
 119        for (ret = uclass_find_first_device(UCLASS_REGULATOR, &dev); dev;
 120             ret = uclass_find_next_device(&dev)) {
 121                if (ret)
 122                        continue;
 123
 124                uc_pdata = dev_get_uclass_platdata(dev);
 125                if (!uc_pdata || strcmp(plat_name, uc_pdata->name))
 126                        continue;
 127
 128                return uclass_get_device_tail(dev, 0, devp);
 129        }
 130
 131        debug("%s: can't find: %s\n", __func__, plat_name);
 132
 133        return -ENODEV;
 134}
 135
 136int regulator_get_by_devname(const char *devname, struct udevice **devp)
 137{
 138        return uclass_get_device_by_name(UCLASS_REGULATOR, devname, devp);
 139}
 140
 141int device_get_supply_regulator(struct udevice *dev, const char *supply_name,
 142                                struct udevice **devp)
 143{
 144        return uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
 145                                            supply_name, devp);
 146}
 147
 148int regulator_autoset(struct udevice *dev)
 149{
 150        struct dm_regulator_uclass_platdata *uc_pdata;
 151        int ret = 0;
 152
 153        uc_pdata = dev_get_uclass_platdata(dev);
 154        if (!uc_pdata->always_on && !uc_pdata->boot_on)
 155                return -EMEDIUMTYPE;
 156
 157        if (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UV)
 158                ret = regulator_set_value(dev, uc_pdata->min_uV);
 159        if (!ret && (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UA))
 160                ret = regulator_set_current(dev, uc_pdata->min_uA);
 161
 162        if (!ret)
 163                ret = regulator_set_enable(dev, true);
 164
 165        return ret;
 166}
 167
 168static void regulator_show(struct udevice *dev, int ret)
 169{
 170        struct dm_regulator_uclass_platdata *uc_pdata;
 171
 172        uc_pdata = dev_get_uclass_platdata(dev);
 173
 174        printf("%s@%s: ", dev->name, uc_pdata->name);
 175        if (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UV)
 176                printf("set %d uV", uc_pdata->min_uV);
 177        if (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UA)
 178                printf("; set %d uA", uc_pdata->min_uA);
 179        printf("; enabling");
 180        if (ret)
 181                printf(" (ret: %d)\n", ret);
 182        printf("\n");
 183}
 184
 185int regulator_autoset_by_name(const char *platname, struct udevice **devp)
 186{
 187        struct udevice *dev;
 188        int ret;
 189
 190        ret = regulator_get_by_platname(platname, &dev);
 191        if (devp)
 192                *devp = dev;
 193        if (ret) {
 194                debug("Can get the regulator: %s!", platname);
 195                return ret;
 196        }
 197
 198        return regulator_autoset(dev);
 199}
 200
 201int regulator_list_autoset(const char *list_platname[],
 202                           struct udevice *list_devp[],
 203                           bool verbose)
 204{
 205        struct udevice *dev;
 206        int error = 0, i = 0, ret;
 207
 208        while (list_platname[i]) {
 209                ret = regulator_autoset_by_name(list_platname[i], &dev);
 210                if (ret != -EMEDIUMTYPE && verbose)
 211                        regulator_show(dev, ret);
 212                if (ret & !error)
 213                        error = ret;
 214
 215                if (list_devp)
 216                        list_devp[i] = dev;
 217
 218                i++;
 219        }
 220
 221        return error;
 222}
 223
 224static bool regulator_name_is_unique(struct udevice *check_dev,
 225                                     const char *check_name)
 226{
 227        struct dm_regulator_uclass_platdata *uc_pdata;
 228        struct udevice *dev;
 229        int check_len = strlen(check_name);
 230        int ret;
 231        int len;
 232
 233        for (ret = uclass_find_first_device(UCLASS_REGULATOR, &dev); dev;
 234             ret = uclass_find_next_device(&dev)) {
 235                if (ret || dev == check_dev)
 236                        continue;
 237
 238                uc_pdata = dev_get_uclass_platdata(dev);
 239                len = strlen(uc_pdata->name);
 240                if (len != check_len)
 241                        continue;
 242
 243                if (!strcmp(uc_pdata->name, check_name))
 244                        return false;
 245        }
 246
 247        return true;
 248}
 249
 250static int regulator_post_bind(struct udevice *dev)
 251{
 252        struct dm_regulator_uclass_platdata *uc_pdata;
 253        int offset = dev->of_offset;
 254        const void *blob = gd->fdt_blob;
 255        const char *property = "regulator-name";
 256
 257        uc_pdata = dev_get_uclass_platdata(dev);
 258        if (!uc_pdata)
 259                return -ENXIO;
 260
 261        /* Regulator's mandatory constraint */
 262        uc_pdata->name = fdt_getprop(blob, offset, property, NULL);
 263        if (!uc_pdata->name) {
 264                debug("%s: dev: %s has no property 'regulator-name'\n",
 265                      __func__, dev->name);
 266                uc_pdata->name = fdt_get_name(blob, offset, NULL);
 267                if (!uc_pdata->name)
 268                        return -EINVAL;
 269        }
 270
 271        if (regulator_name_is_unique(dev, uc_pdata->name))
 272                return 0;
 273
 274        debug("\"%s\" of dev: \"%s\", has nonunique value: \"%s\"",
 275              property, dev->name, uc_pdata->name);
 276
 277        return -EINVAL;
 278}
 279
 280static int regulator_pre_probe(struct udevice *dev)
 281{
 282        struct dm_regulator_uclass_platdata *uc_pdata;
 283        int offset = dev->of_offset;
 284
 285        uc_pdata = dev_get_uclass_platdata(dev);
 286        if (!uc_pdata)
 287                return -ENXIO;
 288
 289        /* Regulator's optional constraints */
 290        uc_pdata->min_uV = fdtdec_get_int(gd->fdt_blob, offset,
 291                                          "regulator-min-microvolt", -ENODATA);
 292        uc_pdata->max_uV = fdtdec_get_int(gd->fdt_blob, offset,
 293                                          "regulator-max-microvolt", -ENODATA);
 294        uc_pdata->min_uA = fdtdec_get_int(gd->fdt_blob, offset,
 295                                          "regulator-min-microamp", -ENODATA);
 296        uc_pdata->max_uA = fdtdec_get_int(gd->fdt_blob, offset,
 297                                          "regulator-max-microamp", -ENODATA);
 298        uc_pdata->always_on = fdtdec_get_bool(gd->fdt_blob, offset,
 299                                              "regulator-always-on");
 300        uc_pdata->boot_on = fdtdec_get_bool(gd->fdt_blob, offset,
 301                                            "regulator-boot-on");
 302
 303        /* Those values are optional (-ENODATA if unset) */
 304        if ((uc_pdata->min_uV != -ENODATA) &&
 305            (uc_pdata->max_uV != -ENODATA) &&
 306            (uc_pdata->min_uV == uc_pdata->max_uV))
 307                uc_pdata->flags |= REGULATOR_FLAG_AUTOSET_UV;
 308
 309        /* Those values are optional (-ENODATA if unset) */
 310        if ((uc_pdata->min_uA != -ENODATA) &&
 311            (uc_pdata->max_uA != -ENODATA) &&
 312            (uc_pdata->min_uA == uc_pdata->max_uA))
 313                uc_pdata->flags |= REGULATOR_FLAG_AUTOSET_UA;
 314
 315        return 0;
 316}
 317
 318int regulators_enable_boot_on(bool verbose)
 319{
 320        struct udevice *dev;
 321        struct uclass *uc;
 322        int ret;
 323
 324        ret = uclass_get(UCLASS_REGULATOR, &uc);
 325        if (ret)
 326                return ret;
 327        for (uclass_first_device(UCLASS_REGULATOR, &dev);
 328             dev && !ret;
 329             uclass_next_device(&dev)) {
 330                ret = regulator_autoset(dev);
 331                if (ret == -EMEDIUMTYPE) {
 332                        ret = 0;
 333                        continue;
 334                }
 335                if (verbose)
 336                        regulator_show(dev, ret);
 337        }
 338
 339        return ret;
 340}
 341
 342UCLASS_DRIVER(regulator) = {
 343        .id             = UCLASS_REGULATOR,
 344        .name           = "regulator",
 345        .post_bind      = regulator_post_bind,
 346        .pre_probe      = regulator_pre_probe,
 347        .per_device_platdata_auto_alloc_size =
 348                                sizeof(struct dm_regulator_uclass_platdata),
 349};
 350