uboot/drivers/power/domain/power-domain-uclass.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (c) 2016, NVIDIA CORPORATION.
   4 */
   5
   6#include <common.h>
   7#include <dm.h>
   8#include <log.h>
   9#include <malloc.h>
  10#include <power-domain.h>
  11#include <power-domain-uclass.h>
  12#include <dm/device-internal.h>
  13
  14static inline struct power_domain_ops *power_domain_dev_ops(struct udevice *dev)
  15{
  16        return (struct power_domain_ops *)dev->driver->ops;
  17}
  18
  19static int power_domain_of_xlate_default(struct power_domain *power_domain,
  20                                         struct ofnode_phandle_args *args)
  21{
  22        debug("%s(power_domain=%p)\n", __func__, power_domain);
  23
  24        if (args->args_count != 1) {
  25                debug("Invalid args_count: %d\n", args->args_count);
  26                return -EINVAL;
  27        }
  28
  29        power_domain->id = args->args[0];
  30
  31        return 0;
  32}
  33
  34int power_domain_get_by_index(struct udevice *dev,
  35                              struct power_domain *power_domain, int index)
  36{
  37        struct ofnode_phandle_args args;
  38        int ret;
  39        struct udevice *dev_power_domain;
  40        struct power_domain_ops *ops;
  41
  42        debug("%s(dev=%p, power_domain=%p)\n", __func__, dev, power_domain);
  43
  44        ret = dev_read_phandle_with_args(dev, "power-domains",
  45                                         "#power-domain-cells", 0, index,
  46                                         &args);
  47        if (ret) {
  48                debug("%s: dev_read_phandle_with_args failed: %d\n",
  49                      __func__, ret);
  50                return ret;
  51        }
  52
  53        ret = uclass_get_device_by_ofnode(UCLASS_POWER_DOMAIN, args.node,
  54                                          &dev_power_domain);
  55        if (ret) {
  56                debug("%s: uclass_get_device_by_ofnode failed: %d\n",
  57                      __func__, ret);
  58                return ret;
  59        }
  60        ops = power_domain_dev_ops(dev_power_domain);
  61
  62        power_domain->dev = dev_power_domain;
  63        if (ops->of_xlate)
  64                ret = ops->of_xlate(power_domain, &args);
  65        else
  66                ret = power_domain_of_xlate_default(power_domain, &args);
  67        if (ret) {
  68                debug("of_xlate() failed: %d\n", ret);
  69                return ret;
  70        }
  71
  72        ret = ops->request(power_domain);
  73        if (ret) {
  74                debug("ops->request() failed: %d\n", ret);
  75                return ret;
  76        }
  77
  78        return 0;
  79}
  80
  81int power_domain_get(struct udevice *dev, struct power_domain *power_domain)
  82{
  83        return power_domain_get_by_index(dev, power_domain, 0);
  84}
  85
  86int power_domain_free(struct power_domain *power_domain)
  87{
  88        struct power_domain_ops *ops = power_domain_dev_ops(power_domain->dev);
  89
  90        debug("%s(power_domain=%p)\n", __func__, power_domain);
  91
  92        return ops->rfree(power_domain);
  93}
  94
  95int power_domain_on(struct power_domain *power_domain)
  96{
  97        struct power_domain_ops *ops = power_domain_dev_ops(power_domain->dev);
  98
  99        debug("%s(power_domain=%p)\n", __func__, power_domain);
 100
 101        return ops->on(power_domain);
 102}
 103
 104int power_domain_off(struct power_domain *power_domain)
 105{
 106        struct power_domain_ops *ops = power_domain_dev_ops(power_domain->dev);
 107
 108        debug("%s(power_domain=%p)\n", __func__, power_domain);
 109
 110        return ops->off(power_domain);
 111}
 112
 113#if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA))
 114static int dev_power_domain_ctrl(struct udevice *dev, bool on)
 115{
 116        struct power_domain pd;
 117        int i, count, ret = 0;
 118
 119        count = dev_count_phandle_with_args(dev, "power-domains",
 120                                            "#power-domain-cells");
 121        for (i = 0; i < count; i++) {
 122                ret = power_domain_get_by_index(dev, &pd, i);
 123                if (ret)
 124                        return ret;
 125                if (on)
 126                        ret = power_domain_on(&pd);
 127                else
 128                        ret = power_domain_off(&pd);
 129        }
 130
 131        /*
 132         * For platforms with parent and child power-domain devices
 133         * we may not run device_remove() on the power-domain parent
 134         * because it will result in removing its children and switching
 135         * off their power-domain parent. So we will get here again and
 136         * again and will be stuck in an endless loop.
 137         */
 138        if (!on && dev_get_parent(dev) == pd.dev &&
 139            device_get_uclass_id(dev) == UCLASS_POWER_DOMAIN)
 140                return ret;
 141
 142        /*
 143         * power_domain_get() bound the device, thus
 144         * we must remove it again to prevent unbinding
 145         * active devices (which would result in unbind
 146         * error).
 147         */
 148        if (count > 0 && !on)
 149                device_remove(pd.dev, DM_REMOVE_NORMAL);
 150
 151        return ret;
 152}
 153
 154int dev_power_domain_on(struct udevice *dev)
 155{
 156        return dev_power_domain_ctrl(dev, true);
 157}
 158
 159int dev_power_domain_off(struct udevice *dev)
 160{
 161        return dev_power_domain_ctrl(dev, false);
 162}
 163#endif
 164
 165UCLASS_DRIVER(power_domain) = {
 166        .id             = UCLASS_POWER_DOMAIN,
 167        .name           = "power_domain",
 168};
 169