aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/power/suspend.c
diff options
context:
space:
mode:
authorMyungJoo Ham <myungjoo.ham@samsung.com>2011-06-12 09:57:05 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2011-07-15 17:58:19 -0400
commit3b5fe85252326217cd96f24a7bda4460d8f71bee (patch)
treecfcf577a53b88109d36f73577a8177279444a09f /kernel/power/suspend.c
parent99f381d3549432a250fe846a2a82d61a032804b0 (diff)
PM / Suspend: Add .suspend_again() callback to suspend_ops
A system or a device may need to control suspend/wakeup events. It may want to wakeup the system after a predefined amount of time or at a predefined event decided while entering suspend for polling or delayed work. Then, it may want to enter suspend again if its predefined wakeup condition is the only wakeup reason and there is no outstanding events; thus, it does not wakeup the userspace unnecessary or unnecessary devices and keeps suspended as long as possible (saving the power). Enabling a system to wakeup after a specified time can be easily achieved by using RTC. However, to enter suspend again immediately without invoking userland and unrelated devices, we need additional features in the suspend framework. Such need comes from: 1. Monitoring a critical device status without interrupts that can wakeup the system. (in-suspend polling) An example is ambient temperature monitoring that needs to shut down the system or a specific device function if it is too hot or cold. The temperature of a specific device may be needed to be monitored as well; e.g., a charger monitors battery temperature in order to stop charging if overheated. 2. Execute critical "delayed work" at suspend. A driver or a system/board may have a delayed work (or any similar things) that it wants to execute at the requested time. For example, some chargers want to check the battery voltage some time (e.g., 30 seconds) after the battery is fully charged and the charger has stopped. Then, the charger restarts charging if the voltage has dropped more than a threshold, which is smaller than "restart-charger" voltage, which is a threshold to restart charging regardless of the time passed. This patch allows to add "suspend_again" callback at struct platform_suspend_ops and let the "suspend_again" callback return true if the system is required to enter suspend again after the current instance of wakeup. Device-wise suspend_again implemented at dev_pm_ops or syscore is not done because: a) suspend_again feature is usually under platform-wise decision and controls the behavior of the whole platform and b) There are very limited devices related to the usage cases of suspend_again; chargers and temperature sensors are mentioned so far. With suspend_again callback registered at struct platform_suspend_ops suspend_ops in kernel/power/suspend.c with suspend_set_ops by the platform, the suspend framework tries to enter suspend again by looping suspend_enter() if suspend_again has returned true and there has been no errors in the suspending sequence or pending wakeups (by pm_wakeup_pending). Tested at Exynos4-NURI. [rjw: Fixed up kerneldoc comment for suspend_enter().] Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Acked-by: Pavel Machek <pavel@ucw.cz> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Diffstat (limited to 'kernel/power/suspend.c')
-rw-r--r--kernel/power/suspend.c18
1 files changed, 12 insertions, 6 deletions
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
index 1c41ba21541..b6762f43365 100644
--- a/kernel/power/suspend.c
+++ b/kernel/power/suspend.c
@@ -126,12 +126,13 @@ void __attribute__ ((weak)) arch_suspend_enable_irqs(void)
126} 126}
127 127
128/** 128/**
129 * suspend_enter - enter the desired system sleep state. 129 * suspend_enter - enter the desired system sleep state.
130 * @state: state to enter 130 * @state: State to enter
131 * @wakeup: Returns information that suspend should not be entered again.
131 * 132 *
132 * This function should be called after devices have been suspended. 133 * This function should be called after devices have been suspended.
133 */ 134 */
134static int suspend_enter(suspend_state_t state) 135static int suspend_enter(suspend_state_t state, bool *wakeup)
135{ 136{
136 int error; 137 int error;
137 138
@@ -165,7 +166,8 @@ static int suspend_enter(suspend_state_t state)
165 166
166 error = syscore_suspend(); 167 error = syscore_suspend();
167 if (!error) { 168 if (!error) {
168 if (!(suspend_test(TEST_CORE) || pm_wakeup_pending())) { 169 *wakeup = pm_wakeup_pending();
170 if (!(suspend_test(TEST_CORE) || *wakeup)) {
169 error = suspend_ops->enter(state); 171 error = suspend_ops->enter(state);
170 events_check_enabled = false; 172 events_check_enabled = false;
171 } 173 }
@@ -199,6 +201,7 @@ static int suspend_enter(suspend_state_t state)
199int suspend_devices_and_enter(suspend_state_t state) 201int suspend_devices_and_enter(suspend_state_t state)
200{ 202{
201 int error; 203 int error;
204 bool wakeup = false;
202 205
203 if (!suspend_ops) 206 if (!suspend_ops)
204 return -ENOSYS; 207 return -ENOSYS;
@@ -220,7 +223,10 @@ int suspend_devices_and_enter(suspend_state_t state)
220 if (suspend_test(TEST_DEVICES)) 223 if (suspend_test(TEST_DEVICES))
221 goto Recover_platform; 224 goto Recover_platform;
222 225
223 error = suspend_enter(state); 226 do {
227 error = suspend_enter(state, &wakeup);
228 } while (!error && !wakeup
229 && suspend_ops->suspend_again && suspend_ops->suspend_again());
224 230
225 Resume_devices: 231 Resume_devices:
226 suspend_test_start(); 232 suspend_test_start();