1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3  * Copyright (c) 2016, NVIDIA CORPORATION.
4  */
5 
6 #ifndef _POWER_DOMAIN_H
7 #define _POWER_DOMAIN_H
8 
9 #include <linux/errno.h>
10 
11 /**
12  * A power domain is a portion of an SoC or chip that is powered by a
13  * switchable source of power. In many cases, software has control over the
14  * power domain, and can turn the power source on or off. This is typically
15  * done to save power by powering off unused devices, or to enable software
16  * sequencing of initial powerup at boot. This API provides a means for
17  * drivers to turn power domains on and off.
18  *
19  * A driver that implements UCLASS_POWER_DOMAIN is a power domain controller or
20  * provider. A controller will often implement multiple separate power domains,
21  * since the hardware it manages often has this capability.
22  * power-domain-uclass.h describes the interface which power domain controllers
23  * must implement.
24  *
25  * Depending on the power domain controller hardware, changing the state of a
26  * power domain may require performing related operations on other resources.
27  * For example, some power domains may require certain clocks to be enabled
28  * whenever the power domain is powered on, or during the time when the power
29  * domain is transitioning state. These details are implementation-specific
30  * and should ideally be encapsulated entirely within the provider driver, or
31  * configured through mechanisms (e.g. device tree) that do not require client
32  * drivers to provide extra configuration information.
33  *
34  * Power domain consumers/clients are the drivers for HW modules within the
35  * power domain. This header file describes the API used by those drivers.
36  *
37  * In many cases, a single complex IO controller (e.g. a PCIe controller) will
38  * be the sole logic contained within a power domain. In such cases, it is
39  * logical for the relevant device driver to directly control that power
40  * domain. In other cases, multiple controllers, each with their own driver,
41  * may be contained in a single power domain. Any logic require to co-ordinate
42  * between drivers for these multiple controllers is beyond the scope of this
43  * API at present. Equally, this API does not define or implement any policy
44  * by which power domains are managed.
45  */
46 
47 struct udevice;
48 
49 /**
50  * struct power_domain - A handle to (allowing control of) a single power domain.
51  *
52  * Clients provide storage for power domain handles. The content of the
53  * structure is managed solely by the power domain API and power domain
54  * drivers. A power domain struct is initialized by "get"ing the power domain
55  * struct. The power domain struct is passed to all other power domain APIs to
56  * identify which power domain to operate upon.
57  *
58  * @dev: The device which implements the power domain.
59  * @id: The power domain ID within the provider.
60  * @priv: Private data corresponding to each power domain.
61  */
62 struct power_domain {
63 	struct udevice *dev;
64 	unsigned long id;
65 	void *priv;
66 };
67 
68 /**
69  * struct power_domain_plat - Per device accessible structure
70  * @subdomains: Number of subdomains covered by this device, required
71  *              for refcounting
72  */
73 struct power_domain_plat {
74 	int subdomains;
75 };
76 
77 /**
78  * power_domain_get - Get/request the power domain for a device.
79  *
80  * This looks up and requests a power domain. Each device is assumed to have
81  * a single (or, at least one) power domain associated with it somehow, and
82  * that domain, or the first/default domain. The mapping of client device to
83  * provider power domain may be via device-tree properties, board-provided
84  * mapping tables, or some other mechanism.
85  *
86  * @dev:	The client device.
87  * @power_domain	A pointer to a power domain struct to initialize.
88  * Return: 0 if OK, or a negative error code.
89  */
90 #if CONFIG_IS_ENABLED(POWER_DOMAIN)
91 int power_domain_get(struct udevice *dev, struct power_domain *power_domain);
92 #else
93 static inline
power_domain_get(struct udevice * dev,struct power_domain * power_domain)94 int power_domain_get(struct udevice *dev, struct power_domain *power_domain)
95 {
96 	return -ENOSYS;
97 }
98 #endif
99 
100 /**
101  * power_domain_get_by_index - Get the indexed power domain for a device.
102  *
103  * @dev:		The client device.
104  * @power_domain:	A pointer to a power domain struct to initialize.
105  * @index:		Power domain index to be powered on.
106  *
107  * Return: 0 if OK, or a negative error code.
108  */
109 #if CONFIG_IS_ENABLED(POWER_DOMAIN)
110 int power_domain_get_by_index(struct udevice *dev,
111 			      struct power_domain *power_domain, int index);
112 #else
113 static inline
power_domain_get_by_index(struct udevice * dev,struct power_domain * power_domain,int index)114 int power_domain_get_by_index(struct udevice *dev,
115 			      struct power_domain *power_domain, int index)
116 {
117 	return -ENOSYS;
118 }
119 #endif
120 
121 /**
122  * power_domain_get_by_name - Get the named power domain for a device.
123  *
124  * @dev:		The client device.
125  * @power_domain:	A pointer to a power domain struct to initialize.
126  * @name:		Power domain name to be powered on.
127  *
128  * Return: 0 if OK, or a negative error code.
129  */
130 #if CONFIG_IS_ENABLED(POWER_DOMAIN)
131 int power_domain_get_by_name(struct udevice *dev,
132 			     struct power_domain *power_domain, const char *name);
133 #else
134 static inline
power_domain_get_by_name(struct udevice * dev,struct power_domain * power_domain,const char * name)135 int power_domain_get_by_name(struct udevice *dev,
136 			     struct power_domain *power_domain, const char *name)
137 {
138 	return -ENOSYS;
139 }
140 #endif
141 
142 /**
143  * power_domain_free - Free a previously requested power domain.
144  *
145  * @power_domain:	A power domain struct that was previously successfully
146  *		requested by power_domain_get().
147  * Return: 0 if OK, or a negative error code.
148  */
149 #if CONFIG_IS_ENABLED(POWER_DOMAIN)
150 int power_domain_free(struct power_domain *power_domain);
151 #else
power_domain_free(struct power_domain * power_domain)152 static inline int power_domain_free(struct power_domain *power_domain)
153 {
154 	return -ENOSYS;
155 }
156 #endif
157 
158 /**
159  * power_domain_on_lowlevel - Enable power to a power domain (with refcounting)
160  *
161  * @power_domain:	A power domain struct that was previously successfully
162  *		requested by power_domain_get().
163  * Return: 0 if the transition has been performed correctly,
164  *         -EALREADY if the domain is already on,
165  *         a negative error code otherwise.
166  */
167 #if CONFIG_IS_ENABLED(POWER_DOMAIN)
168 int power_domain_on_lowlevel(struct power_domain *power_domain);
169 #else
power_domain_on_lowlevel(struct power_domain * power_domain)170 static inline int power_domain_on_lowlevel(struct power_domain *power_domain)
171 {
172 	return -ENOSYS;
173 }
174 #endif
175 
176 /**
177  * power_domain_on - Enable power to a power domain (ignores the actual state
178  *		      of the power domain)
179  *
180  * @power_domain:	A power domain struct that was previously successfully
181  *		requested by power_domain_get().
182  * Return: a negative error code upon error during the transition, 0 otherwise.
183  */
power_domain_on(struct power_domain * power_domain)184 static inline int power_domain_on(struct power_domain *power_domain)
185 {
186 	int ret;
187 
188 	ret = power_domain_on_lowlevel(power_domain);
189 	if (ret == -EALREADY)
190 		ret = 0;
191 
192 	return ret;
193 }
194 
195 /**
196  * power_domain_off_lowlevel - Disable power to a power domain (with refcounting)
197  *
198  * @power_domain:	A power domain struct that was previously successfully
199  *		requested by power_domain_get().
200  * Return: 0 if the transition has been performed correctly,
201  *         -EALREADY if the domain is already off,
202  *         -EBUSY if another device is keeping the domain on (but the refcounter
203  *         is decremented),
204  *         a negative error code otherwise.
205  */
206 #if CONFIG_IS_ENABLED(POWER_DOMAIN)
207 int power_domain_off_lowlevel(struct power_domain *power_domain);
208 #else
power_domain_off_lowlevel(struct power_domain * power_domain)209 static inline int power_domain_off_lowlevel(struct power_domain *power_domain)
210 {
211 	return -ENOSYS;
212 }
213 #endif
214 
215 /**
216  * power_domain_off - Disable power to a power domain (ignores the actual state
217  *		      of the power domain)
218  *
219  * @power_domain:	A power domain struct that was previously successfully
220  *		requested by power_domain_get().
221  * Return: a negative error code upon error during the transition, 0 otherwise.
222  */
power_domain_off(struct power_domain * power_domain)223 static inline int power_domain_off(struct power_domain *power_domain)
224 {
225 	int ret;
226 
227 	ret = power_domain_off_lowlevel(power_domain);
228 	if (ret == -EALREADY || ret == -EBUSY)
229 		ret = 0;
230 
231 	return ret;
232 }
233 
234 /**
235  * dev_power_domain_on - Enable power domains for a device .
236  *
237  * @dev:		The client device.
238  *
239  * Return: 0 if OK, or a negative error code.
240  */
241 #if CONFIG_IS_ENABLED(OF_REAL) && CONFIG_IS_ENABLED(POWER_DOMAIN)
242 int dev_power_domain_on(struct udevice *dev);
243 #else
dev_power_domain_on(struct udevice * dev)244 static inline int dev_power_domain_on(struct udevice *dev)
245 {
246 	return 0;
247 }
248 #endif
249 
250 /**
251  * dev_power_domain_off - Disable power domains for a device .
252  *
253  * @dev:		The client device.
254  *
255  * Return: 0 if OK, or a negative error code.
256  */
257 #if CONFIG_IS_ENABLED(OF_REAL) && CONFIG_IS_ENABLED(POWER_DOMAIN)
258 int dev_power_domain_off(struct udevice *dev);
259 #else
dev_power_domain_off(struct udevice * dev)260 static inline int dev_power_domain_off(struct udevice *dev)
261 {
262 	return 0;
263 }
264 #endif
265 
266 #endif
267