new file mode 100755
@@ -0,0 +1,33 @@
+/* include/linux/quickwakeup.h
+ *
+ * Copyright (C) 2009 Motorola.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+struct quickwakeup_ops {
+ struct list_head list;
+ int (*qw_callback) (void);
+ int (*qw_check)(void);
+ int checked;
+};
+
+#ifdef CONFIG_QUICK_WAKEUP
+
+int quickwakeup_register(struct quickwakeup_ops *ops);
+int quickwakeup_check(void);
+int quickwakeup_execute(void);
+void quickwakeup_unregister(struct quickwakeup_ops *ops);
+
+#else
+static int quickwakeup_register(struct quickwakeup_ops *ops) { return 0; };
+void quickwakeup_unregister(struct quickwakeup_ops *ops) {};
+#endif
@@ -236,3 +236,11 @@ config PM_RUNTIME
and the bus type drivers of the buses the devices are on are
responsible for the actual handling of the autosuspend requests and
wake-up events.
+
+config QUICK_WAKEUP
+ bool "Quick wakeup"
+ depends on SUSPEND
+ default n
+ ---help---
+ Allow kernel driver to do periodic jobs without resuming the full system
+ This option can increase battery life on android powered smartphone.
@@ -10,5 +10,5 @@ obj-$(CONFIG_SUSPEND) += suspend.o
obj-$(CONFIG_PM_TEST_SUSPEND) += suspend_test.o
obj-$(CONFIG_HIBERNATION) += hibernate.o snapshot.o swap.o user.o
obj-$(CONFIG_HIBERNATION_NVS) += hibernate_nvs.o
-
+obj-$(CONFIG_QUICK_WAKEUP) += quickwakeup.o
obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o
new file mode 100644
@@ -0,0 +1,60 @@
+/* kernel/power/quickwakeup.c
+ *
+ * Copyright (C) 2009 Motorola.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/quickwakeup.h>
+
+static LIST_HEAD(qw_head);
+
+int quickwakeup_register(struct quickwakeup_ops *ops)
+{
+ list_add(&ops->list, &qw_head);
+ return 0;
+}
+
+void quickwakeup_unregister(struct quickwakeup_ops *ops)
+{
+ list_del(&ops->list);
+}
+
+int quickwakeup_check(void)
+{
+ int ret = 0;
+ struct quickwakeup_ops *index;
+
+ list_for_each_entry(index, &qw_head, list) {
+ index->checked = index->qw_check();
+ ret |= index->checked;
+ }
+ return ret;
+}
+
+int quickwakeup_execute(void)
+{
+ int ret;
+ int count = 0;
+ struct quickwakeup_ops *index;
+
+ list_for_each_entry(index, &qw_head, list) {
+ if (index->checked)
+ ret = index->qw_callback();
+ if (ret != 0)
+ return ret;
+ count++;
+ }
+ if (!count)
+ return -1;
+ return 0;
+}
@@ -116,6 +116,28 @@ void __attribute__ ((weak)) arch_suspend_enable_irqs(void)
local_irq_enable();
}
+static int _suspend_enter(suspend_state_t state)
+{
+ int error;
+ arch_suspend_disable_irqs();
+ BUG_ON(!irqs_disabled());
+
+ error = sysdev_suspend(PMSG_SUSPEND);
+ if (!error) {
+ if (!suspend_test(TEST_CORE))
+ error = suspend_ops->enter(state);
+ sysdev_resume();
+ }
+ if (!error) {
+#ifdef CONFIG_QUICK_WAKEUP
+ quickwakeup_check();
+#endif
+ }
+ arch_suspend_enable_irqs();
+ BUG_ON(irqs_disabled());
+ return error;
+}
+
/**
* suspend_enter - enter the desired system sleep state.
* @state: state to enter
@@ -151,18 +173,14 @@ static int suspend_enter(suspend_state_t state)
if (error || suspend_test(TEST_CPUS))
goto Enable_cpus;
- arch_suspend_disable_irqs();
- BUG_ON(!irqs_disabled());
-
- error = sysdev_suspend(PMSG_SUSPEND);
- if (!error) {
- if (!suspend_test(TEST_CORE))
- error = suspend_ops->enter(state);
- sysdev_resume();
- }
-
- arch_suspend_enable_irqs();
- BUG_ON(irqs_disabled());
+ error = _suspend_enter(state);
+#ifdef CONFIG_QUICK_WAKEUP
+ while (!error && !quickwakeup_execute()) {
+ if (has_wake_lock(WAKE_LOCK_SUSPEND))
+ break;
+ error = _suspend_enter(state);
+ }
+#endif
Enable_cpus:
enable_nonboot_cpus();