xref: /openbmc/linux/drivers/base/power/domain.c (revision 221e9b58)
1f721889fSRafael J. Wysocki /*
2f721889fSRafael J. Wysocki  * drivers/base/power/domain.c - Common code related to device power domains.
3f721889fSRafael J. Wysocki  *
4f721889fSRafael J. Wysocki  * Copyright (C) 2011 Rafael J. Wysocki <rjw@sisk.pl>, Renesas Electronics Corp.
5f721889fSRafael J. Wysocki  *
6f721889fSRafael J. Wysocki  * This file is released under the GPLv2.
7f721889fSRafael J. Wysocki  */
8f721889fSRafael J. Wysocki 
9f721889fSRafael J. Wysocki #include <linux/init.h>
10f721889fSRafael J. Wysocki #include <linux/kernel.h>
11f721889fSRafael J. Wysocki #include <linux/io.h>
12f721889fSRafael J. Wysocki #include <linux/pm_runtime.h>
13f721889fSRafael J. Wysocki #include <linux/pm_domain.h>
14f721889fSRafael J. Wysocki #include <linux/slab.h>
15f721889fSRafael J. Wysocki #include <linux/err.h>
1617b75ecaSRafael J. Wysocki #include <linux/sched.h>
1717b75ecaSRafael J. Wysocki #include <linux/suspend.h>
18d5e4cbfeSRafael J. Wysocki #include <linux/export.h>
19d5e4cbfeSRafael J. Wysocki 
20d5e4cbfeSRafael J. Wysocki #define GENPD_DEV_CALLBACK(genpd, type, callback, dev)		\
21d5e4cbfeSRafael J. Wysocki ({								\
22d5e4cbfeSRafael J. Wysocki 	type (*__routine)(struct device *__d); 			\
23d5e4cbfeSRafael J. Wysocki 	type __ret = (type)0;					\
24d5e4cbfeSRafael J. Wysocki 								\
25d5e4cbfeSRafael J. Wysocki 	__routine = genpd->dev_ops.callback; 			\
26d5e4cbfeSRafael J. Wysocki 	if (__routine) {					\
27d5e4cbfeSRafael J. Wysocki 		__ret = __routine(dev); 			\
28d5e4cbfeSRafael J. Wysocki 	} else {						\
29d5e4cbfeSRafael J. Wysocki 		__routine = dev_gpd_data(dev)->ops.callback;	\
30d5e4cbfeSRafael J. Wysocki 		if (__routine) 					\
31d5e4cbfeSRafael J. Wysocki 			__ret = __routine(dev);			\
32d5e4cbfeSRafael J. Wysocki 	}							\
33d5e4cbfeSRafael J. Wysocki 	__ret;							\
34d5e4cbfeSRafael J. Wysocki })
35f721889fSRafael J. Wysocki 
365125bbf3SRafael J. Wysocki static LIST_HEAD(gpd_list);
375125bbf3SRafael J. Wysocki static DEFINE_MUTEX(gpd_list_lock);
385125bbf3SRafael J. Wysocki 
395248051bSRafael J. Wysocki #ifdef CONFIG_PM
405248051bSRafael J. Wysocki 
41b02c999aSRafael J. Wysocki struct generic_pm_domain *dev_to_genpd(struct device *dev)
425248051bSRafael J. Wysocki {
435248051bSRafael J. Wysocki 	if (IS_ERR_OR_NULL(dev->pm_domain))
445248051bSRafael J. Wysocki 		return ERR_PTR(-EINVAL);
455248051bSRafael J. Wysocki 
46596ba34bSRafael J. Wysocki 	return pd_to_genpd(dev->pm_domain);
475248051bSRafael J. Wysocki }
48f721889fSRafael J. Wysocki 
49d5e4cbfeSRafael J. Wysocki static int genpd_stop_dev(struct generic_pm_domain *genpd, struct device *dev)
50d5e4cbfeSRafael J. Wysocki {
51d5e4cbfeSRafael J. Wysocki 	return GENPD_DEV_CALLBACK(genpd, int, stop, dev);
52d5e4cbfeSRafael J. Wysocki }
53d5e4cbfeSRafael J. Wysocki 
54d5e4cbfeSRafael J. Wysocki static int genpd_start_dev(struct generic_pm_domain *genpd, struct device *dev)
55d5e4cbfeSRafael J. Wysocki {
56d5e4cbfeSRafael J. Wysocki 	return GENPD_DEV_CALLBACK(genpd, int, start, dev);
57d5e4cbfeSRafael J. Wysocki }
58d5e4cbfeSRafael J. Wysocki 
59ecf00475SRafael J. Wysocki static int genpd_save_dev(struct generic_pm_domain *genpd, struct device *dev)
60ecf00475SRafael J. Wysocki {
61ecf00475SRafael J. Wysocki 	return GENPD_DEV_CALLBACK(genpd, int, save_state, dev);
62ecf00475SRafael J. Wysocki }
63ecf00475SRafael J. Wysocki 
64ecf00475SRafael J. Wysocki static int genpd_restore_dev(struct generic_pm_domain *genpd, struct device *dev)
65ecf00475SRafael J. Wysocki {
66ecf00475SRafael J. Wysocki 	return GENPD_DEV_CALLBACK(genpd, int, restore_state, dev);
67ecf00475SRafael J. Wysocki }
68ecf00475SRafael J. Wysocki 
69c4bb3160SRafael J. Wysocki static bool genpd_sd_counter_dec(struct generic_pm_domain *genpd)
70f721889fSRafael J. Wysocki {
71c4bb3160SRafael J. Wysocki 	bool ret = false;
72c4bb3160SRafael J. Wysocki 
73c4bb3160SRafael J. Wysocki 	if (!WARN_ON(atomic_read(&genpd->sd_count) == 0))
74c4bb3160SRafael J. Wysocki 		ret = !!atomic_dec_and_test(&genpd->sd_count);
75c4bb3160SRafael J. Wysocki 
76c4bb3160SRafael J. Wysocki 	return ret;
77c4bb3160SRafael J. Wysocki }
78c4bb3160SRafael J. Wysocki 
79c4bb3160SRafael J. Wysocki static void genpd_sd_counter_inc(struct generic_pm_domain *genpd)
80c4bb3160SRafael J. Wysocki {
81c4bb3160SRafael J. Wysocki 	atomic_inc(&genpd->sd_count);
82c4bb3160SRafael J. Wysocki 	smp_mb__after_atomic_inc();
83f721889fSRafael J. Wysocki }
84f721889fSRafael J. Wysocki 
8517b75ecaSRafael J. Wysocki static void genpd_acquire_lock(struct generic_pm_domain *genpd)
8617b75ecaSRafael J. Wysocki {
8717b75ecaSRafael J. Wysocki 	DEFINE_WAIT(wait);
8817b75ecaSRafael J. Wysocki 
8917b75ecaSRafael J. Wysocki 	mutex_lock(&genpd->lock);
9017b75ecaSRafael J. Wysocki 	/*
9117b75ecaSRafael J. Wysocki 	 * Wait for the domain to transition into either the active,
9217b75ecaSRafael J. Wysocki 	 * or the power off state.
9317b75ecaSRafael J. Wysocki 	 */
9417b75ecaSRafael J. Wysocki 	for (;;) {
9517b75ecaSRafael J. Wysocki 		prepare_to_wait(&genpd->status_wait_queue, &wait,
9617b75ecaSRafael J. Wysocki 				TASK_UNINTERRUPTIBLE);
97c6d22b37SRafael J. Wysocki 		if (genpd->status == GPD_STATE_ACTIVE
98c6d22b37SRafael J. Wysocki 		    || genpd->status == GPD_STATE_POWER_OFF)
9917b75ecaSRafael J. Wysocki 			break;
10017b75ecaSRafael J. Wysocki 		mutex_unlock(&genpd->lock);
10117b75ecaSRafael J. Wysocki 
10217b75ecaSRafael J. Wysocki 		schedule();
10317b75ecaSRafael J. Wysocki 
10417b75ecaSRafael J. Wysocki 		mutex_lock(&genpd->lock);
10517b75ecaSRafael J. Wysocki 	}
10617b75ecaSRafael J. Wysocki 	finish_wait(&genpd->status_wait_queue, &wait);
10717b75ecaSRafael J. Wysocki }
10817b75ecaSRafael J. Wysocki 
10917b75ecaSRafael J. Wysocki static void genpd_release_lock(struct generic_pm_domain *genpd)
11017b75ecaSRafael J. Wysocki {
11117b75ecaSRafael J. Wysocki 	mutex_unlock(&genpd->lock);
11217b75ecaSRafael J. Wysocki }
11317b75ecaSRafael J. Wysocki 
114c6d22b37SRafael J. Wysocki static void genpd_set_active(struct generic_pm_domain *genpd)
115c6d22b37SRafael J. Wysocki {
116c6d22b37SRafael J. Wysocki 	if (genpd->resume_count == 0)
117c6d22b37SRafael J. Wysocki 		genpd->status = GPD_STATE_ACTIVE;
118c6d22b37SRafael J. Wysocki }
119c6d22b37SRafael J. Wysocki 
120f721889fSRafael J. Wysocki /**
1215063ce15SRafael J. Wysocki  * __pm_genpd_poweron - Restore power to a given PM domain and its masters.
1225248051bSRafael J. Wysocki  * @genpd: PM domain to power up.
1235248051bSRafael J. Wysocki  *
1245063ce15SRafael J. Wysocki  * Restore power to @genpd and all of its masters so that it is possible to
1255248051bSRafael J. Wysocki  * resume a device belonging to it.
1265248051bSRafael J. Wysocki  */
1273f241775SRafael J. Wysocki int __pm_genpd_poweron(struct generic_pm_domain *genpd)
1283f241775SRafael J. Wysocki 	__releases(&genpd->lock) __acquires(&genpd->lock)
1295248051bSRafael J. Wysocki {
1305063ce15SRafael J. Wysocki 	struct gpd_link *link;
1313f241775SRafael J. Wysocki 	DEFINE_WAIT(wait);
1325248051bSRafael J. Wysocki 	int ret = 0;
1335248051bSRafael J. Wysocki 
1345063ce15SRafael J. Wysocki 	/* If the domain's master is being waited for, we have to wait too. */
1353f241775SRafael J. Wysocki 	for (;;) {
1363f241775SRafael J. Wysocki 		prepare_to_wait(&genpd->status_wait_queue, &wait,
1373f241775SRafael J. Wysocki 				TASK_UNINTERRUPTIBLE);
13817877eb5SRafael J. Wysocki 		if (genpd->status != GPD_STATE_WAIT_MASTER)
1393f241775SRafael J. Wysocki 			break;
1403f241775SRafael J. Wysocki 		mutex_unlock(&genpd->lock);
1413f241775SRafael J. Wysocki 
1423f241775SRafael J. Wysocki 		schedule();
1433f241775SRafael J. Wysocki 
14417b75ecaSRafael J. Wysocki 		mutex_lock(&genpd->lock);
1453f241775SRafael J. Wysocki 	}
1463f241775SRafael J. Wysocki 	finish_wait(&genpd->status_wait_queue, &wait);
14717b75ecaSRafael J. Wysocki 
14817b75ecaSRafael J. Wysocki 	if (genpd->status == GPD_STATE_ACTIVE
149596ba34bSRafael J. Wysocki 	    || (genpd->prepared_count > 0 && genpd->suspend_power_off))
1503f241775SRafael J. Wysocki 		return 0;
1515248051bSRafael J. Wysocki 
152c6d22b37SRafael J. Wysocki 	if (genpd->status != GPD_STATE_POWER_OFF) {
153c6d22b37SRafael J. Wysocki 		genpd_set_active(genpd);
1543f241775SRafael J. Wysocki 		return 0;
155c6d22b37SRafael J. Wysocki 	}
156c6d22b37SRafael J. Wysocki 
1575063ce15SRafael J. Wysocki 	/*
1585063ce15SRafael J. Wysocki 	 * The list is guaranteed not to change while the loop below is being
1595063ce15SRafael J. Wysocki 	 * executed, unless one of the masters' .power_on() callbacks fiddles
1605063ce15SRafael J. Wysocki 	 * with it.
1615063ce15SRafael J. Wysocki 	 */
1625063ce15SRafael J. Wysocki 	list_for_each_entry(link, &genpd->slave_links, slave_node) {
1635063ce15SRafael J. Wysocki 		genpd_sd_counter_inc(link->master);
16417877eb5SRafael J. Wysocki 		genpd->status = GPD_STATE_WAIT_MASTER;
1653c07cbc4SRafael J. Wysocki 
1665248051bSRafael J. Wysocki 		mutex_unlock(&genpd->lock);
1675248051bSRafael J. Wysocki 
1685063ce15SRafael J. Wysocki 		ret = pm_genpd_poweron(link->master);
1699e08cf42SRafael J. Wysocki 
1709e08cf42SRafael J. Wysocki 		mutex_lock(&genpd->lock);
1719e08cf42SRafael J. Wysocki 
1723f241775SRafael J. Wysocki 		/*
1733f241775SRafael J. Wysocki 		 * The "wait for parent" status is guaranteed not to change
1745063ce15SRafael J. Wysocki 		 * while the master is powering on.
1753f241775SRafael J. Wysocki 		 */
1763f241775SRafael J. Wysocki 		genpd->status = GPD_STATE_POWER_OFF;
1773f241775SRafael J. Wysocki 		wake_up_all(&genpd->status_wait_queue);
1785063ce15SRafael J. Wysocki 		if (ret) {
1795063ce15SRafael J. Wysocki 			genpd_sd_counter_dec(link->master);
1809e08cf42SRafael J. Wysocki 			goto err;
1815248051bSRafael J. Wysocki 		}
1825063ce15SRafael J. Wysocki 	}
1835248051bSRafael J. Wysocki 
1849e08cf42SRafael J. Wysocki 	if (genpd->power_on) {
185fe202fdeSRafael J. Wysocki 		ret = genpd->power_on(genpd);
1869e08cf42SRafael J. Wysocki 		if (ret)
1879e08cf42SRafael J. Wysocki 			goto err;
1883c07cbc4SRafael J. Wysocki 	}
1895248051bSRafael J. Wysocki 
1909e08cf42SRafael J. Wysocki 	genpd_set_active(genpd);
1919e08cf42SRafael J. Wysocki 
1923f241775SRafael J. Wysocki 	return 0;
1939e08cf42SRafael J. Wysocki 
1949e08cf42SRafael J. Wysocki  err:
1955063ce15SRafael J. Wysocki 	list_for_each_entry_continue_reverse(link, &genpd->slave_links, slave_node)
1965063ce15SRafael J. Wysocki 		genpd_sd_counter_dec(link->master);
1979e08cf42SRafael J. Wysocki 
1983f241775SRafael J. Wysocki 	return ret;
1993f241775SRafael J. Wysocki }
2003f241775SRafael J. Wysocki 
2013f241775SRafael J. Wysocki /**
2025063ce15SRafael J. Wysocki  * pm_genpd_poweron - Restore power to a given PM domain and its masters.
2033f241775SRafael J. Wysocki  * @genpd: PM domain to power up.
2043f241775SRafael J. Wysocki  */
2053f241775SRafael J. Wysocki int pm_genpd_poweron(struct generic_pm_domain *genpd)
2063f241775SRafael J. Wysocki {
2073f241775SRafael J. Wysocki 	int ret;
2083f241775SRafael J. Wysocki 
2093f241775SRafael J. Wysocki 	mutex_lock(&genpd->lock);
2103f241775SRafael J. Wysocki 	ret = __pm_genpd_poweron(genpd);
2113f241775SRafael J. Wysocki 	mutex_unlock(&genpd->lock);
2123f241775SRafael J. Wysocki 	return ret;
2135248051bSRafael J. Wysocki }
2145248051bSRafael J. Wysocki 
2155248051bSRafael J. Wysocki #endif /* CONFIG_PM */
2165248051bSRafael J. Wysocki 
2175248051bSRafael J. Wysocki #ifdef CONFIG_PM_RUNTIME
2185248051bSRafael J. Wysocki 
2195248051bSRafael J. Wysocki /**
220f721889fSRafael J. Wysocki  * __pm_genpd_save_device - Save the pre-suspend state of a device.
2214605ab65SRafael J. Wysocki  * @pdd: Domain data of the device to save the state of.
222f721889fSRafael J. Wysocki  * @genpd: PM domain the device belongs to.
223f721889fSRafael J. Wysocki  */
2244605ab65SRafael J. Wysocki static int __pm_genpd_save_device(struct pm_domain_data *pdd,
225f721889fSRafael J. Wysocki 				  struct generic_pm_domain *genpd)
22617b75ecaSRafael J. Wysocki 	__releases(&genpd->lock) __acquires(&genpd->lock)
227f721889fSRafael J. Wysocki {
228cd0ea672SRafael J. Wysocki 	struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd);
2294605ab65SRafael J. Wysocki 	struct device *dev = pdd->dev;
230f721889fSRafael J. Wysocki 	int ret = 0;
231f721889fSRafael J. Wysocki 
232cd0ea672SRafael J. Wysocki 	if (gpd_data->need_restore)
233f721889fSRafael J. Wysocki 		return 0;
234f721889fSRafael J. Wysocki 
23517b75ecaSRafael J. Wysocki 	mutex_unlock(&genpd->lock);
23617b75ecaSRafael J. Wysocki 
237d5e4cbfeSRafael J. Wysocki 	genpd_start_dev(genpd, dev);
238ecf00475SRafael J. Wysocki 	ret = genpd_save_dev(genpd, dev);
239d5e4cbfeSRafael J. Wysocki 	genpd_stop_dev(genpd, dev);
240f721889fSRafael J. Wysocki 
24117b75ecaSRafael J. Wysocki 	mutex_lock(&genpd->lock);
24217b75ecaSRafael J. Wysocki 
243f721889fSRafael J. Wysocki 	if (!ret)
244cd0ea672SRafael J. Wysocki 		gpd_data->need_restore = true;
245f721889fSRafael J. Wysocki 
246f721889fSRafael J. Wysocki 	return ret;
247f721889fSRafael J. Wysocki }
248f721889fSRafael J. Wysocki 
249f721889fSRafael J. Wysocki /**
250f721889fSRafael J. Wysocki  * __pm_genpd_restore_device - Restore the pre-suspend state of a device.
2514605ab65SRafael J. Wysocki  * @pdd: Domain data of the device to restore the state of.
252f721889fSRafael J. Wysocki  * @genpd: PM domain the device belongs to.
253f721889fSRafael J. Wysocki  */
2544605ab65SRafael J. Wysocki static void __pm_genpd_restore_device(struct pm_domain_data *pdd,
255f721889fSRafael J. Wysocki 				      struct generic_pm_domain *genpd)
25617b75ecaSRafael J. Wysocki 	__releases(&genpd->lock) __acquires(&genpd->lock)
257f721889fSRafael J. Wysocki {
258cd0ea672SRafael J. Wysocki 	struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd);
2594605ab65SRafael J. Wysocki 	struct device *dev = pdd->dev;
260f721889fSRafael J. Wysocki 
261cd0ea672SRafael J. Wysocki 	if (!gpd_data->need_restore)
262f721889fSRafael J. Wysocki 		return;
263f721889fSRafael J. Wysocki 
26417b75ecaSRafael J. Wysocki 	mutex_unlock(&genpd->lock);
26517b75ecaSRafael J. Wysocki 
266d5e4cbfeSRafael J. Wysocki 	genpd_start_dev(genpd, dev);
267ecf00475SRafael J. Wysocki 	genpd_restore_dev(genpd, dev);
268d5e4cbfeSRafael J. Wysocki 	genpd_stop_dev(genpd, dev);
269f721889fSRafael J. Wysocki 
27017b75ecaSRafael J. Wysocki 	mutex_lock(&genpd->lock);
27117b75ecaSRafael J. Wysocki 
272cd0ea672SRafael J. Wysocki 	gpd_data->need_restore = false;
273f721889fSRafael J. Wysocki }
274f721889fSRafael J. Wysocki 
275f721889fSRafael J. Wysocki /**
276c6d22b37SRafael J. Wysocki  * genpd_abort_poweroff - Check if a PM domain power off should be aborted.
277c6d22b37SRafael J. Wysocki  * @genpd: PM domain to check.
278c6d22b37SRafael J. Wysocki  *
279c6d22b37SRafael J. Wysocki  * Return true if a PM domain's status changed to GPD_STATE_ACTIVE during
280c6d22b37SRafael J. Wysocki  * a "power off" operation, which means that a "power on" has occured in the
281c6d22b37SRafael J. Wysocki  * meantime, or if its resume_count field is different from zero, which means
282c6d22b37SRafael J. Wysocki  * that one of its devices has been resumed in the meantime.
283c6d22b37SRafael J. Wysocki  */
284c6d22b37SRafael J. Wysocki static bool genpd_abort_poweroff(struct generic_pm_domain *genpd)
285c6d22b37SRafael J. Wysocki {
28617877eb5SRafael J. Wysocki 	return genpd->status == GPD_STATE_WAIT_MASTER
2873f241775SRafael J. Wysocki 		|| genpd->status == GPD_STATE_ACTIVE || genpd->resume_count > 0;
288c6d22b37SRafael J. Wysocki }
289c6d22b37SRafael J. Wysocki 
290c6d22b37SRafael J. Wysocki /**
29156375fd4SRafael J. Wysocki  * genpd_queue_power_off_work - Queue up the execution of pm_genpd_poweroff().
29256375fd4SRafael J. Wysocki  * @genpd: PM domait to power off.
29356375fd4SRafael J. Wysocki  *
29456375fd4SRafael J. Wysocki  * Queue up the execution of pm_genpd_poweroff() unless it's already been done
29556375fd4SRafael J. Wysocki  * before.
29656375fd4SRafael J. Wysocki  */
2970bc5b2deSRafael J. Wysocki void genpd_queue_power_off_work(struct generic_pm_domain *genpd)
29856375fd4SRafael J. Wysocki {
29956375fd4SRafael J. Wysocki 	if (!work_pending(&genpd->power_off_work))
30056375fd4SRafael J. Wysocki 		queue_work(pm_wq, &genpd->power_off_work);
30156375fd4SRafael J. Wysocki }
30256375fd4SRafael J. Wysocki 
30356375fd4SRafael J. Wysocki /**
304f721889fSRafael J. Wysocki  * pm_genpd_poweroff - Remove power from a given PM domain.
305f721889fSRafael J. Wysocki  * @genpd: PM domain to power down.
306f721889fSRafael J. Wysocki  *
307f721889fSRafael J. Wysocki  * If all of the @genpd's devices have been suspended and all of its subdomains
308f721889fSRafael J. Wysocki  * have been powered down, run the runtime suspend callbacks provided by all of
309f721889fSRafael J. Wysocki  * the @genpd's devices' drivers and remove power from @genpd.
310f721889fSRafael J. Wysocki  */
311f721889fSRafael J. Wysocki static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
31217b75ecaSRafael J. Wysocki 	__releases(&genpd->lock) __acquires(&genpd->lock)
313f721889fSRafael J. Wysocki {
3144605ab65SRafael J. Wysocki 	struct pm_domain_data *pdd;
3155063ce15SRafael J. Wysocki 	struct gpd_link *link;
316f721889fSRafael J. Wysocki 	unsigned int not_suspended;
317c6d22b37SRafael J. Wysocki 	int ret = 0;
318f721889fSRafael J. Wysocki 
319c6d22b37SRafael J. Wysocki  start:
320c6d22b37SRafael J. Wysocki 	/*
321c6d22b37SRafael J. Wysocki 	 * Do not try to power off the domain in the following situations:
322c6d22b37SRafael J. Wysocki 	 * (1) The domain is already in the "power off" state.
3235063ce15SRafael J. Wysocki 	 * (2) The domain is waiting for its master to power up.
324c6d22b37SRafael J. Wysocki 	 * (3) One of the domain's devices is being resumed right now.
3253f241775SRafael J. Wysocki 	 * (4) System suspend is in progress.
326c6d22b37SRafael J. Wysocki 	 */
3273f241775SRafael J. Wysocki 	if (genpd->status == GPD_STATE_POWER_OFF
32817877eb5SRafael J. Wysocki 	    || genpd->status == GPD_STATE_WAIT_MASTER
3293f241775SRafael J. Wysocki 	    || genpd->resume_count > 0 || genpd->prepared_count > 0)
330f721889fSRafael J. Wysocki 		return 0;
331f721889fSRafael J. Wysocki 
332c4bb3160SRafael J. Wysocki 	if (atomic_read(&genpd->sd_count) > 0)
333f721889fSRafael J. Wysocki 		return -EBUSY;
334f721889fSRafael J. Wysocki 
335f721889fSRafael J. Wysocki 	not_suspended = 0;
3364605ab65SRafael J. Wysocki 	list_for_each_entry(pdd, &genpd->dev_list, list_node)
3370aa2a221SRafael J. Wysocki 		if (pdd->dev->driver && (!pm_runtime_suspended(pdd->dev)
3380aa2a221SRafael J. Wysocki 		    || pdd->dev->power.irq_safe))
339f721889fSRafael J. Wysocki 			not_suspended++;
340f721889fSRafael J. Wysocki 
341f721889fSRafael J. Wysocki 	if (not_suspended > genpd->in_progress)
342f721889fSRafael J. Wysocki 		return -EBUSY;
343f721889fSRafael J. Wysocki 
344c6d22b37SRafael J. Wysocki 	if (genpd->poweroff_task) {
345c6d22b37SRafael J. Wysocki 		/*
346c6d22b37SRafael J. Wysocki 		 * Another instance of pm_genpd_poweroff() is executing
347c6d22b37SRafael J. Wysocki 		 * callbacks, so tell it to start over and return.
348c6d22b37SRafael J. Wysocki 		 */
349c6d22b37SRafael J. Wysocki 		genpd->status = GPD_STATE_REPEAT;
350c6d22b37SRafael J. Wysocki 		return 0;
351c6d22b37SRafael J. Wysocki 	}
352c6d22b37SRafael J. Wysocki 
353f721889fSRafael J. Wysocki 	if (genpd->gov && genpd->gov->power_down_ok) {
354f721889fSRafael J. Wysocki 		if (!genpd->gov->power_down_ok(&genpd->domain))
355f721889fSRafael J. Wysocki 			return -EAGAIN;
356f721889fSRafael J. Wysocki 	}
357f721889fSRafael J. Wysocki 
35817b75ecaSRafael J. Wysocki 	genpd->status = GPD_STATE_BUSY;
359c6d22b37SRafael J. Wysocki 	genpd->poweroff_task = current;
36017b75ecaSRafael J. Wysocki 
3614605ab65SRafael J. Wysocki 	list_for_each_entry_reverse(pdd, &genpd->dev_list, list_node) {
3623c07cbc4SRafael J. Wysocki 		ret = atomic_read(&genpd->sd_count) == 0 ?
3634605ab65SRafael J. Wysocki 			__pm_genpd_save_device(pdd, genpd) : -EBUSY;
3643f241775SRafael J. Wysocki 
3653f241775SRafael J. Wysocki 		if (genpd_abort_poweroff(genpd))
3663f241775SRafael J. Wysocki 			goto out;
3673f241775SRafael J. Wysocki 
368697a7f37SRafael J. Wysocki 		if (ret) {
369697a7f37SRafael J. Wysocki 			genpd_set_active(genpd);
370697a7f37SRafael J. Wysocki 			goto out;
371697a7f37SRafael J. Wysocki 		}
372f721889fSRafael J. Wysocki 
373c6d22b37SRafael J. Wysocki 		if (genpd->status == GPD_STATE_REPEAT) {
374c6d22b37SRafael J. Wysocki 			genpd->poweroff_task = NULL;
375c6d22b37SRafael J. Wysocki 			goto start;
376c6d22b37SRafael J. Wysocki 		}
377c6d22b37SRafael J. Wysocki 	}
37817b75ecaSRafael J. Wysocki 
3793c07cbc4SRafael J. Wysocki 	if (genpd->power_off) {
3803c07cbc4SRafael J. Wysocki 		if (atomic_read(&genpd->sd_count) > 0) {
3813c07cbc4SRafael J. Wysocki 			ret = -EBUSY;
382c6d22b37SRafael J. Wysocki 			goto out;
383c6d22b37SRafael J. Wysocki 		}
38417b75ecaSRafael J. Wysocki 
3853c07cbc4SRafael J. Wysocki 		/*
3865063ce15SRafael J. Wysocki 		 * If sd_count > 0 at this point, one of the subdomains hasn't
3875063ce15SRafael J. Wysocki 		 * managed to call pm_genpd_poweron() for the master yet after
3883c07cbc4SRafael J. Wysocki 		 * incrementing it.  In that case pm_genpd_poweron() will wait
3893c07cbc4SRafael J. Wysocki 		 * for us to drop the lock, so we can call .power_off() and let
3903c07cbc4SRafael J. Wysocki 		 * the pm_genpd_poweron() restore power for us (this shouldn't
3913c07cbc4SRafael J. Wysocki 		 * happen very often).
3923c07cbc4SRafael J. Wysocki 		 */
393d2805402SRafael J. Wysocki 		ret = genpd->power_off(genpd);
394d2805402SRafael J. Wysocki 		if (ret == -EBUSY) {
395d2805402SRafael J. Wysocki 			genpd_set_active(genpd);
396d2805402SRafael J. Wysocki 			goto out;
397d2805402SRafael J. Wysocki 		}
398d2805402SRafael J. Wysocki 	}
399f721889fSRafael J. Wysocki 
40017b75ecaSRafael J. Wysocki 	genpd->status = GPD_STATE_POWER_OFF;
401221e9b58SRafael J. Wysocki 	genpd->power_off_time = ktime_get();
402221e9b58SRafael J. Wysocki 
403221e9b58SRafael J. Wysocki 	/* Update PM QoS information for devices in the domain. */
404221e9b58SRafael J. Wysocki 	list_for_each_entry_reverse(pdd, &genpd->dev_list, list_node) {
405221e9b58SRafael J. Wysocki 		struct gpd_timing_data *td = &to_gpd_data(pdd)->td;
406221e9b58SRafael J. Wysocki 
407221e9b58SRafael J. Wysocki 		pm_runtime_update_max_time_suspended(pdd->dev,
408221e9b58SRafael J. Wysocki 					td->start_latency_ns +
409221e9b58SRafael J. Wysocki 					td->restore_state_latency_ns +
410221e9b58SRafael J. Wysocki 					genpd->power_on_latency_ns);
411221e9b58SRafael J. Wysocki 	}
412f721889fSRafael J. Wysocki 
4135063ce15SRafael J. Wysocki 	list_for_each_entry(link, &genpd->slave_links, slave_node) {
4145063ce15SRafael J. Wysocki 		genpd_sd_counter_dec(link->master);
4155063ce15SRafael J. Wysocki 		genpd_queue_power_off_work(link->master);
4165063ce15SRafael J. Wysocki 	}
41717b75ecaSRafael J. Wysocki 
418c6d22b37SRafael J. Wysocki  out:
419c6d22b37SRafael J. Wysocki 	genpd->poweroff_task = NULL;
420c6d22b37SRafael J. Wysocki 	wake_up_all(&genpd->status_wait_queue);
421c6d22b37SRafael J. Wysocki 	return ret;
422f721889fSRafael J. Wysocki }
423f721889fSRafael J. Wysocki 
424f721889fSRafael J. Wysocki /**
425f721889fSRafael J. Wysocki  * genpd_power_off_work_fn - Power off PM domain whose subdomain count is 0.
426f721889fSRafael J. Wysocki  * @work: Work structure used for scheduling the execution of this function.
427f721889fSRafael J. Wysocki  */
428f721889fSRafael J. Wysocki static void genpd_power_off_work_fn(struct work_struct *work)
429f721889fSRafael J. Wysocki {
430f721889fSRafael J. Wysocki 	struct generic_pm_domain *genpd;
431f721889fSRafael J. Wysocki 
432f721889fSRafael J. Wysocki 	genpd = container_of(work, struct generic_pm_domain, power_off_work);
433f721889fSRafael J. Wysocki 
43417b75ecaSRafael J. Wysocki 	genpd_acquire_lock(genpd);
435f721889fSRafael J. Wysocki 	pm_genpd_poweroff(genpd);
43617b75ecaSRafael J. Wysocki 	genpd_release_lock(genpd);
437f721889fSRafael J. Wysocki }
438f721889fSRafael J. Wysocki 
439f721889fSRafael J. Wysocki /**
440f721889fSRafael J. Wysocki  * pm_genpd_runtime_suspend - Suspend a device belonging to I/O PM domain.
441f721889fSRafael J. Wysocki  * @dev: Device to suspend.
442f721889fSRafael J. Wysocki  *
443f721889fSRafael J. Wysocki  * Carry out a runtime suspend of a device under the assumption that its
444f721889fSRafael J. Wysocki  * pm_domain field points to the domain member of an object of type
445f721889fSRafael J. Wysocki  * struct generic_pm_domain representing a PM domain consisting of I/O devices.
446f721889fSRafael J. Wysocki  */
447f721889fSRafael J. Wysocki static int pm_genpd_runtime_suspend(struct device *dev)
448f721889fSRafael J. Wysocki {
449f721889fSRafael J. Wysocki 	struct generic_pm_domain *genpd;
450b02c999aSRafael J. Wysocki 	bool (*stop_ok)(struct device *__dev);
451d5e4cbfeSRafael J. Wysocki 	int ret;
452f721889fSRafael J. Wysocki 
453f721889fSRafael J. Wysocki 	dev_dbg(dev, "%s()\n", __func__);
454f721889fSRafael J. Wysocki 
4555248051bSRafael J. Wysocki 	genpd = dev_to_genpd(dev);
4565248051bSRafael J. Wysocki 	if (IS_ERR(genpd))
457f721889fSRafael J. Wysocki 		return -EINVAL;
458f721889fSRafael J. Wysocki 
4590aa2a221SRafael J. Wysocki 	might_sleep_if(!genpd->dev_irq_safe);
4600aa2a221SRafael J. Wysocki 
461b02c999aSRafael J. Wysocki 	stop_ok = genpd->gov ? genpd->gov->stop_ok : NULL;
462b02c999aSRafael J. Wysocki 	if (stop_ok && !stop_ok(dev))
463b02c999aSRafael J. Wysocki 		return -EBUSY;
464b02c999aSRafael J. Wysocki 
465d5e4cbfeSRafael J. Wysocki 	ret = genpd_stop_dev(genpd, dev);
466f721889fSRafael J. Wysocki 	if (ret)
46717b75ecaSRafael J. Wysocki 		return ret;
46817b75ecaSRafael J. Wysocki 
469b02c999aSRafael J. Wysocki 	pm_runtime_update_max_time_suspended(dev,
470b02c999aSRafael J. Wysocki 				dev_gpd_data(dev)->td.start_latency_ns);
471b02c999aSRafael J. Wysocki 
4720aa2a221SRafael J. Wysocki 	/*
4730aa2a221SRafael J. Wysocki 	 * If power.irq_safe is set, this routine will be run with interrupts
4740aa2a221SRafael J. Wysocki 	 * off, so it can't use mutexes.
4750aa2a221SRafael J. Wysocki 	 */
4760aa2a221SRafael J. Wysocki 	if (dev->power.irq_safe)
4770aa2a221SRafael J. Wysocki 		return 0;
4780aa2a221SRafael J. Wysocki 
479c6d22b37SRafael J. Wysocki 	mutex_lock(&genpd->lock);
480f721889fSRafael J. Wysocki 	genpd->in_progress++;
481f721889fSRafael J. Wysocki 	pm_genpd_poweroff(genpd);
482f721889fSRafael J. Wysocki 	genpd->in_progress--;
483c6d22b37SRafael J. Wysocki 	mutex_unlock(&genpd->lock);
484f721889fSRafael J. Wysocki 
485f721889fSRafael J. Wysocki 	return 0;
486f721889fSRafael J. Wysocki }
487f721889fSRafael J. Wysocki 
488f721889fSRafael J. Wysocki /**
489f721889fSRafael J. Wysocki  * pm_genpd_runtime_resume - Resume a device belonging to I/O PM domain.
490f721889fSRafael J. Wysocki  * @dev: Device to resume.
491f721889fSRafael J. Wysocki  *
492f721889fSRafael J. Wysocki  * Carry out a runtime resume of a device under the assumption that its
493f721889fSRafael J. Wysocki  * pm_domain field points to the domain member of an object of type
494f721889fSRafael J. Wysocki  * struct generic_pm_domain representing a PM domain consisting of I/O devices.
495f721889fSRafael J. Wysocki  */
496f721889fSRafael J. Wysocki static int pm_genpd_runtime_resume(struct device *dev)
497f721889fSRafael J. Wysocki {
498f721889fSRafael J. Wysocki 	struct generic_pm_domain *genpd;
499c6d22b37SRafael J. Wysocki 	DEFINE_WAIT(wait);
500f721889fSRafael J. Wysocki 	int ret;
501f721889fSRafael J. Wysocki 
502f721889fSRafael J. Wysocki 	dev_dbg(dev, "%s()\n", __func__);
503f721889fSRafael J. Wysocki 
5045248051bSRafael J. Wysocki 	genpd = dev_to_genpd(dev);
5055248051bSRafael J. Wysocki 	if (IS_ERR(genpd))
506f721889fSRafael J. Wysocki 		return -EINVAL;
507f721889fSRafael J. Wysocki 
5080aa2a221SRafael J. Wysocki 	might_sleep_if(!genpd->dev_irq_safe);
5090aa2a221SRafael J. Wysocki 
5100aa2a221SRafael J. Wysocki 	/* If power.irq_safe, the PM domain is never powered off. */
5110aa2a221SRafael J. Wysocki 	if (dev->power.irq_safe)
5120aa2a221SRafael J. Wysocki 		goto out;
5130aa2a221SRafael J. Wysocki 
514c6d22b37SRafael J. Wysocki 	mutex_lock(&genpd->lock);
5153f241775SRafael J. Wysocki 	ret = __pm_genpd_poweron(genpd);
5163f241775SRafael J. Wysocki 	if (ret) {
5173f241775SRafael J. Wysocki 		mutex_unlock(&genpd->lock);
5183f241775SRafael J. Wysocki 		return ret;
5193f241775SRafael J. Wysocki 	}
52017b75ecaSRafael J. Wysocki 	genpd->status = GPD_STATE_BUSY;
521c6d22b37SRafael J. Wysocki 	genpd->resume_count++;
522c6d22b37SRafael J. Wysocki 	for (;;) {
523c6d22b37SRafael J. Wysocki 		prepare_to_wait(&genpd->status_wait_queue, &wait,
524c6d22b37SRafael J. Wysocki 				TASK_UNINTERRUPTIBLE);
525c6d22b37SRafael J. Wysocki 		/*
526c6d22b37SRafael J. Wysocki 		 * If current is the powering off task, we have been called
527c6d22b37SRafael J. Wysocki 		 * reentrantly from one of the device callbacks, so we should
528c6d22b37SRafael J. Wysocki 		 * not wait.
529c6d22b37SRafael J. Wysocki 		 */
530c6d22b37SRafael J. Wysocki 		if (!genpd->poweroff_task || genpd->poweroff_task == current)
531c6d22b37SRafael J. Wysocki 			break;
532c6d22b37SRafael J. Wysocki 		mutex_unlock(&genpd->lock);
533c6d22b37SRafael J. Wysocki 
534c6d22b37SRafael J. Wysocki 		schedule();
535c6d22b37SRafael J. Wysocki 
536c6d22b37SRafael J. Wysocki 		mutex_lock(&genpd->lock);
537c6d22b37SRafael J. Wysocki 	}
538c6d22b37SRafael J. Wysocki 	finish_wait(&genpd->status_wait_queue, &wait);
539cd0ea672SRafael J. Wysocki 	__pm_genpd_restore_device(dev->power.subsys_data->domain_data, genpd);
540c6d22b37SRafael J. Wysocki 	genpd->resume_count--;
541c6d22b37SRafael J. Wysocki 	genpd_set_active(genpd);
54217b75ecaSRafael J. Wysocki 	wake_up_all(&genpd->status_wait_queue);
543c6d22b37SRafael J. Wysocki 	mutex_unlock(&genpd->lock);
54417b75ecaSRafael J. Wysocki 
5450aa2a221SRafael J. Wysocki  out:
546d5e4cbfeSRafael J. Wysocki 	genpd_start_dev(genpd, dev);
547f721889fSRafael J. Wysocki 
548f721889fSRafael J. Wysocki 	return 0;
549f721889fSRafael J. Wysocki }
550f721889fSRafael J. Wysocki 
55117f2ae7fSRafael J. Wysocki /**
55217f2ae7fSRafael J. Wysocki  * pm_genpd_poweroff_unused - Power off all PM domains with no devices in use.
55317f2ae7fSRafael J. Wysocki  */
55417f2ae7fSRafael J. Wysocki void pm_genpd_poweroff_unused(void)
55517f2ae7fSRafael J. Wysocki {
55617f2ae7fSRafael J. Wysocki 	struct generic_pm_domain *genpd;
55717f2ae7fSRafael J. Wysocki 
55817f2ae7fSRafael J. Wysocki 	mutex_lock(&gpd_list_lock);
55917f2ae7fSRafael J. Wysocki 
56017f2ae7fSRafael J. Wysocki 	list_for_each_entry(genpd, &gpd_list, gpd_list_node)
56117f2ae7fSRafael J. Wysocki 		genpd_queue_power_off_work(genpd);
56217f2ae7fSRafael J. Wysocki 
56317f2ae7fSRafael J. Wysocki 	mutex_unlock(&gpd_list_lock);
56417f2ae7fSRafael J. Wysocki }
56517f2ae7fSRafael J. Wysocki 
566f721889fSRafael J. Wysocki #else
567f721889fSRafael J. Wysocki 
568f721889fSRafael J. Wysocki static inline void genpd_power_off_work_fn(struct work_struct *work) {}
569f721889fSRafael J. Wysocki 
570f721889fSRafael J. Wysocki #define pm_genpd_runtime_suspend	NULL
571f721889fSRafael J. Wysocki #define pm_genpd_runtime_resume		NULL
572f721889fSRafael J. Wysocki 
573f721889fSRafael J. Wysocki #endif /* CONFIG_PM_RUNTIME */
574f721889fSRafael J. Wysocki 
575596ba34bSRafael J. Wysocki #ifdef CONFIG_PM_SLEEP
576596ba34bSRafael J. Wysocki 
577d5e4cbfeSRafael J. Wysocki static bool genpd_dev_active_wakeup(struct generic_pm_domain *genpd,
578d5e4cbfeSRafael J. Wysocki 				    struct device *dev)
579d5e4cbfeSRafael J. Wysocki {
580d5e4cbfeSRafael J. Wysocki 	return GENPD_DEV_CALLBACK(genpd, bool, active_wakeup, dev);
581d5e4cbfeSRafael J. Wysocki }
582d5e4cbfeSRafael J. Wysocki 
583d23b9b00SRafael J. Wysocki static int genpd_suspend_dev(struct generic_pm_domain *genpd, struct device *dev)
584d23b9b00SRafael J. Wysocki {
585d23b9b00SRafael J. Wysocki 	return GENPD_DEV_CALLBACK(genpd, int, suspend, dev);
586d23b9b00SRafael J. Wysocki }
587d23b9b00SRafael J. Wysocki 
588d23b9b00SRafael J. Wysocki static int genpd_suspend_late(struct generic_pm_domain *genpd, struct device *dev)
589d23b9b00SRafael J. Wysocki {
590d23b9b00SRafael J. Wysocki 	return GENPD_DEV_CALLBACK(genpd, int, suspend_late, dev);
591d23b9b00SRafael J. Wysocki }
592d23b9b00SRafael J. Wysocki 
593d23b9b00SRafael J. Wysocki static int genpd_resume_early(struct generic_pm_domain *genpd, struct device *dev)
594d23b9b00SRafael J. Wysocki {
595d23b9b00SRafael J. Wysocki 	return GENPD_DEV_CALLBACK(genpd, int, resume_early, dev);
596d23b9b00SRafael J. Wysocki }
597d23b9b00SRafael J. Wysocki 
598d23b9b00SRafael J. Wysocki static int genpd_resume_dev(struct generic_pm_domain *genpd, struct device *dev)
599d23b9b00SRafael J. Wysocki {
600d23b9b00SRafael J. Wysocki 	return GENPD_DEV_CALLBACK(genpd, int, resume, dev);
601d23b9b00SRafael J. Wysocki }
602d23b9b00SRafael J. Wysocki 
603d23b9b00SRafael J. Wysocki static int genpd_freeze_dev(struct generic_pm_domain *genpd, struct device *dev)
604d23b9b00SRafael J. Wysocki {
605d23b9b00SRafael J. Wysocki 	return GENPD_DEV_CALLBACK(genpd, int, freeze, dev);
606d23b9b00SRafael J. Wysocki }
607d23b9b00SRafael J. Wysocki 
608d23b9b00SRafael J. Wysocki static int genpd_freeze_late(struct generic_pm_domain *genpd, struct device *dev)
609d23b9b00SRafael J. Wysocki {
610d23b9b00SRafael J. Wysocki 	return GENPD_DEV_CALLBACK(genpd, int, freeze_late, dev);
611d23b9b00SRafael J. Wysocki }
612d23b9b00SRafael J. Wysocki 
613d23b9b00SRafael J. Wysocki static int genpd_thaw_early(struct generic_pm_domain *genpd, struct device *dev)
614d23b9b00SRafael J. Wysocki {
615d23b9b00SRafael J. Wysocki 	return GENPD_DEV_CALLBACK(genpd, int, thaw_early, dev);
616d23b9b00SRafael J. Wysocki }
617d23b9b00SRafael J. Wysocki 
618d23b9b00SRafael J. Wysocki static int genpd_thaw_dev(struct generic_pm_domain *genpd, struct device *dev)
619d23b9b00SRafael J. Wysocki {
620d23b9b00SRafael J. Wysocki 	return GENPD_DEV_CALLBACK(genpd, int, thaw, dev);
621d23b9b00SRafael J. Wysocki }
622d23b9b00SRafael J. Wysocki 
623596ba34bSRafael J. Wysocki /**
6245063ce15SRafael J. Wysocki  * pm_genpd_sync_poweroff - Synchronously power off a PM domain and its masters.
625596ba34bSRafael J. Wysocki  * @genpd: PM domain to power off, if possible.
626596ba34bSRafael J. Wysocki  *
627596ba34bSRafael J. Wysocki  * Check if the given PM domain can be powered off (during system suspend or
6285063ce15SRafael J. Wysocki  * hibernation) and do that if so.  Also, in that case propagate to its masters.
629596ba34bSRafael J. Wysocki  *
630596ba34bSRafael J. Wysocki  * This function is only called in "noirq" stages of system power transitions,
631596ba34bSRafael J. Wysocki  * so it need not acquire locks (all of the "noirq" callbacks are executed
632596ba34bSRafael J. Wysocki  * sequentially, so it is guaranteed that it will never run twice in parallel).
633596ba34bSRafael J. Wysocki  */
634596ba34bSRafael J. Wysocki static void pm_genpd_sync_poweroff(struct generic_pm_domain *genpd)
635596ba34bSRafael J. Wysocki {
6365063ce15SRafael J. Wysocki 	struct gpd_link *link;
637596ba34bSRafael J. Wysocki 
63817b75ecaSRafael J. Wysocki 	if (genpd->status == GPD_STATE_POWER_OFF)
639596ba34bSRafael J. Wysocki 		return;
640596ba34bSRafael J. Wysocki 
641c4bb3160SRafael J. Wysocki 	if (genpd->suspended_count != genpd->device_count
642c4bb3160SRafael J. Wysocki 	    || atomic_read(&genpd->sd_count) > 0)
643596ba34bSRafael J. Wysocki 		return;
644596ba34bSRafael J. Wysocki 
645596ba34bSRafael J. Wysocki 	if (genpd->power_off)
646596ba34bSRafael J. Wysocki 		genpd->power_off(genpd);
647596ba34bSRafael J. Wysocki 
64817b75ecaSRafael J. Wysocki 	genpd->status = GPD_STATE_POWER_OFF;
6495063ce15SRafael J. Wysocki 
6505063ce15SRafael J. Wysocki 	list_for_each_entry(link, &genpd->slave_links, slave_node) {
6515063ce15SRafael J. Wysocki 		genpd_sd_counter_dec(link->master);
6525063ce15SRafael J. Wysocki 		pm_genpd_sync_poweroff(link->master);
653596ba34bSRafael J. Wysocki 	}
654596ba34bSRafael J. Wysocki }
655596ba34bSRafael J. Wysocki 
656596ba34bSRafael J. Wysocki /**
6574ecd6e65SRafael J. Wysocki  * resume_needed - Check whether to resume a device before system suspend.
6584ecd6e65SRafael J. Wysocki  * @dev: Device to check.
6594ecd6e65SRafael J. Wysocki  * @genpd: PM domain the device belongs to.
6604ecd6e65SRafael J. Wysocki  *
6614ecd6e65SRafael J. Wysocki  * There are two cases in which a device that can wake up the system from sleep
6624ecd6e65SRafael J. Wysocki  * states should be resumed by pm_genpd_prepare(): (1) if the device is enabled
6634ecd6e65SRafael J. Wysocki  * to wake up the system and it has to remain active for this purpose while the
6644ecd6e65SRafael J. Wysocki  * system is in the sleep state and (2) if the device is not enabled to wake up
6654ecd6e65SRafael J. Wysocki  * the system from sleep states and it generally doesn't generate wakeup signals
6664ecd6e65SRafael J. Wysocki  * by itself (those signals are generated on its behalf by other parts of the
6674ecd6e65SRafael J. Wysocki  * system).  In the latter case it may be necessary to reconfigure the device's
6684ecd6e65SRafael J. Wysocki  * wakeup settings during system suspend, because it may have been set up to
6694ecd6e65SRafael J. Wysocki  * signal remote wakeup from the system's working state as needed by runtime PM.
6704ecd6e65SRafael J. Wysocki  * Return 'true' in either of the above cases.
6714ecd6e65SRafael J. Wysocki  */
6724ecd6e65SRafael J. Wysocki static bool resume_needed(struct device *dev, struct generic_pm_domain *genpd)
6734ecd6e65SRafael J. Wysocki {
6744ecd6e65SRafael J. Wysocki 	bool active_wakeup;
6754ecd6e65SRafael J. Wysocki 
6764ecd6e65SRafael J. Wysocki 	if (!device_can_wakeup(dev))
6774ecd6e65SRafael J. Wysocki 		return false;
6784ecd6e65SRafael J. Wysocki 
679d5e4cbfeSRafael J. Wysocki 	active_wakeup = genpd_dev_active_wakeup(genpd, dev);
6804ecd6e65SRafael J. Wysocki 	return device_may_wakeup(dev) ? active_wakeup : !active_wakeup;
6814ecd6e65SRafael J. Wysocki }
6824ecd6e65SRafael J. Wysocki 
6834ecd6e65SRafael J. Wysocki /**
684596ba34bSRafael J. Wysocki  * pm_genpd_prepare - Start power transition of a device in a PM domain.
685596ba34bSRafael J. Wysocki  * @dev: Device to start the transition of.
686596ba34bSRafael J. Wysocki  *
687596ba34bSRafael J. Wysocki  * Start a power transition of a device (during a system-wide power transition)
688596ba34bSRafael J. Wysocki  * under the assumption that its pm_domain field points to the domain member of
689596ba34bSRafael J. Wysocki  * an object of type struct generic_pm_domain representing a PM domain
690596ba34bSRafael J. Wysocki  * consisting of I/O devices.
691596ba34bSRafael J. Wysocki  */
692596ba34bSRafael J. Wysocki static int pm_genpd_prepare(struct device *dev)
693596ba34bSRafael J. Wysocki {
694596ba34bSRafael J. Wysocki 	struct generic_pm_domain *genpd;
695b6c10c84SRafael J. Wysocki 	int ret;
696596ba34bSRafael J. Wysocki 
697596ba34bSRafael J. Wysocki 	dev_dbg(dev, "%s()\n", __func__);
698596ba34bSRafael J. Wysocki 
699596ba34bSRafael J. Wysocki 	genpd = dev_to_genpd(dev);
700596ba34bSRafael J. Wysocki 	if (IS_ERR(genpd))
701596ba34bSRafael J. Wysocki 		return -EINVAL;
702596ba34bSRafael J. Wysocki 
70317b75ecaSRafael J. Wysocki 	/*
70417b75ecaSRafael J. Wysocki 	 * If a wakeup request is pending for the device, it should be woken up
70517b75ecaSRafael J. Wysocki 	 * at this point and a system wakeup event should be reported if it's
70617b75ecaSRafael J. Wysocki 	 * set up to wake up the system from sleep states.
70717b75ecaSRafael J. Wysocki 	 */
70817b75ecaSRafael J. Wysocki 	pm_runtime_get_noresume(dev);
70917b75ecaSRafael J. Wysocki 	if (pm_runtime_barrier(dev) && device_may_wakeup(dev))
71017b75ecaSRafael J. Wysocki 		pm_wakeup_event(dev, 0);
71117b75ecaSRafael J. Wysocki 
71217b75ecaSRafael J. Wysocki 	if (pm_wakeup_pending()) {
71317b75ecaSRafael J. Wysocki 		pm_runtime_put_sync(dev);
71417b75ecaSRafael J. Wysocki 		return -EBUSY;
71517b75ecaSRafael J. Wysocki 	}
71617b75ecaSRafael J. Wysocki 
7174ecd6e65SRafael J. Wysocki 	if (resume_needed(dev, genpd))
7184ecd6e65SRafael J. Wysocki 		pm_runtime_resume(dev);
7194ecd6e65SRafael J. Wysocki 
72017b75ecaSRafael J. Wysocki 	genpd_acquire_lock(genpd);
721596ba34bSRafael J. Wysocki 
722596ba34bSRafael J. Wysocki 	if (genpd->prepared_count++ == 0)
72317b75ecaSRafael J. Wysocki 		genpd->suspend_power_off = genpd->status == GPD_STATE_POWER_OFF;
72417b75ecaSRafael J. Wysocki 
72517b75ecaSRafael J. Wysocki 	genpd_release_lock(genpd);
726596ba34bSRafael J. Wysocki 
727596ba34bSRafael J. Wysocki 	if (genpd->suspend_power_off) {
72817b75ecaSRafael J. Wysocki 		pm_runtime_put_noidle(dev);
729596ba34bSRafael J. Wysocki 		return 0;
730596ba34bSRafael J. Wysocki 	}
731596ba34bSRafael J. Wysocki 
732596ba34bSRafael J. Wysocki 	/*
73317b75ecaSRafael J. Wysocki 	 * The PM domain must be in the GPD_STATE_ACTIVE state at this point,
73417b75ecaSRafael J. Wysocki 	 * so pm_genpd_poweron() will return immediately, but if the device
735d5e4cbfeSRafael J. Wysocki 	 * is suspended (e.g. it's been stopped by genpd_stop_dev()), we need
73617b75ecaSRafael J. Wysocki 	 * to make it operational.
737596ba34bSRafael J. Wysocki 	 */
73817b75ecaSRafael J. Wysocki 	pm_runtime_resume(dev);
739596ba34bSRafael J. Wysocki 	__pm_runtime_disable(dev, false);
740596ba34bSRafael J. Wysocki 
741b6c10c84SRafael J. Wysocki 	ret = pm_generic_prepare(dev);
742b6c10c84SRafael J. Wysocki 	if (ret) {
743b6c10c84SRafael J. Wysocki 		mutex_lock(&genpd->lock);
744b6c10c84SRafael J. Wysocki 
745b6c10c84SRafael J. Wysocki 		if (--genpd->prepared_count == 0)
746b6c10c84SRafael J. Wysocki 			genpd->suspend_power_off = false;
747b6c10c84SRafael J. Wysocki 
748b6c10c84SRafael J. Wysocki 		mutex_unlock(&genpd->lock);
74917b75ecaSRafael J. Wysocki 		pm_runtime_enable(dev);
750b6c10c84SRafael J. Wysocki 	}
75117b75ecaSRafael J. Wysocki 
75217b75ecaSRafael J. Wysocki 	pm_runtime_put_sync(dev);
753b6c10c84SRafael J. Wysocki 	return ret;
754596ba34bSRafael J. Wysocki }
755596ba34bSRafael J. Wysocki 
756596ba34bSRafael J. Wysocki /**
757596ba34bSRafael J. Wysocki  * pm_genpd_suspend - Suspend a device belonging to an I/O PM domain.
758596ba34bSRafael J. Wysocki  * @dev: Device to suspend.
759596ba34bSRafael J. Wysocki  *
760596ba34bSRafael J. Wysocki  * Suspend a device under the assumption that its pm_domain field points to the
761596ba34bSRafael J. Wysocki  * domain member of an object of type struct generic_pm_domain representing
762596ba34bSRafael J. Wysocki  * a PM domain consisting of I/O devices.
763596ba34bSRafael J. Wysocki  */
764596ba34bSRafael J. Wysocki static int pm_genpd_suspend(struct device *dev)
765596ba34bSRafael J. Wysocki {
766596ba34bSRafael J. Wysocki 	struct generic_pm_domain *genpd;
767596ba34bSRafael J. Wysocki 
768596ba34bSRafael J. Wysocki 	dev_dbg(dev, "%s()\n", __func__);
769596ba34bSRafael J. Wysocki 
770596ba34bSRafael J. Wysocki 	genpd = dev_to_genpd(dev);
771596ba34bSRafael J. Wysocki 	if (IS_ERR(genpd))
772596ba34bSRafael J. Wysocki 		return -EINVAL;
773596ba34bSRafael J. Wysocki 
774d23b9b00SRafael J. Wysocki 	return genpd->suspend_power_off ? 0 : genpd_suspend_dev(genpd, dev);
775596ba34bSRafael J. Wysocki }
776596ba34bSRafael J. Wysocki 
777596ba34bSRafael J. Wysocki /**
778596ba34bSRafael J. Wysocki  * pm_genpd_suspend_noirq - Late suspend of a device from an I/O PM domain.
779596ba34bSRafael J. Wysocki  * @dev: Device to suspend.
780596ba34bSRafael J. Wysocki  *
781596ba34bSRafael J. Wysocki  * Carry out a late suspend of a device under the assumption that its
782596ba34bSRafael J. Wysocki  * pm_domain field points to the domain member of an object of type
783596ba34bSRafael J. Wysocki  * struct generic_pm_domain representing a PM domain consisting of I/O devices.
784596ba34bSRafael J. Wysocki  */
785596ba34bSRafael J. Wysocki static int pm_genpd_suspend_noirq(struct device *dev)
786596ba34bSRafael J. Wysocki {
787596ba34bSRafael J. Wysocki 	struct generic_pm_domain *genpd;
788596ba34bSRafael J. Wysocki 	int ret;
789596ba34bSRafael J. Wysocki 
790596ba34bSRafael J. Wysocki 	dev_dbg(dev, "%s()\n", __func__);
791596ba34bSRafael J. Wysocki 
792596ba34bSRafael J. Wysocki 	genpd = dev_to_genpd(dev);
793596ba34bSRafael J. Wysocki 	if (IS_ERR(genpd))
794596ba34bSRafael J. Wysocki 		return -EINVAL;
795596ba34bSRafael J. Wysocki 
796596ba34bSRafael J. Wysocki 	if (genpd->suspend_power_off)
797596ba34bSRafael J. Wysocki 		return 0;
798596ba34bSRafael J. Wysocki 
799d23b9b00SRafael J. Wysocki 	ret = genpd_suspend_late(genpd, dev);
800596ba34bSRafael J. Wysocki 	if (ret)
801596ba34bSRafael J. Wysocki 		return ret;
802596ba34bSRafael J. Wysocki 
803d5e4cbfeSRafael J. Wysocki 	if (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))
804d4f2d87aSRafael J. Wysocki 		return 0;
805d4f2d87aSRafael J. Wysocki 
806d5e4cbfeSRafael J. Wysocki 	genpd_stop_dev(genpd, dev);
807596ba34bSRafael J. Wysocki 
808596ba34bSRafael J. Wysocki 	/*
809596ba34bSRafael J. Wysocki 	 * Since all of the "noirq" callbacks are executed sequentially, it is
810596ba34bSRafael J. Wysocki 	 * guaranteed that this function will never run twice in parallel for
811596ba34bSRafael J. Wysocki 	 * the same PM domain, so it is not necessary to use locking here.
812596ba34bSRafael J. Wysocki 	 */
813596ba34bSRafael J. Wysocki 	genpd->suspended_count++;
814596ba34bSRafael J. Wysocki 	pm_genpd_sync_poweroff(genpd);
815596ba34bSRafael J. Wysocki 
816596ba34bSRafael J. Wysocki 	return 0;
817596ba34bSRafael J. Wysocki }
818596ba34bSRafael J. Wysocki 
819596ba34bSRafael J. Wysocki /**
820596ba34bSRafael J. Wysocki  * pm_genpd_resume_noirq - Early resume of a device from an I/O power domain.
821596ba34bSRafael J. Wysocki  * @dev: Device to resume.
822596ba34bSRafael J. Wysocki  *
823596ba34bSRafael J. Wysocki  * Carry out an early resume of a device under the assumption that its
824596ba34bSRafael J. Wysocki  * pm_domain field points to the domain member of an object of type
825596ba34bSRafael J. Wysocki  * struct generic_pm_domain representing a power domain consisting of I/O
826596ba34bSRafael J. Wysocki  * devices.
827596ba34bSRafael J. Wysocki  */
828596ba34bSRafael J. Wysocki static int pm_genpd_resume_noirq(struct device *dev)
829596ba34bSRafael J. Wysocki {
830596ba34bSRafael J. Wysocki 	struct generic_pm_domain *genpd;
831596ba34bSRafael J. Wysocki 
832596ba34bSRafael J. Wysocki 	dev_dbg(dev, "%s()\n", __func__);
833596ba34bSRafael J. Wysocki 
834596ba34bSRafael J. Wysocki 	genpd = dev_to_genpd(dev);
835596ba34bSRafael J. Wysocki 	if (IS_ERR(genpd))
836596ba34bSRafael J. Wysocki 		return -EINVAL;
837596ba34bSRafael J. Wysocki 
838596ba34bSRafael J. Wysocki 	if (genpd->suspend_power_off)
839596ba34bSRafael J. Wysocki 		return 0;
840596ba34bSRafael J. Wysocki 
841596ba34bSRafael J. Wysocki 	/*
842596ba34bSRafael J. Wysocki 	 * Since all of the "noirq" callbacks are executed sequentially, it is
843596ba34bSRafael J. Wysocki 	 * guaranteed that this function will never run twice in parallel for
844596ba34bSRafael J. Wysocki 	 * the same PM domain, so it is not necessary to use locking here.
845596ba34bSRafael J. Wysocki 	 */
846596ba34bSRafael J. Wysocki 	pm_genpd_poweron(genpd);
847596ba34bSRafael J. Wysocki 	genpd->suspended_count--;
848d5e4cbfeSRafael J. Wysocki 	genpd_start_dev(genpd, dev);
849596ba34bSRafael J. Wysocki 
850d23b9b00SRafael J. Wysocki 	return genpd_resume_early(genpd, dev);
851596ba34bSRafael J. Wysocki }
852596ba34bSRafael J. Wysocki 
853596ba34bSRafael J. Wysocki /**
854596ba34bSRafael J. Wysocki  * pm_genpd_resume - Resume a device belonging to an I/O power domain.
855596ba34bSRafael J. Wysocki  * @dev: Device to resume.
856596ba34bSRafael J. Wysocki  *
857596ba34bSRafael J. Wysocki  * Resume a device under the assumption that its pm_domain field points to the
858596ba34bSRafael J. Wysocki  * domain member of an object of type struct generic_pm_domain representing
859596ba34bSRafael J. Wysocki  * a power domain consisting of I/O devices.
860596ba34bSRafael J. Wysocki  */
861596ba34bSRafael J. Wysocki static int pm_genpd_resume(struct device *dev)
862596ba34bSRafael J. Wysocki {
863596ba34bSRafael J. Wysocki 	struct generic_pm_domain *genpd;
864596ba34bSRafael J. Wysocki 
865596ba34bSRafael J. Wysocki 	dev_dbg(dev, "%s()\n", __func__);
866596ba34bSRafael J. Wysocki 
867596ba34bSRafael J. Wysocki 	genpd = dev_to_genpd(dev);
868596ba34bSRafael J. Wysocki 	if (IS_ERR(genpd))
869596ba34bSRafael J. Wysocki 		return -EINVAL;
870596ba34bSRafael J. Wysocki 
871d23b9b00SRafael J. Wysocki 	return genpd->suspend_power_off ? 0 : genpd_resume_dev(genpd, dev);
872596ba34bSRafael J. Wysocki }
873596ba34bSRafael J. Wysocki 
874596ba34bSRafael J. Wysocki /**
875596ba34bSRafael J. Wysocki  * pm_genpd_freeze - Freeze a device belonging to an I/O power domain.
876596ba34bSRafael J. Wysocki  * @dev: Device to freeze.
877596ba34bSRafael J. Wysocki  *
878596ba34bSRafael J. Wysocki  * Freeze a device under the assumption that its pm_domain field points to the
879596ba34bSRafael J. Wysocki  * domain member of an object of type struct generic_pm_domain representing
880596ba34bSRafael J. Wysocki  * a power domain consisting of I/O devices.
881596ba34bSRafael J. Wysocki  */
882596ba34bSRafael J. Wysocki static int pm_genpd_freeze(struct device *dev)
883596ba34bSRafael J. Wysocki {
884596ba34bSRafael J. Wysocki 	struct generic_pm_domain *genpd;
885596ba34bSRafael J. Wysocki 
886596ba34bSRafael J. Wysocki 	dev_dbg(dev, "%s()\n", __func__);
887596ba34bSRafael J. Wysocki 
888596ba34bSRafael J. Wysocki 	genpd = dev_to_genpd(dev);
889596ba34bSRafael J. Wysocki 	if (IS_ERR(genpd))
890596ba34bSRafael J. Wysocki 		return -EINVAL;
891596ba34bSRafael J. Wysocki 
892d23b9b00SRafael J. Wysocki 	return genpd->suspend_power_off ? 0 : genpd_freeze_dev(genpd, dev);
893596ba34bSRafael J. Wysocki }
894596ba34bSRafael J. Wysocki 
895596ba34bSRafael J. Wysocki /**
896596ba34bSRafael J. Wysocki  * pm_genpd_freeze_noirq - Late freeze of a device from an I/O power domain.
897596ba34bSRafael J. Wysocki  * @dev: Device to freeze.
898596ba34bSRafael J. Wysocki  *
899596ba34bSRafael J. Wysocki  * Carry out a late freeze of a device under the assumption that its
900596ba34bSRafael J. Wysocki  * pm_domain field points to the domain member of an object of type
901596ba34bSRafael J. Wysocki  * struct generic_pm_domain representing a power domain consisting of I/O
902596ba34bSRafael J. Wysocki  * devices.
903596ba34bSRafael J. Wysocki  */
904596ba34bSRafael J. Wysocki static int pm_genpd_freeze_noirq(struct device *dev)
905596ba34bSRafael J. Wysocki {
906596ba34bSRafael J. Wysocki 	struct generic_pm_domain *genpd;
907596ba34bSRafael J. Wysocki 	int ret;
908596ba34bSRafael J. Wysocki 
909596ba34bSRafael J. Wysocki 	dev_dbg(dev, "%s()\n", __func__);
910596ba34bSRafael J. Wysocki 
911596ba34bSRafael J. Wysocki 	genpd = dev_to_genpd(dev);
912596ba34bSRafael J. Wysocki 	if (IS_ERR(genpd))
913596ba34bSRafael J. Wysocki 		return -EINVAL;
914596ba34bSRafael J. Wysocki 
915596ba34bSRafael J. Wysocki 	if (genpd->suspend_power_off)
916596ba34bSRafael J. Wysocki 		return 0;
917596ba34bSRafael J. Wysocki 
918d23b9b00SRafael J. Wysocki 	ret = genpd_freeze_late(genpd, dev);
919596ba34bSRafael J. Wysocki 	if (ret)
920596ba34bSRafael J. Wysocki 		return ret;
921596ba34bSRafael J. Wysocki 
922d5e4cbfeSRafael J. Wysocki 	genpd_stop_dev(genpd, dev);
923596ba34bSRafael J. Wysocki 
924596ba34bSRafael J. Wysocki 	return 0;
925596ba34bSRafael J. Wysocki }
926596ba34bSRafael J. Wysocki 
927596ba34bSRafael J. Wysocki /**
928596ba34bSRafael J. Wysocki  * pm_genpd_thaw_noirq - Early thaw of a device from an I/O power domain.
929596ba34bSRafael J. Wysocki  * @dev: Device to thaw.
930596ba34bSRafael J. Wysocki  *
931596ba34bSRafael J. Wysocki  * Carry out an early thaw of a device under the assumption that its
932596ba34bSRafael J. Wysocki  * pm_domain field points to the domain member of an object of type
933596ba34bSRafael J. Wysocki  * struct generic_pm_domain representing a power domain consisting of I/O
934596ba34bSRafael J. Wysocki  * devices.
935596ba34bSRafael J. Wysocki  */
936596ba34bSRafael J. Wysocki static int pm_genpd_thaw_noirq(struct device *dev)
937596ba34bSRafael J. Wysocki {
938596ba34bSRafael J. Wysocki 	struct generic_pm_domain *genpd;
939596ba34bSRafael J. Wysocki 
940596ba34bSRafael J. Wysocki 	dev_dbg(dev, "%s()\n", __func__);
941596ba34bSRafael J. Wysocki 
942596ba34bSRafael J. Wysocki 	genpd = dev_to_genpd(dev);
943596ba34bSRafael J. Wysocki 	if (IS_ERR(genpd))
944596ba34bSRafael J. Wysocki 		return -EINVAL;
945596ba34bSRafael J. Wysocki 
946596ba34bSRafael J. Wysocki 	if (genpd->suspend_power_off)
947596ba34bSRafael J. Wysocki 		return 0;
948596ba34bSRafael J. Wysocki 
949d5e4cbfeSRafael J. Wysocki 	genpd_start_dev(genpd, dev);
950596ba34bSRafael J. Wysocki 
951d23b9b00SRafael J. Wysocki 	return genpd_thaw_early(genpd, dev);
952596ba34bSRafael J. Wysocki }
953596ba34bSRafael J. Wysocki 
954596ba34bSRafael J. Wysocki /**
955596ba34bSRafael J. Wysocki  * pm_genpd_thaw - Thaw a device belonging to an I/O power domain.
956596ba34bSRafael J. Wysocki  * @dev: Device to thaw.
957596ba34bSRafael J. Wysocki  *
958596ba34bSRafael J. Wysocki  * Thaw a device under the assumption that its pm_domain field points to the
959596ba34bSRafael J. Wysocki  * domain member of an object of type struct generic_pm_domain representing
960596ba34bSRafael J. Wysocki  * a power domain consisting of I/O devices.
961596ba34bSRafael J. Wysocki  */
962596ba34bSRafael J. Wysocki static int pm_genpd_thaw(struct device *dev)
963596ba34bSRafael J. Wysocki {
964596ba34bSRafael J. Wysocki 	struct generic_pm_domain *genpd;
965596ba34bSRafael J. Wysocki 
966596ba34bSRafael J. Wysocki 	dev_dbg(dev, "%s()\n", __func__);
967596ba34bSRafael J. Wysocki 
968596ba34bSRafael J. Wysocki 	genpd = dev_to_genpd(dev);
969596ba34bSRafael J. Wysocki 	if (IS_ERR(genpd))
970596ba34bSRafael J. Wysocki 		return -EINVAL;
971596ba34bSRafael J. Wysocki 
972d23b9b00SRafael J. Wysocki 	return genpd->suspend_power_off ? 0 : genpd_thaw_dev(genpd, dev);
973596ba34bSRafael J. Wysocki }
974596ba34bSRafael J. Wysocki 
975596ba34bSRafael J. Wysocki /**
976596ba34bSRafael J. Wysocki  * pm_genpd_restore_noirq - Early restore of a device from an I/O power domain.
977596ba34bSRafael J. Wysocki  * @dev: Device to resume.
978596ba34bSRafael J. Wysocki  *
979596ba34bSRafael J. Wysocki  * Carry out an early restore of a device under the assumption that its
980596ba34bSRafael J. Wysocki  * pm_domain field points to the domain member of an object of type
981596ba34bSRafael J. Wysocki  * struct generic_pm_domain representing a power domain consisting of I/O
982596ba34bSRafael J. Wysocki  * devices.
983596ba34bSRafael J. Wysocki  */
984596ba34bSRafael J. Wysocki static int pm_genpd_restore_noirq(struct device *dev)
985596ba34bSRafael J. Wysocki {
986596ba34bSRafael J. Wysocki 	struct generic_pm_domain *genpd;
987596ba34bSRafael J. Wysocki 
988596ba34bSRafael J. Wysocki 	dev_dbg(dev, "%s()\n", __func__);
989596ba34bSRafael J. Wysocki 
990596ba34bSRafael J. Wysocki 	genpd = dev_to_genpd(dev);
991596ba34bSRafael J. Wysocki 	if (IS_ERR(genpd))
992596ba34bSRafael J. Wysocki 		return -EINVAL;
993596ba34bSRafael J. Wysocki 
994596ba34bSRafael J. Wysocki 	/*
995596ba34bSRafael J. Wysocki 	 * Since all of the "noirq" callbacks are executed sequentially, it is
996596ba34bSRafael J. Wysocki 	 * guaranteed that this function will never run twice in parallel for
997596ba34bSRafael J. Wysocki 	 * the same PM domain, so it is not necessary to use locking here.
998596ba34bSRafael J. Wysocki 	 */
99917b75ecaSRafael J. Wysocki 	genpd->status = GPD_STATE_POWER_OFF;
1000596ba34bSRafael J. Wysocki 	if (genpd->suspend_power_off) {
1001596ba34bSRafael J. Wysocki 		/*
1002596ba34bSRafael J. Wysocki 		 * The boot kernel might put the domain into the power on state,
1003596ba34bSRafael J. Wysocki 		 * so make sure it really is powered off.
1004596ba34bSRafael J. Wysocki 		 */
1005596ba34bSRafael J. Wysocki 		if (genpd->power_off)
1006596ba34bSRafael J. Wysocki 			genpd->power_off(genpd);
1007596ba34bSRafael J. Wysocki 		return 0;
1008596ba34bSRafael J. Wysocki 	}
1009596ba34bSRafael J. Wysocki 
1010596ba34bSRafael J. Wysocki 	pm_genpd_poweron(genpd);
1011596ba34bSRafael J. Wysocki 	genpd->suspended_count--;
1012d5e4cbfeSRafael J. Wysocki 	genpd_start_dev(genpd, dev);
1013596ba34bSRafael J. Wysocki 
1014d23b9b00SRafael J. Wysocki 	return genpd_resume_early(genpd, dev);
1015596ba34bSRafael J. Wysocki }
1016596ba34bSRafael J. Wysocki 
1017596ba34bSRafael J. Wysocki /**
1018596ba34bSRafael J. Wysocki  * pm_genpd_complete - Complete power transition of a device in a power domain.
1019596ba34bSRafael J. Wysocki  * @dev: Device to complete the transition of.
1020596ba34bSRafael J. Wysocki  *
1021596ba34bSRafael J. Wysocki  * Complete a power transition of a device (during a system-wide power
1022596ba34bSRafael J. Wysocki  * transition) under the assumption that its pm_domain field points to the
1023596ba34bSRafael J. Wysocki  * domain member of an object of type struct generic_pm_domain representing
1024596ba34bSRafael J. Wysocki  * a power domain consisting of I/O devices.
1025596ba34bSRafael J. Wysocki  */
1026596ba34bSRafael J. Wysocki static void pm_genpd_complete(struct device *dev)
1027596ba34bSRafael J. Wysocki {
1028596ba34bSRafael J. Wysocki 	struct generic_pm_domain *genpd;
1029596ba34bSRafael J. Wysocki 	bool run_complete;
1030596ba34bSRafael J. Wysocki 
1031596ba34bSRafael J. Wysocki 	dev_dbg(dev, "%s()\n", __func__);
1032596ba34bSRafael J. Wysocki 
1033596ba34bSRafael J. Wysocki 	genpd = dev_to_genpd(dev);
1034596ba34bSRafael J. Wysocki 	if (IS_ERR(genpd))
1035596ba34bSRafael J. Wysocki 		return;
1036596ba34bSRafael J. Wysocki 
1037596ba34bSRafael J. Wysocki 	mutex_lock(&genpd->lock);
1038596ba34bSRafael J. Wysocki 
1039596ba34bSRafael J. Wysocki 	run_complete = !genpd->suspend_power_off;
1040596ba34bSRafael J. Wysocki 	if (--genpd->prepared_count == 0)
1041596ba34bSRafael J. Wysocki 		genpd->suspend_power_off = false;
1042596ba34bSRafael J. Wysocki 
1043596ba34bSRafael J. Wysocki 	mutex_unlock(&genpd->lock);
1044596ba34bSRafael J. Wysocki 
1045596ba34bSRafael J. Wysocki 	if (run_complete) {
1046596ba34bSRafael J. Wysocki 		pm_generic_complete(dev);
10476f00ff78SRafael J. Wysocki 		pm_runtime_set_active(dev);
1048596ba34bSRafael J. Wysocki 		pm_runtime_enable(dev);
10496f00ff78SRafael J. Wysocki 		pm_runtime_idle(dev);
1050596ba34bSRafael J. Wysocki 	}
1051596ba34bSRafael J. Wysocki }
1052596ba34bSRafael J. Wysocki 
1053596ba34bSRafael J. Wysocki #else
1054596ba34bSRafael J. Wysocki 
1055596ba34bSRafael J. Wysocki #define pm_genpd_prepare		NULL
1056596ba34bSRafael J. Wysocki #define pm_genpd_suspend		NULL
1057596ba34bSRafael J. Wysocki #define pm_genpd_suspend_noirq		NULL
1058596ba34bSRafael J. Wysocki #define pm_genpd_resume_noirq		NULL
1059596ba34bSRafael J. Wysocki #define pm_genpd_resume			NULL
1060596ba34bSRafael J. Wysocki #define pm_genpd_freeze			NULL
1061596ba34bSRafael J. Wysocki #define pm_genpd_freeze_noirq		NULL
1062596ba34bSRafael J. Wysocki #define pm_genpd_thaw_noirq		NULL
1063596ba34bSRafael J. Wysocki #define pm_genpd_thaw			NULL
1064596ba34bSRafael J. Wysocki #define pm_genpd_restore_noirq		NULL
1065596ba34bSRafael J. Wysocki #define pm_genpd_complete		NULL
1066596ba34bSRafael J. Wysocki 
1067596ba34bSRafael J. Wysocki #endif /* CONFIG_PM_SLEEP */
1068596ba34bSRafael J. Wysocki 
1069f721889fSRafael J. Wysocki /**
1070b02c999aSRafael J. Wysocki  * __pm_genpd_add_device - Add a device to an I/O PM domain.
1071f721889fSRafael J. Wysocki  * @genpd: PM domain to add the device to.
1072f721889fSRafael J. Wysocki  * @dev: Device to be added.
1073b02c999aSRafael J. Wysocki  * @td: Set of PM QoS timing parameters to attach to the device.
1074f721889fSRafael J. Wysocki  */
1075b02c999aSRafael J. Wysocki int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
1076b02c999aSRafael J. Wysocki 			  struct gpd_timing_data *td)
1077f721889fSRafael J. Wysocki {
1078cd0ea672SRafael J. Wysocki 	struct generic_pm_domain_data *gpd_data;
10794605ab65SRafael J. Wysocki 	struct pm_domain_data *pdd;
1080f721889fSRafael J. Wysocki 	int ret = 0;
1081f721889fSRafael J. Wysocki 
1082f721889fSRafael J. Wysocki 	dev_dbg(dev, "%s()\n", __func__);
1083f721889fSRafael J. Wysocki 
1084f721889fSRafael J. Wysocki 	if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev))
1085f721889fSRafael J. Wysocki 		return -EINVAL;
1086f721889fSRafael J. Wysocki 
108717b75ecaSRafael J. Wysocki 	genpd_acquire_lock(genpd);
1088f721889fSRafael J. Wysocki 
108917b75ecaSRafael J. Wysocki 	if (genpd->status == GPD_STATE_POWER_OFF) {
1090f721889fSRafael J. Wysocki 		ret = -EINVAL;
1091f721889fSRafael J. Wysocki 		goto out;
1092f721889fSRafael J. Wysocki 	}
1093f721889fSRafael J. Wysocki 
1094596ba34bSRafael J. Wysocki 	if (genpd->prepared_count > 0) {
1095596ba34bSRafael J. Wysocki 		ret = -EAGAIN;
1096596ba34bSRafael J. Wysocki 		goto out;
1097596ba34bSRafael J. Wysocki 	}
1098596ba34bSRafael J. Wysocki 
10994605ab65SRafael J. Wysocki 	list_for_each_entry(pdd, &genpd->dev_list, list_node)
11004605ab65SRafael J. Wysocki 		if (pdd->dev == dev) {
1101f721889fSRafael J. Wysocki 			ret = -EINVAL;
1102f721889fSRafael J. Wysocki 			goto out;
1103f721889fSRafael J. Wysocki 		}
1104f721889fSRafael J. Wysocki 
1105cd0ea672SRafael J. Wysocki 	gpd_data = kzalloc(sizeof(*gpd_data), GFP_KERNEL);
1106cd0ea672SRafael J. Wysocki 	if (!gpd_data) {
1107cd0ea672SRafael J. Wysocki 		ret = -ENOMEM;
1108cd0ea672SRafael J. Wysocki 		goto out;
1109cd0ea672SRafael J. Wysocki 	}
1110cd0ea672SRafael J. Wysocki 
1111596ba34bSRafael J. Wysocki 	genpd->device_count++;
1112f721889fSRafael J. Wysocki 
1113f721889fSRafael J. Wysocki 	dev->pm_domain = &genpd->domain;
11144605ab65SRafael J. Wysocki 	dev_pm_get_subsys_data(dev);
1115cd0ea672SRafael J. Wysocki 	dev->power.subsys_data->domain_data = &gpd_data->base;
1116cd0ea672SRafael J. Wysocki 	gpd_data->base.dev = dev;
1117cd0ea672SRafael J. Wysocki 	gpd_data->need_restore = false;
1118cd0ea672SRafael J. Wysocki 	list_add_tail(&gpd_data->base.list_node, &genpd->dev_list);
1119b02c999aSRafael J. Wysocki 	if (td)
1120b02c999aSRafael J. Wysocki 		gpd_data->td = *td;
1121f721889fSRafael J. Wysocki 
1122f721889fSRafael J. Wysocki  out:
112317b75ecaSRafael J. Wysocki 	genpd_release_lock(genpd);
1124f721889fSRafael J. Wysocki 
1125f721889fSRafael J. Wysocki 	return ret;
1126f721889fSRafael J. Wysocki }
1127f721889fSRafael J. Wysocki 
1128f721889fSRafael J. Wysocki /**
1129f721889fSRafael J. Wysocki  * pm_genpd_remove_device - Remove a device from an I/O PM domain.
1130f721889fSRafael J. Wysocki  * @genpd: PM domain to remove the device from.
1131f721889fSRafael J. Wysocki  * @dev: Device to be removed.
1132f721889fSRafael J. Wysocki  */
1133f721889fSRafael J. Wysocki int pm_genpd_remove_device(struct generic_pm_domain *genpd,
1134f721889fSRafael J. Wysocki 			   struct device *dev)
1135f721889fSRafael J. Wysocki {
11364605ab65SRafael J. Wysocki 	struct pm_domain_data *pdd;
1137f721889fSRafael J. Wysocki 	int ret = -EINVAL;
1138f721889fSRafael J. Wysocki 
1139f721889fSRafael J. Wysocki 	dev_dbg(dev, "%s()\n", __func__);
1140f721889fSRafael J. Wysocki 
1141f721889fSRafael J. Wysocki 	if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev))
1142f721889fSRafael J. Wysocki 		return -EINVAL;
1143f721889fSRafael J. Wysocki 
114417b75ecaSRafael J. Wysocki 	genpd_acquire_lock(genpd);
1145f721889fSRafael J. Wysocki 
1146596ba34bSRafael J. Wysocki 	if (genpd->prepared_count > 0) {
1147596ba34bSRafael J. Wysocki 		ret = -EAGAIN;
1148596ba34bSRafael J. Wysocki 		goto out;
1149596ba34bSRafael J. Wysocki 	}
1150596ba34bSRafael J. Wysocki 
11514605ab65SRafael J. Wysocki 	list_for_each_entry(pdd, &genpd->dev_list, list_node) {
11524605ab65SRafael J. Wysocki 		if (pdd->dev != dev)
1153f721889fSRafael J. Wysocki 			continue;
1154f721889fSRafael J. Wysocki 
11554605ab65SRafael J. Wysocki 		list_del_init(&pdd->list_node);
11564605ab65SRafael J. Wysocki 		pdd->dev = NULL;
11574605ab65SRafael J. Wysocki 		dev_pm_put_subsys_data(dev);
1158f721889fSRafael J. Wysocki 		dev->pm_domain = NULL;
1159cd0ea672SRafael J. Wysocki 		kfree(to_gpd_data(pdd));
1160f721889fSRafael J. Wysocki 
1161596ba34bSRafael J. Wysocki 		genpd->device_count--;
1162f721889fSRafael J. Wysocki 
1163f721889fSRafael J. Wysocki 		ret = 0;
1164f721889fSRafael J. Wysocki 		break;
1165f721889fSRafael J. Wysocki 	}
1166f721889fSRafael J. Wysocki 
1167596ba34bSRafael J. Wysocki  out:
116817b75ecaSRafael J. Wysocki 	genpd_release_lock(genpd);
1169f721889fSRafael J. Wysocki 
1170f721889fSRafael J. Wysocki 	return ret;
1171f721889fSRafael J. Wysocki }
1172f721889fSRafael J. Wysocki 
1173f721889fSRafael J. Wysocki /**
1174f721889fSRafael J. Wysocki  * pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain.
1175f721889fSRafael J. Wysocki  * @genpd: Master PM domain to add the subdomain to.
1176bc0403ffSRafael J. Wysocki  * @subdomain: Subdomain to be added.
1177f721889fSRafael J. Wysocki  */
1178f721889fSRafael J. Wysocki int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
1179bc0403ffSRafael J. Wysocki 			   struct generic_pm_domain *subdomain)
1180f721889fSRafael J. Wysocki {
11815063ce15SRafael J. Wysocki 	struct gpd_link *link;
1182f721889fSRafael J. Wysocki 	int ret = 0;
1183f721889fSRafael J. Wysocki 
1184bc0403ffSRafael J. Wysocki 	if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(subdomain))
1185f721889fSRafael J. Wysocki 		return -EINVAL;
1186f721889fSRafael J. Wysocki 
118717b75ecaSRafael J. Wysocki  start:
118817b75ecaSRafael J. Wysocki 	genpd_acquire_lock(genpd);
1189bc0403ffSRafael J. Wysocki 	mutex_lock_nested(&subdomain->lock, SINGLE_DEPTH_NESTING);
1190f721889fSRafael J. Wysocki 
1191bc0403ffSRafael J. Wysocki 	if (subdomain->status != GPD_STATE_POWER_OFF
1192bc0403ffSRafael J. Wysocki 	    && subdomain->status != GPD_STATE_ACTIVE) {
1193bc0403ffSRafael J. Wysocki 		mutex_unlock(&subdomain->lock);
119417b75ecaSRafael J. Wysocki 		genpd_release_lock(genpd);
119517b75ecaSRafael J. Wysocki 		goto start;
119617b75ecaSRafael J. Wysocki 	}
119717b75ecaSRafael J. Wysocki 
119817b75ecaSRafael J. Wysocki 	if (genpd->status == GPD_STATE_POWER_OFF
1199bc0403ffSRafael J. Wysocki 	    &&  subdomain->status != GPD_STATE_POWER_OFF) {
1200f721889fSRafael J. Wysocki 		ret = -EINVAL;
1201f721889fSRafael J. Wysocki 		goto out;
1202f721889fSRafael J. Wysocki 	}
1203f721889fSRafael J. Wysocki 
12045063ce15SRafael J. Wysocki 	list_for_each_entry(link, &genpd->slave_links, slave_node) {
1205bc0403ffSRafael J. Wysocki 		if (link->slave == subdomain && link->master == genpd) {
1206f721889fSRafael J. Wysocki 			ret = -EINVAL;
1207f721889fSRafael J. Wysocki 			goto out;
1208f721889fSRafael J. Wysocki 		}
1209f721889fSRafael J. Wysocki 	}
1210f721889fSRafael J. Wysocki 
12115063ce15SRafael J. Wysocki 	link = kzalloc(sizeof(*link), GFP_KERNEL);
12125063ce15SRafael J. Wysocki 	if (!link) {
12135063ce15SRafael J. Wysocki 		ret = -ENOMEM;
12145063ce15SRafael J. Wysocki 		goto out;
12155063ce15SRafael J. Wysocki 	}
12165063ce15SRafael J. Wysocki 	link->master = genpd;
12175063ce15SRafael J. Wysocki 	list_add_tail(&link->master_node, &genpd->master_links);
1218bc0403ffSRafael J. Wysocki 	link->slave = subdomain;
1219bc0403ffSRafael J. Wysocki 	list_add_tail(&link->slave_node, &subdomain->slave_links);
1220bc0403ffSRafael J. Wysocki 	if (subdomain->status != GPD_STATE_POWER_OFF)
1221c4bb3160SRafael J. Wysocki 		genpd_sd_counter_inc(genpd);
1222f721889fSRafael J. Wysocki 
1223f721889fSRafael J. Wysocki  out:
1224bc0403ffSRafael J. Wysocki 	mutex_unlock(&subdomain->lock);
122517b75ecaSRafael J. Wysocki 	genpd_release_lock(genpd);
1226f721889fSRafael J. Wysocki 
1227f721889fSRafael J. Wysocki 	return ret;
1228f721889fSRafael J. Wysocki }
1229f721889fSRafael J. Wysocki 
1230f721889fSRafael J. Wysocki /**
1231f721889fSRafael J. Wysocki  * pm_genpd_remove_subdomain - Remove a subdomain from an I/O PM domain.
1232f721889fSRafael J. Wysocki  * @genpd: Master PM domain to remove the subdomain from.
12335063ce15SRafael J. Wysocki  * @subdomain: Subdomain to be removed.
1234f721889fSRafael J. Wysocki  */
1235f721889fSRafael J. Wysocki int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
12365063ce15SRafael J. Wysocki 			      struct generic_pm_domain *subdomain)
1237f721889fSRafael J. Wysocki {
12385063ce15SRafael J. Wysocki 	struct gpd_link *link;
1239f721889fSRafael J. Wysocki 	int ret = -EINVAL;
1240f721889fSRafael J. Wysocki 
12415063ce15SRafael J. Wysocki 	if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(subdomain))
1242f721889fSRafael J. Wysocki 		return -EINVAL;
1243f721889fSRafael J. Wysocki 
124417b75ecaSRafael J. Wysocki  start:
124517b75ecaSRafael J. Wysocki 	genpd_acquire_lock(genpd);
1246f721889fSRafael J. Wysocki 
12475063ce15SRafael J. Wysocki 	list_for_each_entry(link, &genpd->master_links, master_node) {
12485063ce15SRafael J. Wysocki 		if (link->slave != subdomain)
1249f721889fSRafael J. Wysocki 			continue;
1250f721889fSRafael J. Wysocki 
1251f721889fSRafael J. Wysocki 		mutex_lock_nested(&subdomain->lock, SINGLE_DEPTH_NESTING);
1252f721889fSRafael J. Wysocki 
125317b75ecaSRafael J. Wysocki 		if (subdomain->status != GPD_STATE_POWER_OFF
125417b75ecaSRafael J. Wysocki 		    && subdomain->status != GPD_STATE_ACTIVE) {
125517b75ecaSRafael J. Wysocki 			mutex_unlock(&subdomain->lock);
125617b75ecaSRafael J. Wysocki 			genpd_release_lock(genpd);
125717b75ecaSRafael J. Wysocki 			goto start;
125817b75ecaSRafael J. Wysocki 		}
125917b75ecaSRafael J. Wysocki 
12605063ce15SRafael J. Wysocki 		list_del(&link->master_node);
12615063ce15SRafael J. Wysocki 		list_del(&link->slave_node);
12625063ce15SRafael J. Wysocki 		kfree(link);
126317b75ecaSRafael J. Wysocki 		if (subdomain->status != GPD_STATE_POWER_OFF)
1264f721889fSRafael J. Wysocki 			genpd_sd_counter_dec(genpd);
1265f721889fSRafael J. Wysocki 
1266f721889fSRafael J. Wysocki 		mutex_unlock(&subdomain->lock);
1267f721889fSRafael J. Wysocki 
1268f721889fSRafael J. Wysocki 		ret = 0;
1269f721889fSRafael J. Wysocki 		break;
1270f721889fSRafael J. Wysocki 	}
1271f721889fSRafael J. Wysocki 
127217b75ecaSRafael J. Wysocki 	genpd_release_lock(genpd);
1273f721889fSRafael J. Wysocki 
1274f721889fSRafael J. Wysocki 	return ret;
1275f721889fSRafael J. Wysocki }
1276f721889fSRafael J. Wysocki 
1277f721889fSRafael J. Wysocki /**
1278d5e4cbfeSRafael J. Wysocki  * pm_genpd_add_callbacks - Add PM domain callbacks to a given device.
1279d5e4cbfeSRafael J. Wysocki  * @dev: Device to add the callbacks to.
1280d5e4cbfeSRafael J. Wysocki  * @ops: Set of callbacks to add.
1281b02c999aSRafael J. Wysocki  * @td: Timing data to add to the device along with the callbacks (optional).
1282d5e4cbfeSRafael J. Wysocki  */
1283b02c999aSRafael J. Wysocki int pm_genpd_add_callbacks(struct device *dev, struct gpd_dev_ops *ops,
1284b02c999aSRafael J. Wysocki 			   struct gpd_timing_data *td)
1285d5e4cbfeSRafael J. Wysocki {
1286d5e4cbfeSRafael J. Wysocki 	struct pm_domain_data *pdd;
1287d5e4cbfeSRafael J. Wysocki 	int ret = 0;
1288d5e4cbfeSRafael J. Wysocki 
1289d5e4cbfeSRafael J. Wysocki 	if (!(dev && dev->power.subsys_data && ops))
1290d5e4cbfeSRafael J. Wysocki 		return -EINVAL;
1291d5e4cbfeSRafael J. Wysocki 
1292d5e4cbfeSRafael J. Wysocki 	pm_runtime_disable(dev);
1293d5e4cbfeSRafael J. Wysocki 	device_pm_lock();
1294d5e4cbfeSRafael J. Wysocki 
1295d5e4cbfeSRafael J. Wysocki 	pdd = dev->power.subsys_data->domain_data;
1296d5e4cbfeSRafael J. Wysocki 	if (pdd) {
1297d5e4cbfeSRafael J. Wysocki 		struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd);
1298d5e4cbfeSRafael J. Wysocki 
1299d5e4cbfeSRafael J. Wysocki 		gpd_data->ops = *ops;
1300b02c999aSRafael J. Wysocki 		if (td)
1301b02c999aSRafael J. Wysocki 			gpd_data->td = *td;
1302d5e4cbfeSRafael J. Wysocki 	} else {
1303d5e4cbfeSRafael J. Wysocki 		ret = -EINVAL;
1304d5e4cbfeSRafael J. Wysocki 	}
1305d5e4cbfeSRafael J. Wysocki 
1306d5e4cbfeSRafael J. Wysocki 	device_pm_unlock();
1307d5e4cbfeSRafael J. Wysocki 	pm_runtime_enable(dev);
1308d5e4cbfeSRafael J. Wysocki 
1309d5e4cbfeSRafael J. Wysocki 	return ret;
1310d5e4cbfeSRafael J. Wysocki }
1311d5e4cbfeSRafael J. Wysocki EXPORT_SYMBOL_GPL(pm_genpd_add_callbacks);
1312d5e4cbfeSRafael J. Wysocki 
1313d5e4cbfeSRafael J. Wysocki /**
1314b02c999aSRafael J. Wysocki  * __pm_genpd_remove_callbacks - Remove PM domain callbacks from a given device.
1315d5e4cbfeSRafael J. Wysocki  * @dev: Device to remove the callbacks from.
1316b02c999aSRafael J. Wysocki  * @clear_td: If set, clear the device's timing data too.
1317d5e4cbfeSRafael J. Wysocki  */
1318b02c999aSRafael J. Wysocki int __pm_genpd_remove_callbacks(struct device *dev, bool clear_td)
1319d5e4cbfeSRafael J. Wysocki {
1320d5e4cbfeSRafael J. Wysocki 	struct pm_domain_data *pdd;
1321d5e4cbfeSRafael J. Wysocki 	int ret = 0;
1322d5e4cbfeSRafael J. Wysocki 
1323d5e4cbfeSRafael J. Wysocki 	if (!(dev && dev->power.subsys_data))
1324d5e4cbfeSRafael J. Wysocki 		return -EINVAL;
1325d5e4cbfeSRafael J. Wysocki 
1326d5e4cbfeSRafael J. Wysocki 	pm_runtime_disable(dev);
1327d5e4cbfeSRafael J. Wysocki 	device_pm_lock();
1328d5e4cbfeSRafael J. Wysocki 
1329d5e4cbfeSRafael J. Wysocki 	pdd = dev->power.subsys_data->domain_data;
1330d5e4cbfeSRafael J. Wysocki 	if (pdd) {
1331d5e4cbfeSRafael J. Wysocki 		struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd);
1332d5e4cbfeSRafael J. Wysocki 
1333d5e4cbfeSRafael J. Wysocki 		gpd_data->ops = (struct gpd_dev_ops){ 0 };
1334b02c999aSRafael J. Wysocki 		if (clear_td)
1335b02c999aSRafael J. Wysocki 			gpd_data->td = (struct gpd_timing_data){ 0 };
1336d5e4cbfeSRafael J. Wysocki 	} else {
1337d5e4cbfeSRafael J. Wysocki 		ret = -EINVAL;
1338d5e4cbfeSRafael J. Wysocki 	}
1339d5e4cbfeSRafael J. Wysocki 
1340d5e4cbfeSRafael J. Wysocki 	device_pm_unlock();
1341d5e4cbfeSRafael J. Wysocki 	pm_runtime_enable(dev);
1342d5e4cbfeSRafael J. Wysocki 
1343d5e4cbfeSRafael J. Wysocki 	return ret;
1344d5e4cbfeSRafael J. Wysocki }
1345b02c999aSRafael J. Wysocki EXPORT_SYMBOL_GPL(__pm_genpd_remove_callbacks);
1346d5e4cbfeSRafael J. Wysocki 
1347d23b9b00SRafael J. Wysocki /* Default device callbacks for generic PM domains. */
1348d23b9b00SRafael J. Wysocki 
1349d5e4cbfeSRafael J. Wysocki /**
1350ecf00475SRafael J. Wysocki  * pm_genpd_default_save_state - Default "save device state" for PM domians.
1351ecf00475SRafael J. Wysocki  * @dev: Device to handle.
1352ecf00475SRafael J. Wysocki  */
1353ecf00475SRafael J. Wysocki static int pm_genpd_default_save_state(struct device *dev)
1354ecf00475SRafael J. Wysocki {
1355ecf00475SRafael J. Wysocki 	int (*cb)(struct device *__dev);
1356ecf00475SRafael J. Wysocki 	struct device_driver *drv = dev->driver;
1357ecf00475SRafael J. Wysocki 
1358ecf00475SRafael J. Wysocki 	cb = dev_gpd_data(dev)->ops.save_state;
1359ecf00475SRafael J. Wysocki 	if (cb)
1360ecf00475SRafael J. Wysocki 		return cb(dev);
1361ecf00475SRafael J. Wysocki 
1362ecf00475SRafael J. Wysocki 	if (drv && drv->pm && drv->pm->runtime_suspend)
1363ecf00475SRafael J. Wysocki 		return drv->pm->runtime_suspend(dev);
1364ecf00475SRafael J. Wysocki 
1365ecf00475SRafael J. Wysocki 	return 0;
1366ecf00475SRafael J. Wysocki }
1367ecf00475SRafael J. Wysocki 
1368ecf00475SRafael J. Wysocki /**
1369ecf00475SRafael J. Wysocki  * pm_genpd_default_restore_state - Default PM domians "restore device state".
1370ecf00475SRafael J. Wysocki  * @dev: Device to handle.
1371ecf00475SRafael J. Wysocki  */
1372ecf00475SRafael J. Wysocki static int pm_genpd_default_restore_state(struct device *dev)
1373ecf00475SRafael J. Wysocki {
1374ecf00475SRafael J. Wysocki 	int (*cb)(struct device *__dev);
1375ecf00475SRafael J. Wysocki 	struct device_driver *drv = dev->driver;
1376ecf00475SRafael J. Wysocki 
1377ecf00475SRafael J. Wysocki 	cb = dev_gpd_data(dev)->ops.restore_state;
1378ecf00475SRafael J. Wysocki 	if (cb)
1379ecf00475SRafael J. Wysocki 		return cb(dev);
1380ecf00475SRafael J. Wysocki 
1381ecf00475SRafael J. Wysocki 	if (drv && drv->pm && drv->pm->runtime_resume)
1382ecf00475SRafael J. Wysocki 		return drv->pm->runtime_resume(dev);
1383ecf00475SRafael J. Wysocki 
1384ecf00475SRafael J. Wysocki 	return 0;
1385ecf00475SRafael J. Wysocki }
1386ecf00475SRafael J. Wysocki 
1387ecf00475SRafael J. Wysocki /**
1388d23b9b00SRafael J. Wysocki  * pm_genpd_default_suspend - Default "device suspend" for PM domians.
1389d23b9b00SRafael J. Wysocki  * @dev: Device to handle.
1390d23b9b00SRafael J. Wysocki  */
1391d23b9b00SRafael J. Wysocki static int pm_genpd_default_suspend(struct device *dev)
1392d23b9b00SRafael J. Wysocki {
1393d23b9b00SRafael J. Wysocki 	int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.freeze;
1394d23b9b00SRafael J. Wysocki 
1395d23b9b00SRafael J. Wysocki 	return cb ? cb(dev) : pm_generic_suspend(dev);
1396d23b9b00SRafael J. Wysocki }
1397d23b9b00SRafael J. Wysocki 
1398d23b9b00SRafael J. Wysocki /**
1399d23b9b00SRafael J. Wysocki  * pm_genpd_default_suspend_late - Default "late device suspend" for PM domians.
1400d23b9b00SRafael J. Wysocki  * @dev: Device to handle.
1401d23b9b00SRafael J. Wysocki  */
1402d23b9b00SRafael J. Wysocki static int pm_genpd_default_suspend_late(struct device *dev)
1403d23b9b00SRafael J. Wysocki {
1404d23b9b00SRafael J. Wysocki 	int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.freeze_late;
1405d23b9b00SRafael J. Wysocki 
1406d23b9b00SRafael J. Wysocki 	return cb ? cb(dev) : pm_generic_suspend_noirq(dev);
1407d23b9b00SRafael J. Wysocki }
1408d23b9b00SRafael J. Wysocki 
1409d23b9b00SRafael J. Wysocki /**
1410d23b9b00SRafael J. Wysocki  * pm_genpd_default_resume_early - Default "early device resume" for PM domians.
1411d23b9b00SRafael J. Wysocki  * @dev: Device to handle.
1412d23b9b00SRafael J. Wysocki  */
1413d23b9b00SRafael J. Wysocki static int pm_genpd_default_resume_early(struct device *dev)
1414d23b9b00SRafael J. Wysocki {
1415d23b9b00SRafael J. Wysocki 	int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.thaw_early;
1416d23b9b00SRafael J. Wysocki 
1417d23b9b00SRafael J. Wysocki 	return cb ? cb(dev) : pm_generic_resume_noirq(dev);
1418d23b9b00SRafael J. Wysocki }
1419d23b9b00SRafael J. Wysocki 
1420d23b9b00SRafael J. Wysocki /**
1421d23b9b00SRafael J. Wysocki  * pm_genpd_default_resume - Default "device resume" for PM domians.
1422d23b9b00SRafael J. Wysocki  * @dev: Device to handle.
1423d23b9b00SRafael J. Wysocki  */
1424d23b9b00SRafael J. Wysocki static int pm_genpd_default_resume(struct device *dev)
1425d23b9b00SRafael J. Wysocki {
1426d23b9b00SRafael J. Wysocki 	int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.thaw;
1427d23b9b00SRafael J. Wysocki 
1428d23b9b00SRafael J. Wysocki 	return cb ? cb(dev) : pm_generic_resume(dev);
1429d23b9b00SRafael J. Wysocki }
1430d23b9b00SRafael J. Wysocki 
1431d23b9b00SRafael J. Wysocki /**
1432d23b9b00SRafael J. Wysocki  * pm_genpd_default_freeze - Default "device freeze" for PM domians.
1433d23b9b00SRafael J. Wysocki  * @dev: Device to handle.
1434d23b9b00SRafael J. Wysocki  */
1435d23b9b00SRafael J. Wysocki static int pm_genpd_default_freeze(struct device *dev)
1436d23b9b00SRafael J. Wysocki {
1437d23b9b00SRafael J. Wysocki 	int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.freeze;
1438d23b9b00SRafael J. Wysocki 
1439d23b9b00SRafael J. Wysocki 	return cb ? cb(dev) : pm_generic_freeze(dev);
1440d23b9b00SRafael J. Wysocki }
1441d23b9b00SRafael J. Wysocki 
1442d23b9b00SRafael J. Wysocki /**
1443d23b9b00SRafael J. Wysocki  * pm_genpd_default_freeze_late - Default "late device freeze" for PM domians.
1444d23b9b00SRafael J. Wysocki  * @dev: Device to handle.
1445d23b9b00SRafael J. Wysocki  */
1446d23b9b00SRafael J. Wysocki static int pm_genpd_default_freeze_late(struct device *dev)
1447d23b9b00SRafael J. Wysocki {
1448d23b9b00SRafael J. Wysocki 	int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.freeze_late;
1449d23b9b00SRafael J. Wysocki 
1450d23b9b00SRafael J. Wysocki 	return cb ? cb(dev) : pm_generic_freeze_noirq(dev);
1451d23b9b00SRafael J. Wysocki }
1452d23b9b00SRafael J. Wysocki 
1453d23b9b00SRafael J. Wysocki /**
1454d23b9b00SRafael J. Wysocki  * pm_genpd_default_thaw_early - Default "early device thaw" for PM domians.
1455d23b9b00SRafael J. Wysocki  * @dev: Device to handle.
1456d23b9b00SRafael J. Wysocki  */
1457d23b9b00SRafael J. Wysocki static int pm_genpd_default_thaw_early(struct device *dev)
1458d23b9b00SRafael J. Wysocki {
1459d23b9b00SRafael J. Wysocki 	int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.thaw_early;
1460d23b9b00SRafael J. Wysocki 
1461d23b9b00SRafael J. Wysocki 	return cb ? cb(dev) : pm_generic_thaw_noirq(dev);
1462d23b9b00SRafael J. Wysocki }
1463d23b9b00SRafael J. Wysocki 
1464d23b9b00SRafael J. Wysocki /**
1465d23b9b00SRafael J. Wysocki  * pm_genpd_default_thaw - Default "device thaw" for PM domians.
1466d23b9b00SRafael J. Wysocki  * @dev: Device to handle.
1467d23b9b00SRafael J. Wysocki  */
1468d23b9b00SRafael J. Wysocki static int pm_genpd_default_thaw(struct device *dev)
1469d23b9b00SRafael J. Wysocki {
1470d23b9b00SRafael J. Wysocki 	int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.thaw;
1471d23b9b00SRafael J. Wysocki 
1472d23b9b00SRafael J. Wysocki 	return cb ? cb(dev) : pm_generic_thaw(dev);
1473d23b9b00SRafael J. Wysocki }
1474d23b9b00SRafael J. Wysocki 
1475d23b9b00SRafael J. Wysocki /**
1476f721889fSRafael J. Wysocki  * pm_genpd_init - Initialize a generic I/O PM domain object.
1477f721889fSRafael J. Wysocki  * @genpd: PM domain object to initialize.
1478f721889fSRafael J. Wysocki  * @gov: PM domain governor to associate with the domain (may be NULL).
1479f721889fSRafael J. Wysocki  * @is_off: Initial value of the domain's power_is_off field.
1480f721889fSRafael J. Wysocki  */
1481f721889fSRafael J. Wysocki void pm_genpd_init(struct generic_pm_domain *genpd,
1482f721889fSRafael J. Wysocki 		   struct dev_power_governor *gov, bool is_off)
1483f721889fSRafael J. Wysocki {
1484f721889fSRafael J. Wysocki 	if (IS_ERR_OR_NULL(genpd))
1485f721889fSRafael J. Wysocki 		return;
1486f721889fSRafael J. Wysocki 
14875063ce15SRafael J. Wysocki 	INIT_LIST_HEAD(&genpd->master_links);
14885063ce15SRafael J. Wysocki 	INIT_LIST_HEAD(&genpd->slave_links);
1489f721889fSRafael J. Wysocki 	INIT_LIST_HEAD(&genpd->dev_list);
1490f721889fSRafael J. Wysocki 	mutex_init(&genpd->lock);
1491f721889fSRafael J. Wysocki 	genpd->gov = gov;
1492f721889fSRafael J. Wysocki 	INIT_WORK(&genpd->power_off_work, genpd_power_off_work_fn);
1493f721889fSRafael J. Wysocki 	genpd->in_progress = 0;
1494c4bb3160SRafael J. Wysocki 	atomic_set(&genpd->sd_count, 0);
149517b75ecaSRafael J. Wysocki 	genpd->status = is_off ? GPD_STATE_POWER_OFF : GPD_STATE_ACTIVE;
149617b75ecaSRafael J. Wysocki 	init_waitqueue_head(&genpd->status_wait_queue);
1497c6d22b37SRafael J. Wysocki 	genpd->poweroff_task = NULL;
1498c6d22b37SRafael J. Wysocki 	genpd->resume_count = 0;
1499596ba34bSRafael J. Wysocki 	genpd->device_count = 0;
1500596ba34bSRafael J. Wysocki 	genpd->suspended_count = 0;
1501221e9b58SRafael J. Wysocki 	genpd->max_off_time_ns = -1;
1502f721889fSRafael J. Wysocki 	genpd->domain.ops.runtime_suspend = pm_genpd_runtime_suspend;
1503f721889fSRafael J. Wysocki 	genpd->domain.ops.runtime_resume = pm_genpd_runtime_resume;
1504f721889fSRafael J. Wysocki 	genpd->domain.ops.runtime_idle = pm_generic_runtime_idle;
1505596ba34bSRafael J. Wysocki 	genpd->domain.ops.prepare = pm_genpd_prepare;
1506596ba34bSRafael J. Wysocki 	genpd->domain.ops.suspend = pm_genpd_suspend;
1507596ba34bSRafael J. Wysocki 	genpd->domain.ops.suspend_noirq = pm_genpd_suspend_noirq;
1508596ba34bSRafael J. Wysocki 	genpd->domain.ops.resume_noirq = pm_genpd_resume_noirq;
1509596ba34bSRafael J. Wysocki 	genpd->domain.ops.resume = pm_genpd_resume;
1510596ba34bSRafael J. Wysocki 	genpd->domain.ops.freeze = pm_genpd_freeze;
1511596ba34bSRafael J. Wysocki 	genpd->domain.ops.freeze_noirq = pm_genpd_freeze_noirq;
1512596ba34bSRafael J. Wysocki 	genpd->domain.ops.thaw_noirq = pm_genpd_thaw_noirq;
1513596ba34bSRafael J. Wysocki 	genpd->domain.ops.thaw = pm_genpd_thaw;
1514d23b9b00SRafael J. Wysocki 	genpd->domain.ops.poweroff = pm_genpd_suspend;
1515d23b9b00SRafael J. Wysocki 	genpd->domain.ops.poweroff_noirq = pm_genpd_suspend_noirq;
1516596ba34bSRafael J. Wysocki 	genpd->domain.ops.restore_noirq = pm_genpd_restore_noirq;
1517d23b9b00SRafael J. Wysocki 	genpd->domain.ops.restore = pm_genpd_resume;
1518596ba34bSRafael J. Wysocki 	genpd->domain.ops.complete = pm_genpd_complete;
1519ecf00475SRafael J. Wysocki 	genpd->dev_ops.save_state = pm_genpd_default_save_state;
1520ecf00475SRafael J. Wysocki 	genpd->dev_ops.restore_state = pm_genpd_default_restore_state;
1521d23b9b00SRafael J. Wysocki 	genpd->dev_ops.freeze = pm_genpd_default_suspend;
1522d23b9b00SRafael J. Wysocki 	genpd->dev_ops.freeze_late = pm_genpd_default_suspend_late;
1523d23b9b00SRafael J. Wysocki 	genpd->dev_ops.thaw_early = pm_genpd_default_resume_early;
1524d23b9b00SRafael J. Wysocki 	genpd->dev_ops.thaw = pm_genpd_default_resume;
1525d23b9b00SRafael J. Wysocki 	genpd->dev_ops.freeze = pm_genpd_default_freeze;
1526d23b9b00SRafael J. Wysocki 	genpd->dev_ops.freeze_late = pm_genpd_default_freeze_late;
1527d23b9b00SRafael J. Wysocki 	genpd->dev_ops.thaw_early = pm_genpd_default_thaw_early;
1528d23b9b00SRafael J. Wysocki 	genpd->dev_ops.thaw = pm_genpd_default_thaw;
15295125bbf3SRafael J. Wysocki 	mutex_lock(&gpd_list_lock);
15305125bbf3SRafael J. Wysocki 	list_add(&genpd->gpd_list_node, &gpd_list);
15315125bbf3SRafael J. Wysocki 	mutex_unlock(&gpd_list_lock);
15325125bbf3SRafael J. Wysocki }
1533