aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/power
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2011-11-27 07:11:44 -0500
committerRafael J. Wysocki <rjw@sisk.pl>2011-12-01 15:47:18 -0500
commitecf00475f229fcf06362412ad2d15a3267e354a1 (patch)
tree282792856ca84debf81e6c29141a6bebe7fdb966 /drivers/base/power
parentd5e4cbfe2049fca375cb19c4bc0cf676e8b4a88a (diff)
PM / Domains: Introduce "save/restore state" device callbacks
The current PM domains code uses device drivers' .runtime_suspend() and .runtime_resume() callbacks as the "save device state" and "restore device state" operations, which may not be appropriate in general, because it forces drivers to assume that they always will be used with generic PM domains. However, in theory, the same hardware may be used in devices that don't belong to any PM domain, in which case it would be necessary to add "fake" PM domains to satisfy the above assumption. It also may be located in a PM domain that's not handled with the help of the generic code. To allow device drivers that may be used along with the generic PM domains code of more flexibility, introduce new device callbacks, .save_state() and .restore_state(), that can be supplied by the drivers in addition to their "standard" runtime PM callbacks. This will allow the drivers to be designed to work with generic PM domains as well as without them. For backwards compatibility, introduce default .save_state() and .restore_state() callback routines for PM domains that will execute a device driver's .runtime_suspend() and .runtime_resume() callbacks, respectively, for the given device if the driver doesn't provide its own implementations of .save_state() and .restore_state(). Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Diffstat (limited to 'drivers/base/power')
-rw-r--r--drivers/base/power/domain.c68
1 files changed, 56 insertions, 12 deletions
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 94afaa2686a6..3c9451b10427 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -56,6 +56,16 @@ static int genpd_start_dev(struct generic_pm_domain *genpd, struct device *dev)
56 return GENPD_DEV_CALLBACK(genpd, int, start, dev); 56 return GENPD_DEV_CALLBACK(genpd, int, start, dev);
57} 57}
58 58
59static int genpd_save_dev(struct generic_pm_domain *genpd, struct device *dev)
60{
61 return GENPD_DEV_CALLBACK(genpd, int, save_state, dev);
62}
63
64static int genpd_restore_dev(struct generic_pm_domain *genpd, struct device *dev)
65{
66 return GENPD_DEV_CALLBACK(genpd, int, restore_state, dev);
67}
68
59static bool genpd_sd_counter_dec(struct generic_pm_domain *genpd) 69static bool genpd_sd_counter_dec(struct generic_pm_domain *genpd)
60{ 70{
61 bool ret = false; 71 bool ret = false;
@@ -217,7 +227,6 @@ static int __pm_genpd_save_device(struct pm_domain_data *pdd,
217{ 227{
218 struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd); 228 struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd);
219 struct device *dev = pdd->dev; 229 struct device *dev = pdd->dev;
220 struct device_driver *drv = dev->driver;
221 int ret = 0; 230 int ret = 0;
222 231
223 if (gpd_data->need_restore) 232 if (gpd_data->need_restore)
@@ -225,11 +234,9 @@ static int __pm_genpd_save_device(struct pm_domain_data *pdd,
225 234
226 mutex_unlock(&genpd->lock); 235 mutex_unlock(&genpd->lock);
227 236
228 if (drv && drv->pm && drv->pm->runtime_suspend) { 237 genpd_start_dev(genpd, dev);
229 genpd_start_dev(genpd, dev); 238 ret = genpd_save_dev(genpd, dev);
230 ret = drv->pm->runtime_suspend(dev); 239 genpd_stop_dev(genpd, dev);
231 genpd_stop_dev(genpd, dev);
232 }
233 240
234 mutex_lock(&genpd->lock); 241 mutex_lock(&genpd->lock);
235 242
@@ -250,18 +257,15 @@ static void __pm_genpd_restore_device(struct pm_domain_data *pdd,
250{ 257{
251 struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd); 258 struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd);
252 struct device *dev = pdd->dev; 259 struct device *dev = pdd->dev;
253 struct device_driver *drv = dev->driver;
254 260
255 if (!gpd_data->need_restore) 261 if (!gpd_data->need_restore)
256 return; 262 return;
257 263
258 mutex_unlock(&genpd->lock); 264 mutex_unlock(&genpd->lock);
259 265
260 if (drv && drv->pm && drv->pm->runtime_resume) { 266 genpd_start_dev(genpd, dev);
261 genpd_start_dev(genpd, dev); 267 genpd_restore_dev(genpd, dev);
262 drv->pm->runtime_resume(dev); 268 genpd_stop_dev(genpd, dev);
263 genpd_stop_dev(genpd, dev);
264 }
265 269
266 mutex_lock(&genpd->lock); 270 mutex_lock(&genpd->lock);
267 271
@@ -1358,6 +1362,44 @@ int pm_genpd_remove_callbacks(struct device *dev)
1358EXPORT_SYMBOL_GPL(pm_genpd_remove_callbacks); 1362EXPORT_SYMBOL_GPL(pm_genpd_remove_callbacks);
1359 1363
1360/** 1364/**
1365 * pm_genpd_default_save_state - Default "save device state" for PM domians.
1366 * @dev: Device to handle.
1367 */
1368static int pm_genpd_default_save_state(struct device *dev)
1369{
1370 int (*cb)(struct device *__dev);
1371 struct device_driver *drv = dev->driver;
1372
1373 cb = dev_gpd_data(dev)->ops.save_state;
1374 if (cb)
1375 return cb(dev);
1376
1377 if (drv && drv->pm && drv->pm->runtime_suspend)
1378 return drv->pm->runtime_suspend(dev);
1379
1380 return 0;
1381}
1382
1383/**
1384 * pm_genpd_default_restore_state - Default PM domians "restore device state".
1385 * @dev: Device to handle.
1386 */
1387static int pm_genpd_default_restore_state(struct device *dev)
1388{
1389 int (*cb)(struct device *__dev);
1390 struct device_driver *drv = dev->driver;
1391
1392 cb = dev_gpd_data(dev)->ops.restore_state;
1393 if (cb)
1394 return cb(dev);
1395
1396 if (drv && drv->pm && drv->pm->runtime_resume)
1397 return drv->pm->runtime_resume(dev);
1398
1399 return 0;
1400}
1401
1402/**
1361 * pm_genpd_init - Initialize a generic I/O PM domain object. 1403 * pm_genpd_init - Initialize a generic I/O PM domain object.
1362 * @genpd: PM domain object to initialize. 1404 * @genpd: PM domain object to initialize.
1363 * @gov: PM domain governor to associate with the domain (may be NULL). 1405 * @gov: PM domain governor to associate with the domain (may be NULL).
@@ -1400,6 +1442,8 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
1400 genpd->domain.ops.restore_noirq = pm_genpd_restore_noirq; 1442 genpd->domain.ops.restore_noirq = pm_genpd_restore_noirq;
1401 genpd->domain.ops.restore = pm_genpd_restore; 1443 genpd->domain.ops.restore = pm_genpd_restore;
1402 genpd->domain.ops.complete = pm_genpd_complete; 1444 genpd->domain.ops.complete = pm_genpd_complete;
1445 genpd->dev_ops.save_state = pm_genpd_default_save_state;
1446 genpd->dev_ops.restore_state = pm_genpd_default_restore_state;
1403 mutex_lock(&gpd_list_lock); 1447 mutex_lock(&gpd_list_lock);
1404 list_add(&genpd->gpd_list_node, &gpd_list); 1448 list_add(&genpd->gpd_list_node, &gpd_list);
1405 mutex_unlock(&gpd_list_lock); 1449 mutex_unlock(&gpd_list_lock);