aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/power
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2011-11-27 07:11:36 -0500
committerRafael J. Wysocki <rjw@sisk.pl>2011-12-01 15:47:08 -0500
commitd5e4cbfe2049fca375cb19c4bc0cf676e8b4a88a (patch)
tree51dfa4b178a53e884d310faad496aed07eee565b /drivers/base/power
parentb930c26416c4ea6855726fd977145ccea9afbdda (diff)
PM / Domains: Make it possible to use per-device domain callbacks
The current generic PM domains code requires that the same .stop(), .start() and .active_wakeup() device callback routines be used for all devices in the given domain, which is inflexible and may not cover some specific use cases. For this reason, make it possible to use device specific .start()/.stop() and .active_wakeup() callback routines by adding corresponding callback pointers to struct generic_pm_domain_data. Add a new helper routine, pm_genpd_register_callbacks(), that can be used to populate the new per-device callback pointers. Modify the shmobile's power domains code to allow drivers to add their own code to be run during the device stop and start operations with the help of the new callback pointers. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Acked-by: Magnus Damm <damm@opensource.se>
Diffstat (limited to 'drivers/base/power')
-rw-r--r--drivers/base/power/domain.c152
1 files changed, 115 insertions, 37 deletions
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 6790cf7eba5a..94afaa2686a6 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -15,6 +15,23 @@
15#include <linux/err.h> 15#include <linux/err.h>
16#include <linux/sched.h> 16#include <linux/sched.h>
17#include <linux/suspend.h> 17#include <linux/suspend.h>
18#include <linux/export.h>
19
20#define GENPD_DEV_CALLBACK(genpd, type, callback, dev) \
21({ \
22 type (*__routine)(struct device *__d); \
23 type __ret = (type)0; \
24 \
25 __routine = genpd->dev_ops.callback; \
26 if (__routine) { \
27 __ret = __routine(dev); \
28 } else { \
29 __routine = dev_gpd_data(dev)->ops.callback; \
30 if (__routine) \
31 __ret = __routine(dev); \
32 } \
33 __ret; \
34})
18 35
19static LIST_HEAD(gpd_list); 36static LIST_HEAD(gpd_list);
20static DEFINE_MUTEX(gpd_list_lock); 37static DEFINE_MUTEX(gpd_list_lock);
@@ -29,6 +46,16 @@ static struct generic_pm_domain *dev_to_genpd(struct device *dev)
29 return pd_to_genpd(dev->pm_domain); 46 return pd_to_genpd(dev->pm_domain);
30} 47}
31 48
49static int genpd_stop_dev(struct generic_pm_domain *genpd, struct device *dev)
50{
51 return GENPD_DEV_CALLBACK(genpd, int, stop, dev);
52}
53
54static int genpd_start_dev(struct generic_pm_domain *genpd, struct device *dev)
55{
56 return GENPD_DEV_CALLBACK(genpd, int, start, dev);
57}
58
32static bool genpd_sd_counter_dec(struct generic_pm_domain *genpd) 59static bool genpd_sd_counter_dec(struct generic_pm_domain *genpd)
33{ 60{
34 bool ret = false; 61 bool ret = false;
@@ -199,13 +226,9 @@ static int __pm_genpd_save_device(struct pm_domain_data *pdd,
199 mutex_unlock(&genpd->lock); 226 mutex_unlock(&genpd->lock);
200 227
201 if (drv && drv->pm && drv->pm->runtime_suspend) { 228 if (drv && drv->pm && drv->pm->runtime_suspend) {
202 if (genpd->start_device) 229 genpd_start_dev(genpd, dev);
203 genpd->start_device(dev);
204
205 ret = drv->pm->runtime_suspend(dev); 230 ret = drv->pm->runtime_suspend(dev);
206 231 genpd_stop_dev(genpd, dev);
207 if (genpd->stop_device)
208 genpd->stop_device(dev);
209 } 232 }
210 233
211 mutex_lock(&genpd->lock); 234 mutex_lock(&genpd->lock);
@@ -235,13 +258,9 @@ static void __pm_genpd_restore_device(struct pm_domain_data *pdd,
235 mutex_unlock(&genpd->lock); 258 mutex_unlock(&genpd->lock);
236 259
237 if (drv && drv->pm && drv->pm->runtime_resume) { 260 if (drv && drv->pm && drv->pm->runtime_resume) {
238 if (genpd->start_device) 261 genpd_start_dev(genpd, dev);
239 genpd->start_device(dev);
240
241 drv->pm->runtime_resume(dev); 262 drv->pm->runtime_resume(dev);
242 263 genpd_stop_dev(genpd, dev);
243 if (genpd->stop_device)
244 genpd->stop_device(dev);
245 } 264 }
246 265
247 mutex_lock(&genpd->lock); 266 mutex_lock(&genpd->lock);
@@ -413,6 +432,7 @@ static void genpd_power_off_work_fn(struct work_struct *work)
413static int pm_genpd_runtime_suspend(struct device *dev) 432static int pm_genpd_runtime_suspend(struct device *dev)
414{ 433{
415 struct generic_pm_domain *genpd; 434 struct generic_pm_domain *genpd;
435 int ret;
416 436
417 dev_dbg(dev, "%s()\n", __func__); 437 dev_dbg(dev, "%s()\n", __func__);
418 438
@@ -422,11 +442,9 @@ static int pm_genpd_runtime_suspend(struct device *dev)
422 442
423 might_sleep_if(!genpd->dev_irq_safe); 443 might_sleep_if(!genpd->dev_irq_safe);
424 444
425 if (genpd->stop_device) { 445 ret = genpd_stop_dev(genpd, dev);
426 int ret = genpd->stop_device(dev); 446 if (ret)
427 if (ret) 447 return ret;
428 return ret;
429 }
430 448
431 /* 449 /*
432 * If power.irq_safe is set, this routine will be run with interrupts 450 * If power.irq_safe is set, this routine will be run with interrupts
@@ -502,8 +520,7 @@ static int pm_genpd_runtime_resume(struct device *dev)
502 mutex_unlock(&genpd->lock); 520 mutex_unlock(&genpd->lock);
503 521
504 out: 522 out:
505 if (genpd->start_device) 523 genpd_start_dev(genpd, dev);
506 genpd->start_device(dev);
507 524
508 return 0; 525 return 0;
509} 526}
@@ -534,6 +551,12 @@ static inline void genpd_power_off_work_fn(struct work_struct *work) {}
534 551
535#ifdef CONFIG_PM_SLEEP 552#ifdef CONFIG_PM_SLEEP
536 553
554static bool genpd_dev_active_wakeup(struct generic_pm_domain *genpd,
555 struct device *dev)
556{
557 return GENPD_DEV_CALLBACK(genpd, bool, active_wakeup, dev);
558}
559
537/** 560/**
538 * pm_genpd_sync_poweroff - Synchronously power off a PM domain and its masters. 561 * pm_genpd_sync_poweroff - Synchronously power off a PM domain and its masters.
539 * @genpd: PM domain to power off, if possible. 562 * @genpd: PM domain to power off, if possible.
@@ -590,7 +613,7 @@ static bool resume_needed(struct device *dev, struct generic_pm_domain *genpd)
590 if (!device_can_wakeup(dev)) 613 if (!device_can_wakeup(dev))
591 return false; 614 return false;
592 615
593 active_wakeup = genpd->active_wakeup && genpd->active_wakeup(dev); 616 active_wakeup = genpd_dev_active_wakeup(genpd, dev);
594 return device_may_wakeup(dev) ? active_wakeup : !active_wakeup; 617 return device_may_wakeup(dev) ? active_wakeup : !active_wakeup;
595} 618}
596 619
@@ -646,7 +669,7 @@ static int pm_genpd_prepare(struct device *dev)
646 /* 669 /*
647 * The PM domain must be in the GPD_STATE_ACTIVE state at this point, 670 * The PM domain must be in the GPD_STATE_ACTIVE state at this point,
648 * so pm_genpd_poweron() will return immediately, but if the device 671 * so pm_genpd_poweron() will return immediately, but if the device
649 * is suspended (e.g. it's been stopped by .stop_device()), we need 672 * is suspended (e.g. it's been stopped by genpd_stop_dev()), we need
650 * to make it operational. 673 * to make it operational.
651 */ 674 */
652 pm_runtime_resume(dev); 675 pm_runtime_resume(dev);
@@ -714,12 +737,10 @@ static int pm_genpd_suspend_noirq(struct device *dev)
714 if (ret) 737 if (ret)
715 return ret; 738 return ret;
716 739
717 if (dev->power.wakeup_path 740 if (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))
718 && genpd->active_wakeup && genpd->active_wakeup(dev))
719 return 0; 741 return 0;
720 742
721 if (genpd->stop_device) 743 genpd_stop_dev(genpd, dev);
722 genpd->stop_device(dev);
723 744
724 /* 745 /*
725 * Since all of the "noirq" callbacks are executed sequentially, it is 746 * Since all of the "noirq" callbacks are executed sequentially, it is
@@ -761,8 +782,7 @@ static int pm_genpd_resume_noirq(struct device *dev)
761 */ 782 */
762 pm_genpd_poweron(genpd); 783 pm_genpd_poweron(genpd);
763 genpd->suspended_count--; 784 genpd->suspended_count--;
764 if (genpd->start_device) 785 genpd_start_dev(genpd, dev);
765 genpd->start_device(dev);
766 786
767 return pm_generic_resume_noirq(dev); 787 return pm_generic_resume_noirq(dev);
768} 788}
@@ -836,8 +856,7 @@ static int pm_genpd_freeze_noirq(struct device *dev)
836 if (ret) 856 if (ret)
837 return ret; 857 return ret;
838 858
839 if (genpd->stop_device) 859 genpd_stop_dev(genpd, dev);
840 genpd->stop_device(dev);
841 860
842 return 0; 861 return 0;
843} 862}
@@ -864,8 +883,7 @@ static int pm_genpd_thaw_noirq(struct device *dev)
864 if (genpd->suspend_power_off) 883 if (genpd->suspend_power_off)
865 return 0; 884 return 0;
866 885
867 if (genpd->start_device) 886 genpd_start_dev(genpd, dev);
868 genpd->start_device(dev);
869 887
870 return pm_generic_thaw_noirq(dev); 888 return pm_generic_thaw_noirq(dev);
871} 889}
@@ -938,12 +956,10 @@ static int pm_genpd_dev_poweroff_noirq(struct device *dev)
938 if (ret) 956 if (ret)
939 return ret; 957 return ret;
940 958
941 if (dev->power.wakeup_path 959 if (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))
942 && genpd->active_wakeup && genpd->active_wakeup(dev))
943 return 0; 960 return 0;
944 961
945 if (genpd->stop_device) 962 genpd_stop_dev(genpd, dev);
946 genpd->stop_device(dev);
947 963
948 /* 964 /*
949 * Since all of the "noirq" callbacks are executed sequentially, it is 965 * Since all of the "noirq" callbacks are executed sequentially, it is
@@ -993,8 +1009,7 @@ static int pm_genpd_restore_noirq(struct device *dev)
993 1009
994 pm_genpd_poweron(genpd); 1010 pm_genpd_poweron(genpd);
995 genpd->suspended_count--; 1011 genpd->suspended_count--;
996 if (genpd->start_device) 1012 genpd_start_dev(genpd, dev);
997 genpd->start_device(dev);
998 1013
999 return pm_generic_restore_noirq(dev); 1014 return pm_generic_restore_noirq(dev);
1000} 1015}
@@ -1280,6 +1295,69 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
1280} 1295}
1281 1296
1282/** 1297/**
1298 * pm_genpd_add_callbacks - Add PM domain callbacks to a given device.
1299 * @dev: Device to add the callbacks to.
1300 * @ops: Set of callbacks to add.
1301 */
1302int pm_genpd_add_callbacks(struct device *dev, struct gpd_dev_ops *ops)
1303{
1304 struct pm_domain_data *pdd;
1305 int ret = 0;
1306
1307 if (!(dev && dev->power.subsys_data && ops))
1308 return -EINVAL;
1309
1310 pm_runtime_disable(dev);
1311 device_pm_lock();
1312
1313 pdd = dev->power.subsys_data->domain_data;
1314 if (pdd) {
1315 struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd);
1316
1317 gpd_data->ops = *ops;
1318 } else {
1319 ret = -EINVAL;
1320 }
1321
1322 device_pm_unlock();
1323 pm_runtime_enable(dev);
1324
1325 return ret;
1326}
1327EXPORT_SYMBOL_GPL(pm_genpd_add_callbacks);
1328
1329/**
1330 * pm_genpd_remove_callbacks - Remove PM domain callbacks from a given device.
1331 * @dev: Device to remove the callbacks from.
1332 */
1333int pm_genpd_remove_callbacks(struct device *dev)
1334{
1335 struct pm_domain_data *pdd;
1336 int ret = 0;
1337
1338 if (!(dev && dev->power.subsys_data))
1339 return -EINVAL;
1340
1341 pm_runtime_disable(dev);
1342 device_pm_lock();
1343
1344 pdd = dev->power.subsys_data->domain_data;
1345 if (pdd) {
1346 struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd);
1347
1348 gpd_data->ops = (struct gpd_dev_ops){ 0 };
1349 } else {
1350 ret = -EINVAL;
1351 }
1352
1353 device_pm_unlock();
1354 pm_runtime_enable(dev);
1355
1356 return ret;
1357}
1358EXPORT_SYMBOL_GPL(pm_genpd_remove_callbacks);
1359
1360/**
1283 * pm_genpd_init - Initialize a generic I/O PM domain object. 1361 * pm_genpd_init - Initialize a generic I/O PM domain object.
1284 * @genpd: PM domain object to initialize. 1362 * @genpd: PM domain object to initialize.
1285 * @gov: PM domain governor to associate with the domain (may be NULL). 1363 * @gov: PM domain governor to associate with the domain (may be NULL).