msm: lpm_levels: Adjust for event wakeup in lpm calculation

Adjust for event wakeup time in lpm calculation that determines the best
sleep mode to enter for a given sleep time. The event wakeup times are
treated as hard wakeups that need modified wakeup time with a back off
calculated on the latency of each low power level.

Change-Id: I4bf5adf13a715960941ad5f12ecc02a16d48b1ff
Signed-off-by: Girish Mahadevan <girishm@codeaurora.org>
diff --git a/arch/arm/mach-msm/lpm_levels.c b/arch/arm/mach-msm/lpm_levels.c
index 539a4fe..8194721 100644
--- a/arch/arm/mach-msm/lpm_levels.c
+++ b/arch/arm/mach-msm/lpm_levels.c
@@ -205,6 +205,8 @@
 	int best_level_iter = msm_lpm_level_count + 1;
 	bool irqs_detect = false;
 	bool gpio_detect = false;
+	bool modify_event_timer;
+	uint32_t next_wakeup_us = time_param->sleep_us;
 
 	if (!msm_lpm_levels)
 		return NULL;
@@ -219,6 +221,8 @@
 	for (i = 0; i < msm_lpm_level_count; i++) {
 		struct msm_rpmrs_level *level = &msm_lpm_levels[i];
 
+		modify_event_timer = false;
+
 		if (!level->available)
 			continue;
 
@@ -228,6 +232,23 @@
 		if (time_param->latency_us < level->latency_us)
 			continue;
 
+		if (time_param->next_event_us &&
+			time_param->next_event_us < level->latency_us)
+			continue;
+
+		if (time_param->next_event_us) {
+			if ((time_param->next_event_us < time_param->sleep_us)
+			|| ((time_param->next_event_us - level->latency_us) <
+				time_param->sleep_us)) {
+				modify_event_timer = true;
+				next_wakeup_us = time_param->next_event_us -
+						level->latency_us;
+			}
+		}
+
+		if (next_wakeup_us <= level->time_overhead_us)
+			continue;
+
 		if ((sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) &&
 			!msm_lpm_irqs_detectable(&level->rs_limits,
 				irqs_detect, gpio_detect))
@@ -238,19 +259,19 @@
 			if (!cpu && msm_rpm_waiting_for_ack())
 					break;
 
-		if (time_param->sleep_us <= 1) {
+		if (next_wakeup_us <= 1) {
 			pwr = level->energy_overhead;
-		} else if (time_param->sleep_us <= level->time_overhead_us) {
-			pwr = level->energy_overhead / time_param->sleep_us;
-		} else if ((time_param->sleep_us >> 10)
+		} else if (next_wakeup_us <= level->time_overhead_us) {
+			pwr = level->energy_overhead / next_wakeup_us;
+		} else if ((next_wakeup_us >> 10)
 				> level->time_overhead_us) {
 			pwr = level->steady_state_power;
 		} else {
 			pwr = level->steady_state_power;
 			pwr -= (level->time_overhead_us *
 				level->steady_state_power) /
-						time_param->sleep_us;
-			pwr += level->energy_overhead / time_param->sleep_us;
+						next_wakeup_us;
+			pwr += level->energy_overhead / next_wakeup_us;
 		}
 
 		if (!best_level || best_level->rs_limits.power[cpu] >= pwr) {
@@ -261,6 +282,14 @@
 			best_level_iter = i;
 			if (power)
 				*power = pwr;
+			if (modify_event_timer &&
+				(sleep_mode !=
+					MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT))
+				time_param->modified_time_us =
+					time_param->next_event_us -
+						best_level->latency_us;
+			else
+				time_param->modified_time_us = 0;
 		}
 	}
 	if (best_level && !lpm_level_permitted(best_level_iter))