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