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        struct dm_regulator_uclass_platdata *uc_pdata;
  45
  46        uc_pdata = dev_get_uclass_platdata(dev);
  47        if (uc_pdata->min_uV != -ENODATA && uV < uc_pdata->min_uV)
  48                return -EINVAL;
  49        if (uc_pdata->max_uV != -ENODATA && uV > uc_pdata->max_uV)
  50                return -EINVAL;
  51
  52        if (!ops || !ops->set_value)
  53                return -ENOSYS;
  54
  55        return ops->set_value(dev, uV);
  56}
  57
  58/*
  59 * To be called with at most caution as there is no check
  60 * before setting the actual voltage value.
  61 */
  62int regulator_set_value_force(struct udevice *dev, int uV)
  63{
  64        const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
  65
  66        if (!ops || !ops->set_value)
  67                return -ENOSYS;
  68
  69        return ops->set_value(dev, uV);
  70}
  71
  72int regulator_get_current(struct udevice *dev)
  73{
  74        const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
  75
  76        if (!ops || !ops->get_current)
  77                return -ENOSYS;
  78
  79        return ops->get_current(dev);
  80}
  81
  82int regulator_set_current(struct udevice *dev, int uA)
  83{
  84        const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
  85        struct dm_regulator_uclass_platdata *uc_pdata;
  86
  87        uc_pdata = dev_get_uclass_platdata(dev);
  88        if (uc_pdata->min_uA != -ENODATA && uA < uc_pdata->min_uA)
  89                return -EINVAL;
  90        if (uc_pdata->max_uA != -ENODATA && uA > uc_pdata->max_uA)
  91                return -EINVAL;
  92
  93        if (!ops || !ops->set_current)
  94                return -ENOSYS;
  95
  96        return ops->set_current(dev, uA);
  97}
  98
  99bool regulator_get_enable(struct udevice *dev)
 100{
 101        const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
 102
 103        if (!ops || !ops->get_enable)
 104                return -ENOSYS;
 105
 106        return ops->get_enable(dev);
 107}
 108
 109int regulator_set_enable(struct udevice *dev, bool enable)
 110{
 111        const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
 112
 113        if (!ops || !ops->set_enable)
 114                return -ENOSYS;
 115
 116        return ops->set_enable(dev, enable);
 117}
 118
 119int regulator_get_mode(struct udevice *dev)
 120{
 121        const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
 122
 123        if (!ops || !ops->get_mode)
 124                return -ENOSYS;
 125
 126        return ops->get_mode(dev);
 127}
 128
 129int regulator_set_mode(struct udevice *dev, int mode)
 130{
 131        const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
 132
 133        if (!ops || !ops->set_mode)
 134                return -ENOSYS;
 135
 136        return ops->set_mode(dev, mode);
 137}
 138
 139int regulator_get_by_platname(const char *plat_name, struct udevice **devp)
 140{
 141        struct dm_regulator_uclass_platdata *uc_pdata;
 142        struct udevice *dev;
 143        int ret;
 144
 145        *devp = NULL;
 146
 147        for (ret = uclass_find_first_device(UCLASS_REGULATOR, &dev); dev;
 148             ret = uclass_find_next_device(&dev)) {
 149                if (ret)
 150                        continue;
 151
 152                uc_pdata = dev_get_uclass_platdata(dev);
 153                if (!uc_pdata || strcmp(plat_name, uc_pdata->name))
 154                        continue;
 155
 156                return uclass_get_device_tail(dev, 0, devp);
 157        }
 158
 159        debug("%s: can't find: %s\n", __func__, plat_name);
 160
 161        return -ENODEV;
 162}
 163
 164int regulator_get_by_devname(const char *devname, struct udevice **devp)
 165{
 166        return uclass_get_device_by_name(UCLASS_REGULATOR, devname, devp);
 167}
 168
 169int device_get_supply_regulator(struct udevice *dev, const char *supply_name,
 170                                struct udevice **devp)
 171{
 172        return uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
 173                                            supply_name, devp);
 174}
 175
 176int regulator_autoset(struct udevice *dev)
 177{
 178        struct dm_regulator_uclass_platdata *uc_pdata;
 179        int ret = 0;
 180
 181        uc_pdata = dev_get_uclass_platdata(dev);
 182        if (!uc_pdata->always_on && !uc_pdata->boot_on)
 183                return -EMEDIUMTYPE;
 184
 185        if (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UV)
 186                ret = regulator_set_value(dev, uc_pdata->min_uV);
 187        if (!ret && (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UA))
 188                ret = regulator_set_current(dev, uc_pdata->min_uA);
 189
 190        if (!ret)
 191                ret = regulator_set_enable(dev, true);
 192
 193        return ret;
 194}
 195
 196static void regulator_show(struct udevice *dev, int ret)
 197{
 198        struct dm_regulator_uclass_platdata *uc_pdata;
 199
 200        uc_pdata = dev_get_uclass_platdata(dev);
 201
 202        printf("%s@%s: ", dev->name, uc_pdata->name);
 203        if (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UV)
 204                printf("set %d uV", uc_pdata->min_uV);
 205        if (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UA)
 206                printf("; set %d uA", uc_pdata->min_uA);
 207        printf("; enabling");
 208        if (ret)
 209                printf(" (ret: %d)", ret);
 210        printf("\n");
 211}
 212
 213int regulator_autoset_by_name(const char *platname, struct udevice **devp)
 214{
 215        struct udevice *dev;
 216        int ret;
 217
 218        ret = regulator_get_by_platname(platname, &dev);
 219        if (devp)
 220                *devp = dev;
 221        if (ret) {
 222                debug("Can get the regulator: %s!", platname);
 223                return ret;
 224        }
 225
 226        return regulator_autoset(dev);
 227}
 228
 229int regulator_list_autoset(const char *list_platname[],
 230                           struct udevice *list_devp[],
 231                           bool verbose)
 232{
 233        struct udevice *dev;
 234        int error = 0, i = 0, ret;
 235
 236        while (list_platname[i]) {
 237                ret = regulator_autoset_by_name(list_platname[i], &dev);
 238                if (ret != -EMEDIUMTYPE && verbose)
 239                        regulator_show(dev, ret);
 240                if (ret & !error)
 241                        error = ret;
 242
 243                if (list_devp)
 244                        list_devp[i] = dev;
 245
 246                i++;
 247        }
 248
 249        return error;
 250}
 251
 252static bool regulator_name_is_unique(struct udevice *check_dev,
 253                                     const char *check_name)
 254{
 255        struct dm_regulator_uclass_platdata *uc_pdata;
 256        struct udevice *dev;
 257        int check_len = strlen(check_name);
 258        int ret;
 259        int len;
 260
 261        for (ret = uclass_find_first_device(UCLASS_REGULATOR, &dev); dev;
 262             ret = uclass_find_next_device(&dev)) {
 263                if (ret || dev == check_dev)
 264                        continue;
 265
 266                uc_pdata = dev_get_uclass_platdata(dev);
 267                len = strlen(uc_pdata->name);
 268                if (len != check_len)
 269                        continue;
 270
 271                if (!strcmp(uc_pdata->name, check_name))
 272                        return false;
 273        }
 274
 275        return true;
 276}
 277
 278static int regulator_post_bind(struct udevice *dev)
 279{
 280        struct dm_regulator_uclass_platdata *uc_pdata;
 281        int offset = dev->of_offset;
 282        const void *blob = gd->fdt_blob;
 283        const char *property = "regulator-name";
 284
 285        uc_pdata = dev_get_uclass_platdata(dev);
 286        if (!uc_pdata)
 287                return -ENXIO;
 288
 289        /* Regulator's mandatory constraint */
 290        uc_pdata->name = fdt_getprop(blob, offset, property, NULL);
 291        if (!uc_pdata->name) {
 292                debug("%s: dev: %s has no property 'regulator-name'\n",
 293                      __func__, dev->name);
 294                uc_pdata->name = fdt_get_name(blob, offset, NULL);
 295                if (!uc_pdata->name)
 296                        return -EINVAL;
 297        }
 298
 299        if (regulator_name_is_unique(dev, uc_pdata->name))
 300                return 0;
 301
 302        debug("\"%s\" of dev: \"%s\", has nonunique value: \"%s\"",
 303              property, dev->name, uc_pdata->name);
 304
 305        return -EINVAL;
 306}
 307
 308static int regulator_pre_probe(struct udevice *dev)
 309{
 310        struct dm_regulator_uclass_platdata *uc_pdata;
 311        int offset = dev->of_offset;
 312
 313        uc_pdata = dev_get_uclass_platdata(dev);
 314        if (!uc_pdata)
 315                return -ENXIO;
 316
 317        /* Regulator's optional constraints */
 318        uc_pdata->min_uV = fdtdec_get_int(gd->fdt_blob, offset,
 319                                          "regulator-min-microvolt", -ENODATA);
 320        uc_pdata->max_uV = fdtdec_get_int(gd->fdt_blob, offset,
 321                                          "regulator-max-microvolt", -ENODATA);
 322        uc_pdata->min_uA = fdtdec_get_int(gd->fdt_blob, offset,
 323                                          "regulator-min-microamp", -ENODATA);
 324        uc_pdata->max_uA = fdtdec_get_int(gd->fdt_blob, offset,
 325                                          "regulator-max-microamp", -ENODATA);
 326        uc_pdata->always_on = fdtdec_get_bool(gd->fdt_blob, offset,
 327                                              "regulator-always-on");
 328        uc_pdata->boot_on = fdtdec_get_bool(gd->fdt_blob, offset,
 329                                            "regulator-boot-on");
 330
 331        /* Those values are optional (-ENODATA if unset) */
 332        if ((uc_pdata->min_uV != -ENODATA) &&
 333            (uc_pdata->max_uV != -ENODATA) &&
 334            (uc_pdata->min_uV == uc_pdata->max_uV))
 335                uc_pdata->flags |= REGULATOR_FLAG_AUTOSET_UV;
 336
 337        /* Those values are optional (-ENODATA if unset) */
 338        if ((uc_pdata->min_uA != -ENODATA) &&
 339            (uc_pdata->max_uA != -ENODATA) &&
 340            (uc_pdata->min_uA == uc_pdata->max_uA))
 341                uc_pdata->flags |= REGULATOR_FLAG_AUTOSET_UA;
 342
 343        return 0;
 344}
 345
 346int regulators_enable_boot_on(bool verbose)
 347{
 348        struct udevice *dev;
 349        struct uclass *uc;
 350        int ret;
 351
 352        ret = uclass_get(UCLASS_REGULATOR, &uc);
 353        if (ret)
 354                return ret;
 355        for (uclass_first_device(UCLASS_REGULATOR, &dev);
 356             dev;
 357             uclass_next_device(&dev)) {
 358                ret = regulator_autoset(dev);
 359                if (ret == -EMEDIUMTYPE) {
 360                        ret = 0;
 361                        continue;
 362                }
 363                if (verbose)
 364                        regulator_show(dev, ret);
 365                if (ret == -ENOSYS)
 366                        ret = 0;
 367        }
 368
 369        return ret;
 370}
 371
 372UCLASS_DRIVER(regulator) = {
 373        .id             = UCLASS_REGULATOR,
 374        .name           = "regulator",
 375        .post_bind      = regulator_post_bind,
 376        .pre_probe      = regulator_pre_probe,
 377        .per_device_platdata_auto_alloc_size =
 378                                sizeof(struct dm_regulator_uclass_platdata),
 379};
 380