diff options
author | Rafael J. Wysocki <rjw@sisk.pl> | 2012-09-17 14:25:18 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rjw@sisk.pl> | 2012-09-17 14:25:18 -0400 |
commit | 00e8b2613331042bbe0177e5b9bb5c8a654b14ae (patch) | |
tree | cfec260ba68b007ddd090c8f63c879b5bb58d2c4 /drivers/base | |
parent | 5698bd757d55b1bb87edd1a9744ab09c142abfc2 (diff) | |
parent | feb70af0e3ac6817327be70b47731039ea135dbc (diff) |
Merge branch 'pm-timers'
* pm-timers:
PM: Do not use the syscore flag for runtime PM
sh: MTU2: Basic runtime PM support
sh: CMT: Basic runtime PM support
sh: TMU: Basic runtime PM support
PM / Domains: Do not measure start time for "irq safe" devices
PM / Domains: Move syscore flag from subsys data to struct device
PM / Domains: Rename the always_on device flag to syscore
PM / Runtime: Allow helpers to be called by early platform drivers
PM: Reorganize device PM initialization
sh: MTU2: Introduce clock events suspend/resume routines
sh: CMT: Introduce clocksource/clock events suspend/resume routines
sh: TMU: Introduce clocksource/clock events suspend/resume routines
timekeeping: Add suspend and resume of clock event devices
PM / Domains: Add power off/on function for system core suspend stage
PM / Domains: Introduce simplified power on routine for system resume
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/platform.c | 2 | ||||
-rw-r--r-- | drivers/base/power/domain.c | 130 | ||||
-rw-r--r-- | drivers/base/power/main.c | 35 | ||||
-rw-r--r-- | drivers/base/power/power.h | 36 |
4 files changed, 152 insertions, 51 deletions
diff --git a/drivers/base/platform.c b/drivers/base/platform.c index a1a722502587..d51514b79efe 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/pm_runtime.h> | 22 | #include <linux/pm_runtime.h> |
23 | 23 | ||
24 | #include "base.h" | 24 | #include "base.h" |
25 | #include "power/power.h" | ||
25 | 26 | ||
26 | #define to_platform_driver(drv) (container_of((drv), struct platform_driver, \ | 27 | #define to_platform_driver(drv) (container_of((drv), struct platform_driver, \ |
27 | driver)) | 28 | driver)) |
@@ -948,6 +949,7 @@ void __init early_platform_add_devices(struct platform_device **devs, int num) | |||
948 | dev = &devs[i]->dev; | 949 | dev = &devs[i]->dev; |
949 | 950 | ||
950 | if (!dev->devres_head.next) { | 951 | if (!dev->devres_head.next) { |
952 | pm_runtime_early_init(dev); | ||
951 | INIT_LIST_HEAD(&dev->devres_head); | 953 | INIT_LIST_HEAD(&dev->devres_head); |
952 | list_add_tail(&dev->devres_head, | 954 | list_add_tail(&dev->devres_head, |
953 | &early_platform_device_list); | 955 | &early_platform_device_list); |
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index ba3487c9835b..5f4606f13be6 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c | |||
@@ -75,6 +75,12 @@ static int genpd_start_dev(struct generic_pm_domain *genpd, struct device *dev) | |||
75 | start_latency_ns, "start"); | 75 | start_latency_ns, "start"); |
76 | } | 76 | } |
77 | 77 | ||
78 | static int genpd_start_dev_no_timing(struct generic_pm_domain *genpd, | ||
79 | struct device *dev) | ||
80 | { | ||
81 | return GENPD_DEV_CALLBACK(genpd, int, start, dev); | ||
82 | } | ||
83 | |||
78 | static bool genpd_sd_counter_dec(struct generic_pm_domain *genpd) | 84 | static bool genpd_sd_counter_dec(struct generic_pm_domain *genpd) |
79 | { | 85 | { |
80 | bool ret = false; | 86 | bool ret = false; |
@@ -436,7 +442,7 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd) | |||
436 | not_suspended = 0; | 442 | not_suspended = 0; |
437 | list_for_each_entry(pdd, &genpd->dev_list, list_node) | 443 | list_for_each_entry(pdd, &genpd->dev_list, list_node) |
438 | if (pdd->dev->driver && (!pm_runtime_suspended(pdd->dev) | 444 | if (pdd->dev->driver && (!pm_runtime_suspended(pdd->dev) |
439 | || pdd->dev->power.irq_safe || to_gpd_data(pdd)->always_on)) | 445 | || pdd->dev->power.irq_safe)) |
440 | not_suspended++; | 446 | not_suspended++; |
441 | 447 | ||
442 | if (not_suspended > genpd->in_progress) | 448 | if (not_suspended > genpd->in_progress) |
@@ -578,9 +584,6 @@ static int pm_genpd_runtime_suspend(struct device *dev) | |||
578 | 584 | ||
579 | might_sleep_if(!genpd->dev_irq_safe); | 585 | might_sleep_if(!genpd->dev_irq_safe); |
580 | 586 | ||
581 | if (dev_gpd_data(dev)->always_on) | ||
582 | return -EBUSY; | ||
583 | |||
584 | stop_ok = genpd->gov ? genpd->gov->stop_ok : NULL; | 587 | stop_ok = genpd->gov ? genpd->gov->stop_ok : NULL; |
585 | if (stop_ok && !stop_ok(dev)) | 588 | if (stop_ok && !stop_ok(dev)) |
586 | return -EBUSY; | 589 | return -EBUSY; |
@@ -629,7 +632,7 @@ static int pm_genpd_runtime_resume(struct device *dev) | |||
629 | 632 | ||
630 | /* If power.irq_safe, the PM domain is never powered off. */ | 633 | /* If power.irq_safe, the PM domain is never powered off. */ |
631 | if (dev->power.irq_safe) | 634 | if (dev->power.irq_safe) |
632 | return genpd_start_dev(genpd, dev); | 635 | return genpd_start_dev_no_timing(genpd, dev); |
633 | 636 | ||
634 | mutex_lock(&genpd->lock); | 637 | mutex_lock(&genpd->lock); |
635 | ret = __pm_genpd_poweron(genpd); | 638 | ret = __pm_genpd_poweron(genpd); |
@@ -697,6 +700,24 @@ static inline void genpd_power_off_work_fn(struct work_struct *work) {} | |||
697 | 700 | ||
698 | #ifdef CONFIG_PM_SLEEP | 701 | #ifdef CONFIG_PM_SLEEP |
699 | 702 | ||
703 | /** | ||
704 | * pm_genpd_present - Check if the given PM domain has been initialized. | ||
705 | * @genpd: PM domain to check. | ||
706 | */ | ||
707 | static bool pm_genpd_present(struct generic_pm_domain *genpd) | ||
708 | { | ||
709 | struct generic_pm_domain *gpd; | ||
710 | |||
711 | if (IS_ERR_OR_NULL(genpd)) | ||
712 | return false; | ||
713 | |||
714 | list_for_each_entry(gpd, &gpd_list, gpd_list_node) | ||
715 | if (gpd == genpd) | ||
716 | return true; | ||
717 | |||
718 | return false; | ||
719 | } | ||
720 | |||
700 | static bool genpd_dev_active_wakeup(struct generic_pm_domain *genpd, | 721 | static bool genpd_dev_active_wakeup(struct generic_pm_domain *genpd, |
701 | struct device *dev) | 722 | struct device *dev) |
702 | { | 723 | { |
@@ -750,9 +771,10 @@ static int genpd_thaw_dev(struct generic_pm_domain *genpd, struct device *dev) | |||
750 | * Check if the given PM domain can be powered off (during system suspend or | 771 | * Check if the given PM domain can be powered off (during system suspend or |
751 | * hibernation) and do that if so. Also, in that case propagate to its masters. | 772 | * hibernation) and do that if so. Also, in that case propagate to its masters. |
752 | * | 773 | * |
753 | * This function is only called in "noirq" stages of system power transitions, | 774 | * This function is only called in "noirq" and "syscore" stages of system power |
754 | * so it need not acquire locks (all of the "noirq" callbacks are executed | 775 | * transitions, so it need not acquire locks (all of the "noirq" callbacks are |
755 | * sequentially, so it is guaranteed that it will never run twice in parallel). | 776 | * executed sequentially, so it is guaranteed that it will never run twice in |
777 | * parallel). | ||
756 | */ | 778 | */ |
757 | static void pm_genpd_sync_poweroff(struct generic_pm_domain *genpd) | 779 | static void pm_genpd_sync_poweroff(struct generic_pm_domain *genpd) |
758 | { | 780 | { |
@@ -777,6 +799,33 @@ static void pm_genpd_sync_poweroff(struct generic_pm_domain *genpd) | |||
777 | } | 799 | } |
778 | 800 | ||
779 | /** | 801 | /** |
802 | * pm_genpd_sync_poweron - Synchronously power on a PM domain and its masters. | ||
803 | * @genpd: PM domain to power on. | ||
804 | * | ||
805 | * This function is only called in "noirq" and "syscore" stages of system power | ||
806 | * transitions, so it need not acquire locks (all of the "noirq" callbacks are | ||
807 | * executed sequentially, so it is guaranteed that it will never run twice in | ||
808 | * parallel). | ||
809 | */ | ||
810 | static void pm_genpd_sync_poweron(struct generic_pm_domain *genpd) | ||
811 | { | ||
812 | struct gpd_link *link; | ||
813 | |||
814 | if (genpd->status != GPD_STATE_POWER_OFF) | ||
815 | return; | ||
816 | |||
817 | list_for_each_entry(link, &genpd->slave_links, slave_node) { | ||
818 | pm_genpd_sync_poweron(link->master); | ||
819 | genpd_sd_counter_inc(link->master); | ||
820 | } | ||
821 | |||
822 | if (genpd->power_on) | ||
823 | genpd->power_on(genpd); | ||
824 | |||
825 | genpd->status = GPD_STATE_ACTIVE; | ||
826 | } | ||
827 | |||
828 | /** | ||
780 | * resume_needed - Check whether to resume a device before system suspend. | 829 | * resume_needed - Check whether to resume a device before system suspend. |
781 | * @dev: Device to check. | 830 | * @dev: Device to check. |
782 | * @genpd: PM domain the device belongs to. | 831 | * @genpd: PM domain the device belongs to. |
@@ -937,7 +986,7 @@ static int pm_genpd_suspend_noirq(struct device *dev) | |||
937 | if (IS_ERR(genpd)) | 986 | if (IS_ERR(genpd)) |
938 | return -EINVAL; | 987 | return -EINVAL; |
939 | 988 | ||
940 | if (genpd->suspend_power_off || dev_gpd_data(dev)->always_on | 989 | if (genpd->suspend_power_off |
941 | || (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))) | 990 | || (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))) |
942 | return 0; | 991 | return 0; |
943 | 992 | ||
@@ -970,7 +1019,7 @@ static int pm_genpd_resume_noirq(struct device *dev) | |||
970 | if (IS_ERR(genpd)) | 1019 | if (IS_ERR(genpd)) |
971 | return -EINVAL; | 1020 | return -EINVAL; |
972 | 1021 | ||
973 | if (genpd->suspend_power_off || dev_gpd_data(dev)->always_on | 1022 | if (genpd->suspend_power_off |
974 | || (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))) | 1023 | || (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))) |
975 | return 0; | 1024 | return 0; |
976 | 1025 | ||
@@ -979,7 +1028,7 @@ static int pm_genpd_resume_noirq(struct device *dev) | |||
979 | * guaranteed that this function will never run twice in parallel for | 1028 | * guaranteed that this function will never run twice in parallel for |
980 | * the same PM domain, so it is not necessary to use locking here. | 1029 | * the same PM domain, so it is not necessary to use locking here. |
981 | */ | 1030 | */ |
982 | pm_genpd_poweron(genpd); | 1031 | pm_genpd_sync_poweron(genpd); |
983 | genpd->suspended_count--; | 1032 | genpd->suspended_count--; |
984 | 1033 | ||
985 | return genpd_start_dev(genpd, dev); | 1034 | return genpd_start_dev(genpd, dev); |
@@ -1090,8 +1139,7 @@ static int pm_genpd_freeze_noirq(struct device *dev) | |||
1090 | if (IS_ERR(genpd)) | 1139 | if (IS_ERR(genpd)) |
1091 | return -EINVAL; | 1140 | return -EINVAL; |
1092 | 1141 | ||
1093 | return genpd->suspend_power_off || dev_gpd_data(dev)->always_on ? | 1142 | return genpd->suspend_power_off ? 0 : genpd_stop_dev(genpd, dev); |
1094 | 0 : genpd_stop_dev(genpd, dev); | ||
1095 | } | 1143 | } |
1096 | 1144 | ||
1097 | /** | 1145 | /** |
@@ -1111,8 +1159,7 @@ static int pm_genpd_thaw_noirq(struct device *dev) | |||
1111 | if (IS_ERR(genpd)) | 1159 | if (IS_ERR(genpd)) |
1112 | return -EINVAL; | 1160 | return -EINVAL; |
1113 | 1161 | ||
1114 | return genpd->suspend_power_off || dev_gpd_data(dev)->always_on ? | 1162 | return genpd->suspend_power_off ? 0 : genpd_start_dev(genpd, dev); |
1115 | 0 : genpd_start_dev(genpd, dev); | ||
1116 | } | 1163 | } |
1117 | 1164 | ||
1118 | /** | 1165 | /** |
@@ -1186,8 +1233,8 @@ static int pm_genpd_restore_noirq(struct device *dev) | |||
1186 | if (genpd->suspended_count++ == 0) { | 1233 | if (genpd->suspended_count++ == 0) { |
1187 | /* | 1234 | /* |
1188 | * The boot kernel might put the domain into arbitrary state, | 1235 | * The boot kernel might put the domain into arbitrary state, |
1189 | * so make it appear as powered off to pm_genpd_poweron(), so | 1236 | * so make it appear as powered off to pm_genpd_sync_poweron(), |
1190 | * that it tries to power it on in case it was really off. | 1237 | * so that it tries to power it on in case it was really off. |
1191 | */ | 1238 | */ |
1192 | genpd->status = GPD_STATE_POWER_OFF; | 1239 | genpd->status = GPD_STATE_POWER_OFF; |
1193 | if (genpd->suspend_power_off) { | 1240 | if (genpd->suspend_power_off) { |
@@ -1205,9 +1252,9 @@ static int pm_genpd_restore_noirq(struct device *dev) | |||
1205 | if (genpd->suspend_power_off) | 1252 | if (genpd->suspend_power_off) |
1206 | return 0; | 1253 | return 0; |
1207 | 1254 | ||
1208 | pm_genpd_poweron(genpd); | 1255 | pm_genpd_sync_poweron(genpd); |
1209 | 1256 | ||
1210 | return dev_gpd_data(dev)->always_on ? 0 : genpd_start_dev(genpd, dev); | 1257 | return genpd_start_dev(genpd, dev); |
1211 | } | 1258 | } |
1212 | 1259 | ||
1213 | /** | 1260 | /** |
@@ -1246,6 +1293,31 @@ static void pm_genpd_complete(struct device *dev) | |||
1246 | } | 1293 | } |
1247 | } | 1294 | } |
1248 | 1295 | ||
1296 | /** | ||
1297 | * pm_genpd_syscore_switch - Switch power during system core suspend or resume. | ||
1298 | * @dev: Device that normally is marked as "always on" to switch power for. | ||
1299 | * | ||
1300 | * This routine may only be called during the system core (syscore) suspend or | ||
1301 | * resume phase for devices whose "always on" flags are set. | ||
1302 | */ | ||
1303 | void pm_genpd_syscore_switch(struct device *dev, bool suspend) | ||
1304 | { | ||
1305 | struct generic_pm_domain *genpd; | ||
1306 | |||
1307 | genpd = dev_to_genpd(dev); | ||
1308 | if (!pm_genpd_present(genpd)) | ||
1309 | return; | ||
1310 | |||
1311 | if (suspend) { | ||
1312 | genpd->suspended_count++; | ||
1313 | pm_genpd_sync_poweroff(genpd); | ||
1314 | } else { | ||
1315 | pm_genpd_sync_poweron(genpd); | ||
1316 | genpd->suspended_count--; | ||
1317 | } | ||
1318 | } | ||
1319 | EXPORT_SYMBOL_GPL(pm_genpd_syscore_switch); | ||
1320 | |||
1249 | #else | 1321 | #else |
1250 | 1322 | ||
1251 | #define pm_genpd_prepare NULL | 1323 | #define pm_genpd_prepare NULL |
@@ -1455,26 +1527,6 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd, | |||
1455 | } | 1527 | } |
1456 | 1528 | ||
1457 | /** | 1529 | /** |
1458 | * pm_genpd_dev_always_on - Set/unset the "always on" flag for a given device. | ||
1459 | * @dev: Device to set/unset the flag for. | ||
1460 | * @val: The new value of the device's "always on" flag. | ||
1461 | */ | ||
1462 | void pm_genpd_dev_always_on(struct device *dev, bool val) | ||
1463 | { | ||
1464 | struct pm_subsys_data *psd; | ||
1465 | unsigned long flags; | ||
1466 | |||
1467 | spin_lock_irqsave(&dev->power.lock, flags); | ||
1468 | |||
1469 | psd = dev_to_psd(dev); | ||
1470 | if (psd && psd->domain_data) | ||
1471 | to_gpd_data(psd->domain_data)->always_on = val; | ||
1472 | |||
1473 | spin_unlock_irqrestore(&dev->power.lock, flags); | ||
1474 | } | ||
1475 | EXPORT_SYMBOL_GPL(pm_genpd_dev_always_on); | ||
1476 | |||
1477 | /** | ||
1478 | * pm_genpd_dev_need_restore - Set/unset the device's "need restore" flag. | 1530 | * pm_genpd_dev_need_restore - Set/unset the device's "need restore" flag. |
1479 | * @dev: Device to set/unset the flag for. | 1531 | * @dev: Device to set/unset the flag for. |
1480 | * @val: The new value of the device's "need restore" flag. | 1532 | * @val: The new value of the device's "need restore" flag. |
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 0113adc310dc..57f5814c2732 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c | |||
@@ -57,20 +57,17 @@ static pm_message_t pm_transition; | |||
57 | static int async_error; | 57 | static int async_error; |
58 | 58 | ||
59 | /** | 59 | /** |
60 | * device_pm_init - Initialize the PM-related part of a device object. | 60 | * device_pm_sleep_init - Initialize system suspend-related device fields. |
61 | * @dev: Device object being initialized. | 61 | * @dev: Device object being initialized. |
62 | */ | 62 | */ |
63 | void device_pm_init(struct device *dev) | 63 | void device_pm_sleep_init(struct device *dev) |
64 | { | 64 | { |
65 | dev->power.is_prepared = false; | 65 | dev->power.is_prepared = false; |
66 | dev->power.is_suspended = false; | 66 | dev->power.is_suspended = false; |
67 | init_completion(&dev->power.completion); | 67 | init_completion(&dev->power.completion); |
68 | complete_all(&dev->power.completion); | 68 | complete_all(&dev->power.completion); |
69 | dev->power.wakeup = NULL; | 69 | dev->power.wakeup = NULL; |
70 | spin_lock_init(&dev->power.lock); | ||
71 | pm_runtime_init(dev); | ||
72 | INIT_LIST_HEAD(&dev->power.entry); | 70 | INIT_LIST_HEAD(&dev->power.entry); |
73 | dev->power.power_state = PMSG_INVALID; | ||
74 | } | 71 | } |
75 | 72 | ||
76 | /** | 73 | /** |
@@ -408,6 +405,9 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) | |||
408 | TRACE_DEVICE(dev); | 405 | TRACE_DEVICE(dev); |
409 | TRACE_RESUME(0); | 406 | TRACE_RESUME(0); |
410 | 407 | ||
408 | if (dev->power.syscore) | ||
409 | goto Out; | ||
410 | |||
411 | if (dev->pm_domain) { | 411 | if (dev->pm_domain) { |
412 | info = "noirq power domain "; | 412 | info = "noirq power domain "; |
413 | callback = pm_noirq_op(&dev->pm_domain->ops, state); | 413 | callback = pm_noirq_op(&dev->pm_domain->ops, state); |
@@ -429,6 +429,7 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) | |||
429 | 429 | ||
430 | error = dpm_run_callback(callback, dev, state, info); | 430 | error = dpm_run_callback(callback, dev, state, info); |
431 | 431 | ||
432 | Out: | ||
432 | TRACE_RESUME(error); | 433 | TRACE_RESUME(error); |
433 | return error; | 434 | return error; |
434 | } | 435 | } |
@@ -486,6 +487,9 @@ static int device_resume_early(struct device *dev, pm_message_t state) | |||
486 | TRACE_DEVICE(dev); | 487 | TRACE_DEVICE(dev); |
487 | TRACE_RESUME(0); | 488 | TRACE_RESUME(0); |
488 | 489 | ||
490 | if (dev->power.syscore) | ||
491 | goto Out; | ||
492 | |||
489 | if (dev->pm_domain) { | 493 | if (dev->pm_domain) { |
490 | info = "early power domain "; | 494 | info = "early power domain "; |
491 | callback = pm_late_early_op(&dev->pm_domain->ops, state); | 495 | callback = pm_late_early_op(&dev->pm_domain->ops, state); |
@@ -507,6 +511,7 @@ static int device_resume_early(struct device *dev, pm_message_t state) | |||
507 | 511 | ||
508 | error = dpm_run_callback(callback, dev, state, info); | 512 | error = dpm_run_callback(callback, dev, state, info); |
509 | 513 | ||
514 | Out: | ||
510 | TRACE_RESUME(error); | 515 | TRACE_RESUME(error); |
511 | return error; | 516 | return error; |
512 | } | 517 | } |
@@ -570,6 +575,9 @@ static int device_resume(struct device *dev, pm_message_t state, bool async) | |||
570 | TRACE_DEVICE(dev); | 575 | TRACE_DEVICE(dev); |
571 | TRACE_RESUME(0); | 576 | TRACE_RESUME(0); |
572 | 577 | ||
578 | if (dev->power.syscore) | ||
579 | goto Complete; | ||
580 | |||
573 | dpm_wait(dev->parent, async); | 581 | dpm_wait(dev->parent, async); |
574 | device_lock(dev); | 582 | device_lock(dev); |
575 | 583 | ||
@@ -632,6 +640,8 @@ static int device_resume(struct device *dev, pm_message_t state, bool async) | |||
632 | 640 | ||
633 | Unlock: | 641 | Unlock: |
634 | device_unlock(dev); | 642 | device_unlock(dev); |
643 | |||
644 | Complete: | ||
635 | complete_all(&dev->power.completion); | 645 | complete_all(&dev->power.completion); |
636 | 646 | ||
637 | TRACE_RESUME(error); | 647 | TRACE_RESUME(error); |
@@ -722,6 +732,9 @@ static void device_complete(struct device *dev, pm_message_t state) | |||
722 | void (*callback)(struct device *) = NULL; | 732 | void (*callback)(struct device *) = NULL; |
723 | char *info = NULL; | 733 | char *info = NULL; |
724 | 734 | ||
735 | if (dev->power.syscore) | ||
736 | return; | ||
737 | |||
725 | device_lock(dev); | 738 | device_lock(dev); |
726 | 739 | ||
727 | if (dev->pm_domain) { | 740 | if (dev->pm_domain) { |
@@ -834,6 +847,9 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state) | |||
834 | pm_callback_t callback = NULL; | 847 | pm_callback_t callback = NULL; |
835 | char *info = NULL; | 848 | char *info = NULL; |
836 | 849 | ||
850 | if (dev->power.syscore) | ||
851 | return 0; | ||
852 | |||
837 | if (dev->pm_domain) { | 853 | if (dev->pm_domain) { |
838 | info = "noirq power domain "; | 854 | info = "noirq power domain "; |
839 | callback = pm_noirq_op(&dev->pm_domain->ops, state); | 855 | callback = pm_noirq_op(&dev->pm_domain->ops, state); |
@@ -917,6 +933,9 @@ static int device_suspend_late(struct device *dev, pm_message_t state) | |||
917 | pm_callback_t callback = NULL; | 933 | pm_callback_t callback = NULL; |
918 | char *info = NULL; | 934 | char *info = NULL; |
919 | 935 | ||
936 | if (dev->power.syscore) | ||
937 | return 0; | ||
938 | |||
920 | if (dev->pm_domain) { | 939 | if (dev->pm_domain) { |
921 | info = "late power domain "; | 940 | info = "late power domain "; |
922 | callback = pm_late_early_op(&dev->pm_domain->ops, state); | 941 | callback = pm_late_early_op(&dev->pm_domain->ops, state); |
@@ -1053,6 +1072,9 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) | |||
1053 | goto Complete; | 1072 | goto Complete; |
1054 | } | 1073 | } |
1055 | 1074 | ||
1075 | if (dev->power.syscore) | ||
1076 | goto Complete; | ||
1077 | |||
1056 | device_lock(dev); | 1078 | device_lock(dev); |
1057 | 1079 | ||
1058 | if (dev->pm_domain) { | 1080 | if (dev->pm_domain) { |
@@ -1209,6 +1231,9 @@ static int device_prepare(struct device *dev, pm_message_t state) | |||
1209 | char *info = NULL; | 1231 | char *info = NULL; |
1210 | int error = 0; | 1232 | int error = 0; |
1211 | 1233 | ||
1234 | if (dev->power.syscore) | ||
1235 | return 0; | ||
1236 | |||
1212 | device_lock(dev); | 1237 | device_lock(dev); |
1213 | 1238 | ||
1214 | dev->power.wakeup_path = device_may_wakeup(dev); | 1239 | dev->power.wakeup_path = device_may_wakeup(dev); |
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index eeb4bff9505c..0dbfdf4419af 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h | |||
@@ -1,12 +1,32 @@ | |||
1 | #include <linux/pm_qos.h> | 1 | #include <linux/pm_qos.h> |
2 | 2 | ||
3 | static inline void device_pm_init_common(struct device *dev) | ||
4 | { | ||
5 | if (!dev->power.early_init) { | ||
6 | spin_lock_init(&dev->power.lock); | ||
7 | dev->power.power_state = PMSG_INVALID; | ||
8 | dev->power.early_init = true; | ||
9 | } | ||
10 | } | ||
11 | |||
3 | #ifdef CONFIG_PM_RUNTIME | 12 | #ifdef CONFIG_PM_RUNTIME |
4 | 13 | ||
14 | static inline void pm_runtime_early_init(struct device *dev) | ||
15 | { | ||
16 | dev->power.disable_depth = 1; | ||
17 | device_pm_init_common(dev); | ||
18 | } | ||
19 | |||
5 | extern void pm_runtime_init(struct device *dev); | 20 | extern void pm_runtime_init(struct device *dev); |
6 | extern void pm_runtime_remove(struct device *dev); | 21 | extern void pm_runtime_remove(struct device *dev); |
7 | 22 | ||
8 | #else /* !CONFIG_PM_RUNTIME */ | 23 | #else /* !CONFIG_PM_RUNTIME */ |
9 | 24 | ||
25 | static inline void pm_runtime_early_init(struct device *dev) | ||
26 | { | ||
27 | device_pm_init_common(dev); | ||
28 | } | ||
29 | |||
10 | static inline void pm_runtime_init(struct device *dev) {} | 30 | static inline void pm_runtime_init(struct device *dev) {} |
11 | static inline void pm_runtime_remove(struct device *dev) {} | 31 | static inline void pm_runtime_remove(struct device *dev) {} |
12 | 32 | ||
@@ -25,7 +45,7 @@ static inline struct device *to_device(struct list_head *entry) | |||
25 | return container_of(entry, struct device, power.entry); | 45 | return container_of(entry, struct device, power.entry); |
26 | } | 46 | } |
27 | 47 | ||
28 | extern void device_pm_init(struct device *dev); | 48 | extern void device_pm_sleep_init(struct device *dev); |
29 | extern void device_pm_add(struct device *); | 49 | extern void device_pm_add(struct device *); |
30 | extern void device_pm_remove(struct device *); | 50 | extern void device_pm_remove(struct device *); |
31 | extern void device_pm_move_before(struct device *, struct device *); | 51 | extern void device_pm_move_before(struct device *, struct device *); |
@@ -34,12 +54,7 @@ extern void device_pm_move_last(struct device *); | |||
34 | 54 | ||
35 | #else /* !CONFIG_PM_SLEEP */ | 55 | #else /* !CONFIG_PM_SLEEP */ |
36 | 56 | ||
37 | static inline void device_pm_init(struct device *dev) | 57 | static inline void device_pm_sleep_init(struct device *dev) {} |
38 | { | ||
39 | spin_lock_init(&dev->power.lock); | ||
40 | dev->power.power_state = PMSG_INVALID; | ||
41 | pm_runtime_init(dev); | ||
42 | } | ||
43 | 58 | ||
44 | static inline void device_pm_add(struct device *dev) | 59 | static inline void device_pm_add(struct device *dev) |
45 | { | 60 | { |
@@ -60,6 +75,13 @@ static inline void device_pm_move_last(struct device *dev) {} | |||
60 | 75 | ||
61 | #endif /* !CONFIG_PM_SLEEP */ | 76 | #endif /* !CONFIG_PM_SLEEP */ |
62 | 77 | ||
78 | static inline void device_pm_init(struct device *dev) | ||
79 | { | ||
80 | device_pm_init_common(dev); | ||
81 | device_pm_sleep_init(dev); | ||
82 | pm_runtime_init(dev); | ||
83 | } | ||
84 | |||
63 | #ifdef CONFIG_PM | 85 | #ifdef CONFIG_PM |
64 | 86 | ||
65 | /* | 87 | /* |