1 /* 2 * Copyright (c) 2016, NVIDIA CORPORATION. 3 * 4 * SPDX-License-Identifier: GPL-2.0 5 */ 6 7 #include <common.h> 8 #include <dm.h> 9 #include <power-domain.h> 10 #include <power-domain-uclass.h> 11 12 DECLARE_GLOBAL_DATA_PTR; 13 14 static inline struct power_domain_ops *power_domain_dev_ops(struct udevice *dev) 15 { 16 return (struct power_domain_ops *)dev->driver->ops; 17 } 18 19 static 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 34 int 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 81 int 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 86 int 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->free(power_domain); 93 } 94 95 int 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 104 int 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_PLATDATA) 114 int dev_power_domain_on(struct udevice *dev) 115 { 116 struct power_domain pd; 117 int i, count, ret; 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 ret = power_domain_on(&pd); 126 if (ret) 127 return ret; 128 } 129 130 return 0; 131 } 132 #endif 133 134 UCLASS_DRIVER(power_domain) = { 135 .id = UCLASS_POWER_DOMAIN, 136 .name = "power_domain", 137 }; 138