manta: power: turn off interaction boost on VSYNC off

Change-Id: I43e2f80eba2d3c3be04bc10853b469ffea596978
diff --git a/power/power_manta.c b/power/power_manta.c
index 077520b..f1ba426 100644
--- a/power/power_manta.c
+++ b/power/power_manta.c
@@ -21,6 +21,8 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <unistd.h>
+#include <linux/time.h>
+#include <stdbool.h>
 //#define LOG_NDEBUG 0
 
 #define LOG_TAG "MantaPowerHAL"
@@ -30,6 +32,13 @@
 #include <hardware/power.h>
 
 #define BOOSTPULSE_PATH "/sys/devices/system/cpu/cpufreq/interactive/boostpulse"
+#define BOOST_PATH "/sys/devices/system/cpu/cpufreq/interactive/boost"
+//BOOST_PULSE_DURATION and BOOT_PULSE_DURATION_STR should always be in sync
+#define BOOST_PULSE_DURATION 1000000
+#define BOOST_PULSE_DURATION_STR "1000000"
+#define NSEC_PER_SEC 1000000000
+#define USEC_PER_SEC 1000000
+#define NSEC_PER_USEC 100
 
 struct manta_power_module {
     struct power_module base;
@@ -39,6 +48,10 @@
     const char *touchscreen_power_path;
 };
 
+static unsigned int vsync_count;
+static struct timespec last_touch_boost;
+static bool touch_boost;
+
 static void sysfs_write(const char *path, char *s)
 {
     char buf[80];
@@ -115,7 +128,7 @@
     sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/above_hispeed_delay",
                 "80000");
     sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/boostpulse_duration",
-                "500000");
+                BOOST_PULSE_DURATION_STR);
     sysfs_write("/sys/devices/system/cpu/cpufreq/interactive/io_is_busy", "1");
 
     init_touchscreen_power_path(manta);
@@ -163,29 +176,74 @@
     return manta->boostpulse_fd;
 }
 
+static struct timespec timespec_diff(struct timespec lhs, struct timespec rhs)
+{
+    struct timespec result;
+    if (rhs.tv_nsec > lhs.tv_nsec) {
+        result.tv_sec = lhs.tv_sec - rhs.tv_sec - 1;
+        result.tv_nsec = NSEC_PER_SEC + lhs.tv_nsec - rhs.tv_nsec;
+    } else {
+        result.tv_sec = lhs.tv_sec - rhs.tv_sec;
+        result.tv_nsec = lhs.tv_nsec - rhs.tv_nsec;
+    }
+    return result;
+}
+
+static int check_boostpulse_on(struct timespec diff)
+{
+    long boost_ns = (BOOST_PULSE_DURATION * NSEC_PER_USEC) % NSEC_PER_SEC;
+    long boost_s = BOOST_PULSE_DURATION / USEC_PER_SEC;
+
+    if (diff.tv_sec == boost_s)
+        return (diff.tv_nsec < boost_ns);
+    return (diff.tv_sec < boost_s);
+}
+
 static void manta_power_hint(struct power_module *module, power_hint_t hint,
                              void *data)
 {
     struct manta_power_module *manta = (struct manta_power_module *) module;
+    struct timespec now, diff;
     char buf[80];
     int len;
 
     switch (hint) {
      case POWER_HINT_INTERACTION:
         if (boostpulse_open(manta) >= 0) {
+            pthread_mutex_lock(&manta->lock);
             len = write(manta->boostpulse_fd, "1", 1);
 
             if (len < 0) {
                 strerror_r(errno, buf, sizeof(buf));
                 ALOGE("Error writing to %s: %s\n", BOOSTPULSE_PATH, buf);
+            } else {
+                clock_gettime(CLOCK_MONOTONIC, &last_touch_boost);
+                touch_boost = true;
             }
+            pthread_mutex_unlock(&manta->lock);
         }
 
         break;
 
-   case POWER_HINT_VSYNC:
+     case POWER_HINT_VSYNC:
+        pthread_mutex_lock(&manta->lock);
+        if (data) {
+            if (vsync_count < UINT_MAX)
+                vsync_count++;
+        } else {
+            if (vsync_count)
+                vsync_count--;
+            if (vsync_count == 0 && touch_boost) {
+                touch_boost = false;
+                clock_gettime(CLOCK_MONOTONIC, &now);
+                diff = timespec_diff(now, last_touch_boost);
+                if (check_boostpulse_on(diff)) {
+                    sysfs_write(BOOST_PATH, "0");
+                }
+            }
+        }
+        pthread_mutex_unlock(&manta->lock);
         break;
-
     default:
             break;
     }