0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/device.h>
0011 #include <linux/mutex.h>
0012 #include <linux/pm_wakeup.h>
0013
0014 #include "power.h"
0015
0016 static suspend_state_t autosleep_state;
0017 static struct workqueue_struct *autosleep_wq;
0018
0019
0020
0021
0022
0023
0024 static DEFINE_MUTEX(autosleep_lock);
0025 static struct wakeup_source *autosleep_ws;
0026
0027 static void try_to_suspend(struct work_struct *work)
0028 {
0029 unsigned int initial_count, final_count;
0030
0031 if (!pm_get_wakeup_count(&initial_count, true))
0032 goto out;
0033
0034 mutex_lock(&autosleep_lock);
0035
0036 if (!pm_save_wakeup_count(initial_count) ||
0037 system_state != SYSTEM_RUNNING) {
0038 mutex_unlock(&autosleep_lock);
0039 goto out;
0040 }
0041
0042 if (autosleep_state == PM_SUSPEND_ON) {
0043 mutex_unlock(&autosleep_lock);
0044 return;
0045 }
0046 if (autosleep_state >= PM_SUSPEND_MAX)
0047 hibernate();
0048 else
0049 pm_suspend(autosleep_state);
0050
0051 mutex_unlock(&autosleep_lock);
0052
0053 if (!pm_get_wakeup_count(&final_count, false))
0054 goto out;
0055
0056
0057
0058
0059
0060 if (final_count == initial_count)
0061 schedule_timeout_uninterruptible(HZ / 2);
0062
0063 out:
0064 queue_up_suspend_work();
0065 }
0066
0067 static DECLARE_WORK(suspend_work, try_to_suspend);
0068
0069 void queue_up_suspend_work(void)
0070 {
0071 if (autosleep_state > PM_SUSPEND_ON)
0072 queue_work(autosleep_wq, &suspend_work);
0073 }
0074
0075 suspend_state_t pm_autosleep_state(void)
0076 {
0077 return autosleep_state;
0078 }
0079
0080 int pm_autosleep_lock(void)
0081 {
0082 return mutex_lock_interruptible(&autosleep_lock);
0083 }
0084
0085 void pm_autosleep_unlock(void)
0086 {
0087 mutex_unlock(&autosleep_lock);
0088 }
0089
0090 int pm_autosleep_set_state(suspend_state_t state)
0091 {
0092
0093 #ifndef CONFIG_HIBERNATION
0094 if (state >= PM_SUSPEND_MAX)
0095 return -EINVAL;
0096 #endif
0097
0098 __pm_stay_awake(autosleep_ws);
0099
0100 mutex_lock(&autosleep_lock);
0101
0102 autosleep_state = state;
0103
0104 __pm_relax(autosleep_ws);
0105
0106 if (state > PM_SUSPEND_ON) {
0107 pm_wakep_autosleep_enabled(true);
0108 queue_up_suspend_work();
0109 } else {
0110 pm_wakep_autosleep_enabled(false);
0111 }
0112
0113 mutex_unlock(&autosleep_lock);
0114 return 0;
0115 }
0116
0117 int __init pm_autosleep_init(void)
0118 {
0119 autosleep_ws = wakeup_source_register(NULL, "autosleep");
0120 if (!autosleep_ws)
0121 return -ENOMEM;
0122
0123 autosleep_wq = alloc_ordered_workqueue("autosleep", 0);
0124 if (autosleep_wq)
0125 return 0;
0126
0127 wakeup_source_unregister(autosleep_ws);
0128 return -ENOMEM;
0129 }