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 | |
| 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
| -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 | ||||
| -rw-r--r-- | drivers/clocksource/sh_cmt.c | 71 | ||||
| -rw-r--r-- | drivers/clocksource/sh_mtu2.c | 41 | ||||
| -rw-r--r-- | drivers/clocksource/sh_tmu.c | 112 | ||||
| -rw-r--r-- | include/linux/clockchips.h | 8 | ||||
| -rw-r--r-- | include/linux/device.h | 7 | ||||
| -rw-r--r-- | include/linux/pm.h | 2 | ||||
| -rw-r--r-- | include/linux/pm_domain.h | 19 | ||||
| -rw-r--r-- | kernel/power/Kconfig | 4 | ||||
| -rw-r--r-- | kernel/time/clockevents.c | 24 | ||||
| -rw-r--r-- | kernel/time/timekeeping.c | 2 |
14 files changed, 419 insertions, 74 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 | /* |
diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index 98b06baafcc6..a5f7829f2799 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c | |||
| @@ -33,6 +33,7 @@ | |||
| 33 | #include <linux/slab.h> | 33 | #include <linux/slab.h> |
| 34 | #include <linux/module.h> | 34 | #include <linux/module.h> |
| 35 | #include <linux/pm_domain.h> | 35 | #include <linux/pm_domain.h> |
| 36 | #include <linux/pm_runtime.h> | ||
| 36 | 37 | ||
| 37 | struct sh_cmt_priv { | 38 | struct sh_cmt_priv { |
| 38 | void __iomem *mapbase; | 39 | void __iomem *mapbase; |
| @@ -52,6 +53,7 @@ struct sh_cmt_priv { | |||
| 52 | struct clock_event_device ced; | 53 | struct clock_event_device ced; |
| 53 | struct clocksource cs; | 54 | struct clocksource cs; |
| 54 | unsigned long total_cycles; | 55 | unsigned long total_cycles; |
| 56 | bool cs_enabled; | ||
| 55 | }; | 57 | }; |
| 56 | 58 | ||
| 57 | static DEFINE_RAW_SPINLOCK(sh_cmt_lock); | 59 | static DEFINE_RAW_SPINLOCK(sh_cmt_lock); |
| @@ -155,6 +157,9 @@ static int sh_cmt_enable(struct sh_cmt_priv *p, unsigned long *rate) | |||
| 155 | { | 157 | { |
| 156 | int k, ret; | 158 | int k, ret; |
| 157 | 159 | ||
| 160 | pm_runtime_get_sync(&p->pdev->dev); | ||
| 161 | dev_pm_syscore_device(&p->pdev->dev, true); | ||
| 162 | |||
| 158 | /* enable clock */ | 163 | /* enable clock */ |
| 159 | ret = clk_enable(p->clk); | 164 | ret = clk_enable(p->clk); |
| 160 | if (ret) { | 165 | if (ret) { |
| @@ -221,6 +226,9 @@ static void sh_cmt_disable(struct sh_cmt_priv *p) | |||
| 221 | 226 | ||
| 222 | /* stop clock */ | 227 | /* stop clock */ |
| 223 | clk_disable(p->clk); | 228 | clk_disable(p->clk); |
| 229 | |||
| 230 | dev_pm_syscore_device(&p->pdev->dev, false); | ||
| 231 | pm_runtime_put(&p->pdev->dev); | ||
| 224 | } | 232 | } |
| 225 | 233 | ||
| 226 | /* private flags */ | 234 | /* private flags */ |
| @@ -451,22 +459,42 @@ static int sh_cmt_clocksource_enable(struct clocksource *cs) | |||
| 451 | int ret; | 459 | int ret; |
| 452 | struct sh_cmt_priv *p = cs_to_sh_cmt(cs); | 460 | struct sh_cmt_priv *p = cs_to_sh_cmt(cs); |
| 453 | 461 | ||
| 462 | WARN_ON(p->cs_enabled); | ||
| 463 | |||
| 454 | p->total_cycles = 0; | 464 | p->total_cycles = 0; |
| 455 | 465 | ||
| 456 | ret = sh_cmt_start(p, FLAG_CLOCKSOURCE); | 466 | ret = sh_cmt_start(p, FLAG_CLOCKSOURCE); |
| 457 | if (!ret) | 467 | if (!ret) { |
| 458 | __clocksource_updatefreq_hz(cs, p->rate); | 468 | __clocksource_updatefreq_hz(cs, p->rate); |
| 469 | p->cs_enabled = true; | ||
| 470 | } | ||
| 459 | return ret; | 471 | return ret; |
| 460 | } | 472 | } |
| 461 | 473 | ||
| 462 | static void sh_cmt_clocksource_disable(struct clocksource *cs) | 474 | static void sh_cmt_clocksource_disable(struct clocksource *cs) |
| 463 | { | 475 | { |
| 464 | sh_cmt_stop(cs_to_sh_cmt(cs), FLAG_CLOCKSOURCE); | 476 | struct sh_cmt_priv *p = cs_to_sh_cmt(cs); |
| 477 | |||
| 478 | WARN_ON(!p->cs_enabled); | ||
| 479 | |||
| 480 | sh_cmt_stop(p, FLAG_CLOCKSOURCE); | ||
| 481 | p->cs_enabled = false; | ||
| 482 | } | ||
| 483 | |||
| 484 | static void sh_cmt_clocksource_suspend(struct clocksource *cs) | ||
| 485 | { | ||
| 486 | struct sh_cmt_priv *p = cs_to_sh_cmt(cs); | ||
| 487 | |||
| 488 | sh_cmt_stop(p, FLAG_CLOCKSOURCE); | ||
| 489 | pm_genpd_syscore_poweroff(&p->pdev->dev); | ||
| 465 | } | 490 | } |
| 466 | 491 | ||
| 467 | static void sh_cmt_clocksource_resume(struct clocksource *cs) | 492 | static void sh_cmt_clocksource_resume(struct clocksource *cs) |
| 468 | { | 493 | { |
| 469 | sh_cmt_start(cs_to_sh_cmt(cs), FLAG_CLOCKSOURCE); | 494 | struct sh_cmt_priv *p = cs_to_sh_cmt(cs); |
| 495 | |||
| 496 | pm_genpd_syscore_poweron(&p->pdev->dev); | ||
| 497 | sh_cmt_start(p, FLAG_CLOCKSOURCE); | ||
| 470 | } | 498 | } |
| 471 | 499 | ||
| 472 | static int sh_cmt_register_clocksource(struct sh_cmt_priv *p, | 500 | static int sh_cmt_register_clocksource(struct sh_cmt_priv *p, |
| @@ -479,7 +507,7 @@ static int sh_cmt_register_clocksource(struct sh_cmt_priv *p, | |||
| 479 | cs->read = sh_cmt_clocksource_read; | 507 | cs->read = sh_cmt_clocksource_read; |
| 480 | cs->enable = sh_cmt_clocksource_enable; | 508 | cs->enable = sh_cmt_clocksource_enable; |
| 481 | cs->disable = sh_cmt_clocksource_disable; | 509 | cs->disable = sh_cmt_clocksource_disable; |
| 482 | cs->suspend = sh_cmt_clocksource_disable; | 510 | cs->suspend = sh_cmt_clocksource_suspend; |
| 483 | cs->resume = sh_cmt_clocksource_resume; | 511 | cs->resume = sh_cmt_clocksource_resume; |
| 484 | cs->mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8); | 512 | cs->mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8); |
| 485 | cs->flags = CLOCK_SOURCE_IS_CONTINUOUS; | 513 | cs->flags = CLOCK_SOURCE_IS_CONTINUOUS; |
| @@ -562,6 +590,16 @@ static int sh_cmt_clock_event_next(unsigned long delta, | |||
| 562 | return 0; | 590 | return 0; |
| 563 | } | 591 | } |
| 564 | 592 | ||
| 593 | static void sh_cmt_clock_event_suspend(struct clock_event_device *ced) | ||
| 594 | { | ||
| 595 | pm_genpd_syscore_poweroff(&ced_to_sh_cmt(ced)->pdev->dev); | ||
| 596 | } | ||
| 597 | |||
| 598 | static void sh_cmt_clock_event_resume(struct clock_event_device *ced) | ||
| 599 | { | ||
| 600 | pm_genpd_syscore_poweron(&ced_to_sh_cmt(ced)->pdev->dev); | ||
| 601 | } | ||
| 602 | |||
| 565 | static void sh_cmt_register_clockevent(struct sh_cmt_priv *p, | 603 | static void sh_cmt_register_clockevent(struct sh_cmt_priv *p, |
| 566 | char *name, unsigned long rating) | 604 | char *name, unsigned long rating) |
| 567 | { | 605 | { |
| @@ -576,6 +614,8 @@ static void sh_cmt_register_clockevent(struct sh_cmt_priv *p, | |||
| 576 | ced->cpumask = cpumask_of(0); | 614 | ced->cpumask = cpumask_of(0); |
| 577 | ced->set_next_event = sh_cmt_clock_event_next; | 615 | ced->set_next_event = sh_cmt_clock_event_next; |
| 578 | ced->set_mode = sh_cmt_clock_event_mode; | 616 | ced->set_mode = sh_cmt_clock_event_mode; |
| 617 | ced->suspend = sh_cmt_clock_event_suspend; | ||
| 618 | ced->resume = sh_cmt_clock_event_resume; | ||
| 579 | 619 | ||
| 580 | dev_info(&p->pdev->dev, "used for clock events\n"); | 620 | dev_info(&p->pdev->dev, "used for clock events\n"); |
| 581 | clockevents_register_device(ced); | 621 | clockevents_register_device(ced); |
| @@ -670,6 +710,7 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) | |||
| 670 | dev_err(&p->pdev->dev, "registration failed\n"); | 710 | dev_err(&p->pdev->dev, "registration failed\n"); |
| 671 | goto err1; | 711 | goto err1; |
| 672 | } | 712 | } |
| 713 | p->cs_enabled = false; | ||
| 673 | 714 | ||
| 674 | ret = setup_irq(irq, &p->irqaction); | 715 | ret = setup_irq(irq, &p->irqaction); |
| 675 | if (ret) { | 716 | if (ret) { |
| @@ -688,14 +729,17 @@ err0: | |||
| 688 | static int __devinit sh_cmt_probe(struct platform_device *pdev) | 729 | static int __devinit sh_cmt_probe(struct platform_device *pdev) |
| 689 | { | 730 | { |
| 690 | struct sh_cmt_priv *p = platform_get_drvdata(pdev); | 731 | struct sh_cmt_priv *p = platform_get_drvdata(pdev); |
| 732 | struct sh_timer_config *cfg = pdev->dev.platform_data; | ||
| 691 | int ret; | 733 | int ret; |
| 692 | 734 | ||
| 693 | if (!is_early_platform_device(pdev)) | 735 | if (!is_early_platform_device(pdev)) { |
| 694 | pm_genpd_dev_always_on(&pdev->dev, true); | 736 | pm_runtime_set_active(&pdev->dev); |
| 737 | pm_runtime_enable(&pdev->dev); | ||
| 738 | } | ||
| 695 | 739 | ||
| 696 | if (p) { | 740 | if (p) { |
| 697 | dev_info(&pdev->dev, "kept as earlytimer\n"); | 741 | dev_info(&pdev->dev, "kept as earlytimer\n"); |
| 698 | return 0; | 742 | goto out; |
| 699 | } | 743 | } |
| 700 | 744 | ||
| 701 | p = kmalloc(sizeof(*p), GFP_KERNEL); | 745 | p = kmalloc(sizeof(*p), GFP_KERNEL); |
| @@ -708,8 +752,19 @@ static int __devinit sh_cmt_probe(struct platform_device *pdev) | |||
| 708 | if (ret) { | 752 | if (ret) { |
| 709 | kfree(p); | 753 | kfree(p); |
| 710 | platform_set_drvdata(pdev, NULL); | 754 | platform_set_drvdata(pdev, NULL); |
| 755 | pm_runtime_idle(&pdev->dev); | ||
| 756 | return ret; | ||
| 711 | } | 757 | } |
| 712 | return ret; | 758 | if (is_early_platform_device(pdev)) |
| 759 | return 0; | ||
| 760 | |||
| 761 | out: | ||
| 762 | if (cfg->clockevent_rating || cfg->clocksource_rating) | ||
| 763 | pm_runtime_irq_safe(&pdev->dev); | ||
| 764 | else | ||
| 765 | pm_runtime_idle(&pdev->dev); | ||
| 766 | |||
| 767 | return 0; | ||
| 713 | } | 768 | } |
| 714 | 769 | ||
| 715 | static int __devexit sh_cmt_remove(struct platform_device *pdev) | 770 | static int __devexit sh_cmt_remove(struct platform_device *pdev) |
diff --git a/drivers/clocksource/sh_mtu2.c b/drivers/clocksource/sh_mtu2.c index d9b76ca64a61..c5eea858054a 100644 --- a/drivers/clocksource/sh_mtu2.c +++ b/drivers/clocksource/sh_mtu2.c | |||
| @@ -32,6 +32,7 @@ | |||
| 32 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
| 33 | #include <linux/module.h> | 33 | #include <linux/module.h> |
| 34 | #include <linux/pm_domain.h> | 34 | #include <linux/pm_domain.h> |
| 35 | #include <linux/pm_runtime.h> | ||
| 35 | 36 | ||
| 36 | struct sh_mtu2_priv { | 37 | struct sh_mtu2_priv { |
| 37 | void __iomem *mapbase; | 38 | void __iomem *mapbase; |
| @@ -123,6 +124,9 @@ static int sh_mtu2_enable(struct sh_mtu2_priv *p) | |||
| 123 | { | 124 | { |
| 124 | int ret; | 125 | int ret; |
| 125 | 126 | ||
| 127 | pm_runtime_get_sync(&p->pdev->dev); | ||
| 128 | dev_pm_syscore_device(&p->pdev->dev, true); | ||
| 129 | |||
| 126 | /* enable clock */ | 130 | /* enable clock */ |
| 127 | ret = clk_enable(p->clk); | 131 | ret = clk_enable(p->clk); |
| 128 | if (ret) { | 132 | if (ret) { |
| @@ -157,6 +161,9 @@ static void sh_mtu2_disable(struct sh_mtu2_priv *p) | |||
| 157 | 161 | ||
| 158 | /* stop clock */ | 162 | /* stop clock */ |
| 159 | clk_disable(p->clk); | 163 | clk_disable(p->clk); |
| 164 | |||
| 165 | dev_pm_syscore_device(&p->pdev->dev, false); | ||
| 166 | pm_runtime_put(&p->pdev->dev); | ||
| 160 | } | 167 | } |
| 161 | 168 | ||
| 162 | static irqreturn_t sh_mtu2_interrupt(int irq, void *dev_id) | 169 | static irqreturn_t sh_mtu2_interrupt(int irq, void *dev_id) |
| @@ -208,6 +215,16 @@ static void sh_mtu2_clock_event_mode(enum clock_event_mode mode, | |||
| 208 | } | 215 | } |
| 209 | } | 216 | } |
| 210 | 217 | ||
| 218 | static void sh_mtu2_clock_event_suspend(struct clock_event_device *ced) | ||
| 219 | { | ||
| 220 | pm_genpd_syscore_poweroff(&ced_to_sh_mtu2(ced)->pdev->dev); | ||
| 221 | } | ||
| 222 | |||
| 223 | static void sh_mtu2_clock_event_resume(struct clock_event_device *ced) | ||
| 224 | { | ||
| 225 | pm_genpd_syscore_poweron(&ced_to_sh_mtu2(ced)->pdev->dev); | ||
| 226 | } | ||
| 227 | |||
| 211 | static void sh_mtu2_register_clockevent(struct sh_mtu2_priv *p, | 228 | static void sh_mtu2_register_clockevent(struct sh_mtu2_priv *p, |
| 212 | char *name, unsigned long rating) | 229 | char *name, unsigned long rating) |
| 213 | { | 230 | { |
| @@ -221,6 +238,8 @@ static void sh_mtu2_register_clockevent(struct sh_mtu2_priv *p, | |||
| 221 | ced->rating = rating; | 238 | ced->rating = rating; |
| 222 | ced->cpumask = cpumask_of(0); | 239 | ced->cpumask = cpumask_of(0); |
| 223 | ced->set_mode = sh_mtu2_clock_event_mode; | 240 | ced->set_mode = sh_mtu2_clock_event_mode; |
| 241 | ced->suspend = sh_mtu2_clock_event_suspend; | ||
| 242 | ced->resume = sh_mtu2_clock_event_resume; | ||
| 224 | 243 | ||
| 225 | dev_info(&p->pdev->dev, "used for clock events\n"); | 244 | dev_info(&p->pdev->dev, "used for clock events\n"); |
| 226 | clockevents_register_device(ced); | 245 | clockevents_register_device(ced); |
| @@ -305,14 +324,17 @@ static int sh_mtu2_setup(struct sh_mtu2_priv *p, struct platform_device *pdev) | |||
| 305 | static int __devinit sh_mtu2_probe(struct platform_device *pdev) | 324 | static int __devinit sh_mtu2_probe(struct platform_device *pdev) |
| 306 | { | 325 | { |
| 307 | struct sh_mtu2_priv *p = platform_get_drvdata(pdev); | 326 | struct sh_mtu2_priv *p = platform_get_drvdata(pdev); |
| 327 | struct sh_timer_config *cfg = pdev->dev.platform_data; | ||
| 308 | int ret; | 328 | int ret; |
| 309 | 329 | ||
| 310 | if (!is_early_platform_device(pdev)) | 330 | if (!is_early_platform_device(pdev)) { |
| 311 | pm_genpd_dev_always_on(&pdev->dev, true); | 331 | pm_runtime_set_active(&pdev->dev); |
| 332 | pm_runtime_enable(&pdev->dev); | ||
| 333 | } | ||
| 312 | 334 | ||
| 313 | if (p) { | 335 | if (p) { |
| 314 | dev_info(&pdev->dev, "kept as earlytimer\n"); | 336 | dev_info(&pdev->dev, "kept as earlytimer\n"); |
| 315 | return 0; | 337 | goto out; |
| 316 | } | 338 | } |
| 317 | 339 | ||
| 318 | p = kmalloc(sizeof(*p), GFP_KERNEL); | 340 | p = kmalloc(sizeof(*p), GFP_KERNEL); |
| @@ -325,8 +347,19 @@ static int __devinit sh_mtu2_probe(struct platform_device *pdev) | |||
| 325 | if (ret) { | 347 | if (ret) { |
| 326 | kfree(p); | 348 | kfree(p); |
| 327 | platform_set_drvdata(pdev, NULL); | 349 | platform_set_drvdata(pdev, NULL); |
| 350 | pm_runtime_idle(&pdev->dev); | ||
| 351 | return ret; | ||
| 328 | } | 352 | } |
| 329 | return ret; | 353 | if (is_early_platform_device(pdev)) |
| 354 | return 0; | ||
| 355 | |||
| 356 | out: | ||
| 357 | if (cfg->clockevent_rating) | ||
| 358 | pm_runtime_irq_safe(&pdev->dev); | ||
| 359 | else | ||
| 360 | pm_runtime_idle(&pdev->dev); | ||
| 361 | |||
| 362 | return 0; | ||
| 330 | } | 363 | } |
| 331 | 364 | ||
| 332 | static int __devexit sh_mtu2_remove(struct platform_device *pdev) | 365 | static int __devexit sh_mtu2_remove(struct platform_device *pdev) |
diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c index c1b51d49d106..0cc4add88279 100644 --- a/drivers/clocksource/sh_tmu.c +++ b/drivers/clocksource/sh_tmu.c | |||
| @@ -33,6 +33,7 @@ | |||
| 33 | #include <linux/slab.h> | 33 | #include <linux/slab.h> |
| 34 | #include <linux/module.h> | 34 | #include <linux/module.h> |
| 35 | #include <linux/pm_domain.h> | 35 | #include <linux/pm_domain.h> |
| 36 | #include <linux/pm_runtime.h> | ||
| 36 | 37 | ||
| 37 | struct sh_tmu_priv { | 38 | struct sh_tmu_priv { |
| 38 | void __iomem *mapbase; | 39 | void __iomem *mapbase; |
| @@ -43,6 +44,8 @@ struct sh_tmu_priv { | |||
| 43 | unsigned long periodic; | 44 | unsigned long periodic; |
| 44 | struct clock_event_device ced; | 45 | struct clock_event_device ced; |
| 45 | struct clocksource cs; | 46 | struct clocksource cs; |
| 47 | bool cs_enabled; | ||
| 48 | unsigned int enable_count; | ||
| 46 | }; | 49 | }; |
| 47 | 50 | ||
| 48 | static DEFINE_RAW_SPINLOCK(sh_tmu_lock); | 51 | static DEFINE_RAW_SPINLOCK(sh_tmu_lock); |
| @@ -107,7 +110,7 @@ static void sh_tmu_start_stop_ch(struct sh_tmu_priv *p, int start) | |||
| 107 | raw_spin_unlock_irqrestore(&sh_tmu_lock, flags); | 110 | raw_spin_unlock_irqrestore(&sh_tmu_lock, flags); |
| 108 | } | 111 | } |
| 109 | 112 | ||
| 110 | static int sh_tmu_enable(struct sh_tmu_priv *p) | 113 | static int __sh_tmu_enable(struct sh_tmu_priv *p) |
| 111 | { | 114 | { |
| 112 | int ret; | 115 | int ret; |
| 113 | 116 | ||
| @@ -135,7 +138,18 @@ static int sh_tmu_enable(struct sh_tmu_priv *p) | |||
| 135 | return 0; | 138 | return 0; |
| 136 | } | 139 | } |
| 137 | 140 | ||
| 138 | static void sh_tmu_disable(struct sh_tmu_priv *p) | 141 | static int sh_tmu_enable(struct sh_tmu_priv *p) |
| 142 | { | ||
| 143 | if (p->enable_count++ > 0) | ||
| 144 | return 0; | ||
| 145 | |||
| 146 | pm_runtime_get_sync(&p->pdev->dev); | ||
| 147 | dev_pm_syscore_device(&p->pdev->dev, true); | ||
| 148 | |||
| 149 | return __sh_tmu_enable(p); | ||
| 150 | } | ||
| 151 | |||
| 152 | static void __sh_tmu_disable(struct sh_tmu_priv *p) | ||
| 139 | { | 153 | { |
| 140 | /* disable channel */ | 154 | /* disable channel */ |
| 141 | sh_tmu_start_stop_ch(p, 0); | 155 | sh_tmu_start_stop_ch(p, 0); |
| @@ -147,6 +161,20 @@ static void sh_tmu_disable(struct sh_tmu_priv *p) | |||
| 147 | clk_disable(p->clk); | 161 | clk_disable(p->clk); |
| 148 | } | 162 | } |
| 149 | 163 | ||
| 164 | static void sh_tmu_disable(struct sh_tmu_priv *p) | ||
| 165 | { | ||
| 166 | if (WARN_ON(p->enable_count == 0)) | ||
| 167 | return; | ||
| 168 | |||
| 169 | if (--p->enable_count > 0) | ||
| 170 | return; | ||
| 171 | |||
| 172 | __sh_tmu_disable(p); | ||
| 173 | |||
| 174 | dev_pm_syscore_device(&p->pdev->dev, false); | ||
| 175 | pm_runtime_put(&p->pdev->dev); | ||
| 176 | } | ||
| 177 | |||
| 150 | static void sh_tmu_set_next(struct sh_tmu_priv *p, unsigned long delta, | 178 | static void sh_tmu_set_next(struct sh_tmu_priv *p, unsigned long delta, |
| 151 | int periodic) | 179 | int periodic) |
| 152 | { | 180 | { |
| @@ -203,15 +231,53 @@ static int sh_tmu_clocksource_enable(struct clocksource *cs) | |||
| 203 | struct sh_tmu_priv *p = cs_to_sh_tmu(cs); | 231 | struct sh_tmu_priv *p = cs_to_sh_tmu(cs); |
| 204 | int ret; | 232 | int ret; |
| 205 | 233 | ||
| 234 | if (WARN_ON(p->cs_enabled)) | ||
| 235 | return 0; | ||
| 236 | |||
| 206 | ret = sh_tmu_enable(p); | 237 | ret = sh_tmu_enable(p); |
| 207 | if (!ret) | 238 | if (!ret) { |
| 208 | __clocksource_updatefreq_hz(cs, p->rate); | 239 | __clocksource_updatefreq_hz(cs, p->rate); |
| 240 | p->cs_enabled = true; | ||
| 241 | } | ||
| 242 | |||
| 209 | return ret; | 243 | return ret; |
| 210 | } | 244 | } |
| 211 | 245 | ||
| 212 | static void sh_tmu_clocksource_disable(struct clocksource *cs) | 246 | static void sh_tmu_clocksource_disable(struct clocksource *cs) |
| 213 | { | 247 | { |
| 214 | sh_tmu_disable(cs_to_sh_tmu(cs)); | 248 | struct sh_tmu_priv *p = cs_to_sh_tmu(cs); |
| 249 | |||
| 250 | if (WARN_ON(!p->cs_enabled)) | ||
| 251 | return; | ||
| 252 | |||
| 253 | sh_tmu_disable(p); | ||
| 254 | p->cs_enabled = false; | ||
| 255 | } | ||
| 256 | |||
| 257 | static void sh_tmu_clocksource_suspend(struct clocksource *cs) | ||
| 258 | { | ||
| 259 | struct sh_tmu_priv *p = cs_to_sh_tmu(cs); | ||
| 260 | |||
| 261 | if (!p->cs_enabled) | ||
| 262 | return; | ||
| 263 | |||
| 264 | if (--p->enable_count == 0) { | ||
| 265 | __sh_tmu_disable(p); | ||
| 266 | pm_genpd_syscore_poweroff(&p->pdev->dev); | ||
| 267 | } | ||
| 268 | } | ||
| 269 | |||
| 270 | static void sh_tmu_clocksource_resume(struct clocksource *cs) | ||
| 271 | { | ||
| 272 | struct sh_tmu_priv *p = cs_to_sh_tmu(cs); | ||
| 273 | |||
| 274 | if (!p->cs_enabled) | ||
| 275 | return; | ||
| 276 | |||
| 277 | if (p->enable_count++ == 0) { | ||
| 278 | pm_genpd_syscore_poweron(&p->pdev->dev); | ||
| 279 | __sh_tmu_enable(p); | ||
| 280 | } | ||
| 215 | } | 281 | } |
| 216 | 282 | ||
| 217 | static int sh_tmu_register_clocksource(struct sh_tmu_priv *p, | 283 | static int sh_tmu_register_clocksource(struct sh_tmu_priv *p, |
| @@ -224,6 +290,8 @@ static int sh_tmu_register_clocksource(struct sh_tmu_priv *p, | |||
| 224 | cs->read = sh_tmu_clocksource_read; | 290 | cs->read = sh_tmu_clocksource_read; |
| 225 | cs->enable = sh_tmu_clocksource_enable; | 291 | cs->enable = sh_tmu_clocksource_enable; |
| 226 | cs->disable = sh_tmu_clocksource_disable; | 292 | cs->disable = sh_tmu_clocksource_disable; |
| 293 | cs->suspend = sh_tmu_clocksource_suspend; | ||
| 294 | cs->resume = sh_tmu_clocksource_resume; | ||
| 227 | cs->mask = CLOCKSOURCE_MASK(32); | 295 | cs->mask = CLOCKSOURCE_MASK(32); |
| 228 | cs->flags = CLOCK_SOURCE_IS_CONTINUOUS; | 296 | cs->flags = CLOCK_SOURCE_IS_CONTINUOUS; |
| 229 | 297 | ||
| @@ -301,6 +369,16 @@ static int sh_tmu_clock_event_next(unsigned long delta, | |||
| 301 | return 0; | 369 | return 0; |
| 302 | } | 370 | } |
| 303 | 371 | ||
| 372 | static void sh_tmu_clock_event_suspend(struct clock_event_device *ced) | ||
| 373 | { | ||
| 374 | pm_genpd_syscore_poweroff(&ced_to_sh_tmu(ced)->pdev->dev); | ||
| 375 | } | ||
| 376 | |||
| 377 | static void sh_tmu_clock_event_resume(struct clock_event_device *ced) | ||
| 378 | { | ||
| 379 | pm_genpd_syscore_poweron(&ced_to_sh_tmu(ced)->pdev->dev); | ||
| 380 | } | ||
| 381 | |||
| 304 | static void sh_tmu_register_clockevent(struct sh_tmu_priv *p, | 382 | static void sh_tmu_register_clockevent(struct sh_tmu_priv *p, |
| 305 | char *name, unsigned long rating) | 383 | char *name, unsigned long rating) |
| 306 | { | 384 | { |
| @@ -316,6 +394,8 @@ static void sh_tmu_register_clockevent(struct sh_tmu_priv *p, | |||
| 316 | ced->cpumask = cpumask_of(0); | 394 | ced->cpumask = cpumask_of(0); |
| 317 | ced->set_next_event = sh_tmu_clock_event_next; | 395 | ced->set_next_event = sh_tmu_clock_event_next; |
| 318 | ced->set_mode = sh_tmu_clock_event_mode; | 396 | ced->set_mode = sh_tmu_clock_event_mode; |
| 397 | ced->suspend = sh_tmu_clock_event_suspend; | ||
| 398 | ced->resume = sh_tmu_clock_event_resume; | ||
| 319 | 399 | ||
| 320 | dev_info(&p->pdev->dev, "used for clock events\n"); | 400 | dev_info(&p->pdev->dev, "used for clock events\n"); |
| 321 | 401 | ||
| @@ -392,6 +472,8 @@ static int sh_tmu_setup(struct sh_tmu_priv *p, struct platform_device *pdev) | |||
| 392 | ret = PTR_ERR(p->clk); | 472 | ret = PTR_ERR(p->clk); |
| 393 | goto err1; | 473 | goto err1; |
| 394 | } | 474 | } |
| 475 | p->cs_enabled = false; | ||
| 476 | p->enable_count = 0; | ||
| 395 | 477 | ||
| 396 | return sh_tmu_register(p, (char *)dev_name(&p->pdev->dev), | 478 | return sh_tmu_register(p, (char *)dev_name(&p->pdev->dev), |
| 397 | cfg->clockevent_rating, | 479 | cfg->clockevent_rating, |
| @@ -405,14 +487,17 @@ static int sh_tmu_setup(struct sh_tmu_priv *p, struct platform_device *pdev) | |||
| 405 | static int __devinit sh_tmu_probe(struct platform_device *pdev) | 487 | static int __devinit sh_tmu_probe(struct platform_device *pdev) |
| 406 | { | 488 | { |
| 407 | struct sh_tmu_priv *p = platform_get_drvdata(pdev); | 489 | struct sh_tmu_priv *p = platform_get_drvdata(pdev); |
| 490 | struct sh_timer_config *cfg = pdev->dev.platform_data; | ||
| 408 | int ret; | 491 | int ret; |
| 409 | 492 | ||
| 410 | if (!is_early_platform_device(pdev)) | 493 | if (!is_early_platform_device(pdev)) { |
| 411 | pm_genpd_dev_always_on(&pdev->dev, true); | 494 | pm_runtime_set_active(&pdev->dev); |
| 495 | pm_runtime_enable(&pdev->dev); | ||
| 496 | } | ||
| 412 | 497 | ||
| 413 | if (p) { | 498 | if (p) { |
| 414 | dev_info(&pdev->dev, "kept as earlytimer\n"); | 499 | dev_info(&pdev->dev, "kept as earlytimer\n"); |
| 415 | return 0; | 500 | goto out; |
| 416 | } | 501 | } |
| 417 | 502 | ||
| 418 | p = kmalloc(sizeof(*p), GFP_KERNEL); | 503 | p = kmalloc(sizeof(*p), GFP_KERNEL); |
| @@ -425,8 +510,19 @@ static int __devinit sh_tmu_probe(struct platform_device *pdev) | |||
| 425 | if (ret) { | 510 | if (ret) { |
| 426 | kfree(p); | 511 | kfree(p); |
| 427 | platform_set_drvdata(pdev, NULL); | 512 | platform_set_drvdata(pdev, NULL); |
| 513 | pm_runtime_idle(&pdev->dev); | ||
| 514 | return ret; | ||
| 428 | } | 515 | } |
| 429 | return ret; | 516 | if (is_early_platform_device(pdev)) |
| 517 | return 0; | ||
| 518 | |||
| 519 | out: | ||
| 520 | if (cfg->clockevent_rating || cfg->clocksource_rating) | ||
| 521 | pm_runtime_irq_safe(&pdev->dev); | ||
| 522 | else | ||
| 523 | pm_runtime_idle(&pdev->dev); | ||
| 524 | |||
| 525 | return 0; | ||
| 430 | } | 526 | } |
| 431 | 527 | ||
| 432 | static int __devexit sh_tmu_remove(struct platform_device *pdev) | 528 | static int __devexit sh_tmu_remove(struct platform_device *pdev) |
diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h index acba894374a1..8a7096fcb01e 100644 --- a/include/linux/clockchips.h +++ b/include/linux/clockchips.h | |||
| @@ -97,6 +97,8 @@ struct clock_event_device { | |||
| 97 | void (*broadcast)(const struct cpumask *mask); | 97 | void (*broadcast)(const struct cpumask *mask); |
| 98 | void (*set_mode)(enum clock_event_mode mode, | 98 | void (*set_mode)(enum clock_event_mode mode, |
| 99 | struct clock_event_device *); | 99 | struct clock_event_device *); |
| 100 | void (*suspend)(struct clock_event_device *); | ||
| 101 | void (*resume)(struct clock_event_device *); | ||
| 100 | unsigned long min_delta_ticks; | 102 | unsigned long min_delta_ticks; |
| 101 | unsigned long max_delta_ticks; | 103 | unsigned long max_delta_ticks; |
| 102 | 104 | ||
| @@ -156,6 +158,9 @@ clockevents_calc_mult_shift(struct clock_event_device *ce, u32 freq, u32 minsec) | |||
| 156 | freq, minsec); | 158 | freq, minsec); |
| 157 | } | 159 | } |
| 158 | 160 | ||
| 161 | extern void clockevents_suspend(void); | ||
| 162 | extern void clockevents_resume(void); | ||
| 163 | |||
| 159 | #ifdef CONFIG_GENERIC_CLOCKEVENTS | 164 | #ifdef CONFIG_GENERIC_CLOCKEVENTS |
| 160 | extern void clockevents_notify(unsigned long reason, void *arg); | 165 | extern void clockevents_notify(unsigned long reason, void *arg); |
| 161 | #else | 166 | #else |
| @@ -164,6 +169,9 @@ extern void clockevents_notify(unsigned long reason, void *arg); | |||
| 164 | 169 | ||
| 165 | #else /* CONFIG_GENERIC_CLOCKEVENTS_BUILD */ | 170 | #else /* CONFIG_GENERIC_CLOCKEVENTS_BUILD */ |
| 166 | 171 | ||
| 172 | static inline void clockevents_suspend(void) {} | ||
| 173 | static inline void clockevents_resume(void) {} | ||
| 174 | |||
| 167 | #define clockevents_notify(reason, arg) do { } while (0) | 175 | #define clockevents_notify(reason, arg) do { } while (0) |
| 168 | 176 | ||
| 169 | #endif | 177 | #endif |
diff --git a/include/linux/device.h b/include/linux/device.h index 52a5f15a2223..86529e642d6c 100644 --- a/include/linux/device.h +++ b/include/linux/device.h | |||
| @@ -772,6 +772,13 @@ static inline void pm_suspend_ignore_children(struct device *dev, bool enable) | |||
| 772 | dev->power.ignore_children = enable; | 772 | dev->power.ignore_children = enable; |
| 773 | } | 773 | } |
| 774 | 774 | ||
| 775 | static inline void dev_pm_syscore_device(struct device *dev, bool val) | ||
| 776 | { | ||
| 777 | #ifdef CONFIG_PM_SLEEP | ||
| 778 | dev->power.syscore = val; | ||
| 779 | #endif | ||
| 780 | } | ||
| 781 | |||
| 775 | static inline void device_lock(struct device *dev) | 782 | static inline void device_lock(struct device *dev) |
| 776 | { | 783 | { |
| 777 | mutex_lock(&dev->mutex); | 784 | mutex_lock(&dev->mutex); |
diff --git a/include/linux/pm.h b/include/linux/pm.h index f067e60a3832..44d1f2307dbc 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h | |||
| @@ -510,12 +510,14 @@ struct dev_pm_info { | |||
| 510 | bool is_prepared:1; /* Owned by the PM core */ | 510 | bool is_prepared:1; /* Owned by the PM core */ |
| 511 | bool is_suspended:1; /* Ditto */ | 511 | bool is_suspended:1; /* Ditto */ |
| 512 | bool ignore_children:1; | 512 | bool ignore_children:1; |
| 513 | bool early_init:1; /* Owned by the PM core */ | ||
| 513 | spinlock_t lock; | 514 | spinlock_t lock; |
| 514 | #ifdef CONFIG_PM_SLEEP | 515 | #ifdef CONFIG_PM_SLEEP |
| 515 | struct list_head entry; | 516 | struct list_head entry; |
| 516 | struct completion completion; | 517 | struct completion completion; |
| 517 | struct wakeup_source *wakeup; | 518 | struct wakeup_source *wakeup; |
| 518 | bool wakeup_path:1; | 519 | bool wakeup_path:1; |
| 520 | bool syscore:1; | ||
| 519 | #else | 521 | #else |
| 520 | unsigned int should_wakeup:1; | 522 | unsigned int should_wakeup:1; |
| 521 | #endif | 523 | #endif |
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index a7d6172922d4..08adf8e5a80e 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h | |||
| @@ -114,7 +114,6 @@ struct generic_pm_domain_data { | |||
| 114 | struct mutex lock; | 114 | struct mutex lock; |
| 115 | unsigned int refcount; | 115 | unsigned int refcount; |
| 116 | bool need_restore; | 116 | bool need_restore; |
| 117 | bool always_on; | ||
| 118 | }; | 117 | }; |
| 119 | 118 | ||
| 120 | #ifdef CONFIG_PM_GENERIC_DOMAINS | 119 | #ifdef CONFIG_PM_GENERIC_DOMAINS |
| @@ -153,7 +152,6 @@ static inline int pm_genpd_of_add_device(struct device_node *genpd_node, | |||
| 153 | 152 | ||
| 154 | extern int pm_genpd_remove_device(struct generic_pm_domain *genpd, | 153 | extern int pm_genpd_remove_device(struct generic_pm_domain *genpd, |
| 155 | struct device *dev); | 154 | struct device *dev); |
| 156 | extern void pm_genpd_dev_always_on(struct device *dev, bool val); | ||
| 157 | extern void pm_genpd_dev_need_restore(struct device *dev, bool val); | 155 | extern void pm_genpd_dev_need_restore(struct device *dev, bool val); |
| 158 | extern int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, | 156 | extern int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, |
| 159 | struct generic_pm_domain *new_subdomain); | 157 | struct generic_pm_domain *new_subdomain); |
| @@ -199,7 +197,6 @@ static inline int pm_genpd_remove_device(struct generic_pm_domain *genpd, | |||
| 199 | { | 197 | { |
| 200 | return -ENOSYS; | 198 | return -ENOSYS; |
| 201 | } | 199 | } |
| 202 | static inline void pm_genpd_dev_always_on(struct device *dev, bool val) {} | ||
| 203 | static inline void pm_genpd_dev_need_restore(struct device *dev, bool val) {} | 200 | static inline void pm_genpd_dev_need_restore(struct device *dev, bool val) {} |
| 204 | static inline int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, | 201 | static inline int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, |
| 205 | struct generic_pm_domain *new_sd) | 202 | struct generic_pm_domain *new_sd) |
| @@ -258,4 +255,20 @@ static inline void genpd_queue_power_off_work(struct generic_pm_domain *gpd) {} | |||
| 258 | static inline void pm_genpd_poweroff_unused(void) {} | 255 | static inline void pm_genpd_poweroff_unused(void) {} |
| 259 | #endif | 256 | #endif |
| 260 | 257 | ||
| 258 | #ifdef CONFIG_PM_GENERIC_DOMAINS_SLEEP | ||
| 259 | extern void pm_genpd_syscore_switch(struct device *dev, bool suspend); | ||
| 260 | #else | ||
| 261 | static inline void pm_genpd_syscore_switch(struct device *dev, bool suspend) {} | ||
| 262 | #endif | ||
| 263 | |||
| 264 | static inline void pm_genpd_syscore_poweroff(struct device *dev) | ||
| 265 | { | ||
| 266 | pm_genpd_syscore_switch(dev, true); | ||
| 267 | } | ||
| 268 | |||
| 269 | static inline void pm_genpd_syscore_poweron(struct device *dev) | ||
| 270 | { | ||
| 271 | pm_genpd_syscore_switch(dev, false); | ||
| 272 | } | ||
| 273 | |||
| 261 | #endif /* _LINUX_PM_DOMAIN_H */ | 274 | #endif /* _LINUX_PM_DOMAIN_H */ |
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index a70518c9d82f..5dfdc9ea180b 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig | |||
| @@ -263,6 +263,10 @@ config PM_GENERIC_DOMAINS | |||
| 263 | bool | 263 | bool |
| 264 | depends on PM | 264 | depends on PM |
| 265 | 265 | ||
| 266 | config PM_GENERIC_DOMAINS_SLEEP | ||
| 267 | def_bool y | ||
| 268 | depends on PM_SLEEP && PM_GENERIC_DOMAINS | ||
| 269 | |||
| 266 | config PM_GENERIC_DOMAINS_RUNTIME | 270 | config PM_GENERIC_DOMAINS_RUNTIME |
| 267 | def_bool y | 271 | def_bool y |
| 268 | depends on PM_RUNTIME && PM_GENERIC_DOMAINS | 272 | depends on PM_RUNTIME && PM_GENERIC_DOMAINS |
diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c index 7e1ce012a851..30b6de0d977c 100644 --- a/kernel/time/clockevents.c +++ b/kernel/time/clockevents.c | |||
| @@ -397,6 +397,30 @@ void clockevents_exchange_device(struct clock_event_device *old, | |||
| 397 | local_irq_restore(flags); | 397 | local_irq_restore(flags); |
| 398 | } | 398 | } |
| 399 | 399 | ||
| 400 | /** | ||
| 401 | * clockevents_suspend - suspend clock devices | ||
| 402 | */ | ||
| 403 | void clockevents_suspend(void) | ||
| 404 | { | ||
| 405 | struct clock_event_device *dev; | ||
| 406 | |||
| 407 | list_for_each_entry_reverse(dev, &clockevent_devices, list) | ||
| 408 | if (dev->suspend) | ||
| 409 | dev->suspend(dev); | ||
| 410 | } | ||
| 411 | |||
| 412 | /** | ||
| 413 | * clockevents_resume - resume clock devices | ||
| 414 | */ | ||
| 415 | void clockevents_resume(void) | ||
| 416 | { | ||
| 417 | struct clock_event_device *dev; | ||
| 418 | |||
| 419 | list_for_each_entry(dev, &clockevent_devices, list) | ||
| 420 | if (dev->resume) | ||
| 421 | dev->resume(dev); | ||
| 422 | } | ||
| 423 | |||
| 400 | #ifdef CONFIG_GENERIC_CLOCKEVENTS | 424 | #ifdef CONFIG_GENERIC_CLOCKEVENTS |
| 401 | /** | 425 | /** |
| 402 | * clockevents_notify - notification about relevant events | 426 | * clockevents_notify - notification about relevant events |
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 34e5eac81424..312a675cb240 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c | |||
| @@ -773,6 +773,7 @@ static void timekeeping_resume(void) | |||
| 773 | 773 | ||
| 774 | read_persistent_clock(&ts); | 774 | read_persistent_clock(&ts); |
| 775 | 775 | ||
| 776 | clockevents_resume(); | ||
| 776 | clocksource_resume(); | 777 | clocksource_resume(); |
| 777 | 778 | ||
| 778 | write_seqlock_irqsave(&tk->lock, flags); | 779 | write_seqlock_irqsave(&tk->lock, flags); |
| @@ -832,6 +833,7 @@ static int timekeeping_suspend(void) | |||
| 832 | 833 | ||
| 833 | clockevents_notify(CLOCK_EVT_NOTIFY_SUSPEND, NULL); | 834 | clockevents_notify(CLOCK_EVT_NOTIFY_SUSPEND, NULL); |
| 834 | clocksource_suspend(); | 835 | clocksource_suspend(); |
| 836 | clockevents_suspend(); | ||
| 835 | 837 | ||
| 836 | return 0; | 838 | return 0; |
| 837 | } | 839 | } |
