diff mbox

New feature proposal "quickwakeup"

Message ID 1257523241.1318.367.camel@xhp836-11 (mailing list archive)
State Not Applicable
Delegated to: Kevin Hilman
Headers show

Commit Message

Falempe Jocelyn Nov. 6, 2009, 4 p.m. UTC
None
diff mbox

Patch

diff --git a/include/linux/quickwakeup.h b/include/linux/quickwakeup.h
new file mode 100755
index 0000000..60df3b8
--- /dev/null
+++ b/include/linux/quickwakeup.h
@@ -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
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 39263f4..5671f98 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -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.
diff --git a/kernel/power/Makefile b/kernel/power/Makefile
index 4319181..18b55e5 100644
--- a/kernel/power/Makefile
+++ b/kernel/power/Makefile
@@ -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
diff --git a/kernel/power/quickwakeup.c b/kernel/power/quickwakeup.c
new file mode 100644
index 0000000..3ad7392
--- /dev/null
+++ b/kernel/power/quickwakeup.c
@@ -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;
+}
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
index 6f10dfc..3fe1ec0 100644
--- a/kernel/power/suspend.c
+++ b/kernel/power/suspend.c
@@ -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();