Merge tag 'v3.10.56' into update
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / kernel / power / main.c
index 312c1b2c725ddf4165a373c609f307679118a951..4811bd391f08ab3c8918181a2e451759c97cee0e 100644 (file)
 
 #include "power.h"
 
+#define HIB_PM_DEBUG 1
+#define _TAG_HIB_M "HIB/PM"
+#if (HIB_PM_DEBUG)
+#undef hib_log
+#define hib_log(fmt, ...)  pr_warn("[%s][%s]" fmt, _TAG_HIB_M, __func__, ##__VA_ARGS__);
+#else
+#define hib_log(fmt, ...)
+#endif
+#undef hib_warn
+#define hib_warn(fmt, ...) pr_warn("[%s][%s]" fmt, _TAG_HIB_M, __func__, ##__VA_ARGS__);
+
 DEFINE_MUTEX(pm_mutex);
+EXPORT_SYMBOL_GPL(pm_mutex);
 
 #ifdef CONFIG_PM_SLEEP
 
 /* Routines for PM-transition notifications */
 
-static BLOCKING_NOTIFIER_HEAD(pm_chain_head);
+BLOCKING_NOTIFIER_HEAD(pm_chain_head);
+EXPORT_SYMBOL_GPL(pm_chain_head);
+//<20130327> <marc.huang> add pm_notifier_count
+static unsigned int pm_notifier_count = 0;
 
 int register_pm_notifier(struct notifier_block *nb)
 {
+       //<20130327> <marc.huang> add pm_notifier_count
+       ++pm_notifier_count;
        return blocking_notifier_chain_register(&pm_chain_head, nb);
 }
 EXPORT_SYMBOL_GPL(register_pm_notifier);
 
 int unregister_pm_notifier(struct notifier_block *nb)
 {
+       //<20130327> <marc.huang> add pm_notifier_count
+       --pm_notifier_count;
        return blocking_notifier_chain_unregister(&pm_chain_head, nb);
 }
 EXPORT_SYMBOL_GPL(unregister_pm_notifier);
 
 int pm_notifier_call_chain(unsigned long val)
 {
-       int ret = blocking_notifier_call_chain(&pm_chain_head, val, NULL);
+       //<20130327> <marc.huang> add pm_notifier_count
+       int ret;
+       pr_debug("[%s] pm_notifier_count: %u, event = %lu\n", __func__, pm_notifier_count, val);
+
+       ret = blocking_notifier_call_chain(&pm_chain_head, val, NULL);
 
        return notifier_to_errno(ret);
 }
+EXPORT_SYMBOL_GPL(pm_notifier_call_chain);
 
 /* If set, devices may be suspended and resumed asynchronously. */
-int pm_async_enabled = 1;
+//<20130327> <marc.huang> disable async suspend/resume, set pm_async_enabled = 0
+int pm_async_enabled = 0;
 
 static ssize_t pm_async_show(struct kobject *kobj, struct kobj_attribute *attr,
                             char *buf)
@@ -277,6 +302,7 @@ static inline void pm_print_times_init(void) {}
 #endif /* CONFIG_PM_SLEEP_DEBUG */
 
 struct kobject *power_kobj;
+EXPORT_SYMBOL_GPL(power_kobj);
 
 /**
  *     state - control system power state.
@@ -336,6 +362,8 @@ static suspend_state_t decode_state(const char *buf, size_t n)
        return PM_SUSPEND_ON;
 }
 
+//<20130327> <marc.huang> merge android kernel 3.0 state_store function
+#ifdef CONFIG_MTK_LDVT
 static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
                           const char *buf, size_t n)
 {
@@ -363,7 +391,81 @@ static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
        pm_autosleep_unlock();
        return error ? error : n;
 }
+#else //#ifdef CONFIG_MTK_LDVT
+static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
+               const char *buf, size_t n)
+{
+#ifdef CONFIG_SUSPEND
+#ifdef CONFIG_EARLYSUSPEND
+    suspend_state_t state = PM_SUSPEND_ON;
+#else
+    suspend_state_t state = PM_SUSPEND_STANDBY;
+#endif
+    const char * const *s;
+#endif
+    char *p;
+    int len;
+    int error = -EINVAL;
+
+    p = memchr(buf, '\n', n);
+    len = p ? p - buf : n;
+
+#ifdef CONFIG_MTK_HIBERNATION
+    state = decode_state(buf, n);
+    hib_log("entry (%d)\n", state);
+#endif
 
+#ifdef CONFIG_MTK_HIBERNATION
+    if (len == 8 && !strncmp(buf, "hibabort", len)) {
+        hib_log("abort hibernation...\n");
+        error = mtk_hibernate_abort();
+        goto Exit;
+    }
+#endif
+
+    /* First, check if we are requested to hibernate */
+    if (len == 4 && !strncmp(buf, "disk", len)) {
+#ifdef CONFIG_MTK_HIBERNATION
+        hib_log("trigger hibernation...\n");
+#ifdef CONFIG_EARLYSUSPEND
+        if (PM_SUSPEND_ON == get_suspend_state()) {
+            hib_warn("\"on\" to \"disk\" (i.e., 0->4) is not supported !!!\n");
+            error = -EINVAL;
+            goto Exit;
+        }
+#endif
+        if (!pre_hibernate()) {
+            error = 0;
+            error = mtk_hibernate();
+        }
+#else // !CONFIG_MTK_HIBERNATION
+        error = hibernate();
+#endif
+        goto Exit;
+    }
+
+#ifdef CONFIG_SUSPEND
+    for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {
+        if (*s && len == strlen(*s) && !strncmp(buf, *s, len))
+            break;
+    }
+    if (state < PM_SUSPEND_MAX && *s) {
+#ifdef CONFIG_EARLYSUSPEND
+        if (state == PM_SUSPEND_ON || valid_state(state)) {
+            error = 0;
+            request_suspend_state(state);
+        } else
+            error = -EINVAL;
+#else
+        error = enter_state(state);
+#endif
+    }
+#endif
+
+ Exit:
+    return error ? error : n;
+}
+#endif
 power_attr(state);
 
 #ifdef CONFIG_PM_SLEEP
@@ -463,6 +565,7 @@ static ssize_t autosleep_store(struct kobject *kobj,
        suspend_state_t state = decode_state(buf, n);
        int error;
 
+    hib_log("store autosleep_state(%d)\n", state);
        if (state == PM_SUSPEND_ON
            && strcmp(buf, "off") && strcmp(buf, "off\n"))
                return -EINVAL;