msm: krait-regulator: enable phase management based on cpu status

The current code enables phase management at late init stage. This is
safe except if the acpuclock driver moves to late init stage, we might end
up enabling phase management before the acpuclock driver gets to call
voltage and mode callbacks on already onlined cpus. We risk
prematurely lowering the phase count and browning out the device.
Instead check how many cpus are actually online at probe time and enable
phase management only after voltage and mode callbacks happen for them.

Change-Id: Ia63ec06a0793d5e33b28c89c872f1b822567f521
Signed-off-by: Patrick Cain <pcain@codeaurora.org>
diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
index e0dd3dc..ed9f639 100644
--- a/arch/arm/mach-msm/krait-regulator.c
+++ b/arch/arm/mach-msm/krait-regulator.c
@@ -171,6 +171,9 @@
 	LDO_MODE = REGULATOR_MODE_IDLE,
 };
 
+#define WAIT_FOR_LOAD		0x2
+#define WAIT_FOR_VOLTAGE	0x1
+
 struct krait_power_vreg {
 	struct list_head		link;
 	struct regulator_desc		desc;
@@ -191,6 +194,7 @@
 	int				coeff1;
 	int				coeff2;
 	bool				online;
+	int				online_at_probe;
 };
 
 DEFINE_PER_CPU(struct krait_power_vreg *, krait_vregs);
@@ -388,6 +392,19 @@
 	return load_total;
 }
 
+static bool enable_phase_management(struct pmic_gang_vreg *pvreg)
+{
+	struct krait_power_vreg *kvreg;
+
+	list_for_each_entry(kvreg, &pvreg->krait_power_vregs, link) {
+		pr_debug("%s online_at_probe:0x%x\n", kvreg->name,
+							kvreg->online_at_probe);
+		if (kvreg->online_at_probe)
+			return false;
+	}
+	return true;
+}
+
 #define PMIC_FTS_MODE_PFM	0x00
 #define PMIC_FTS_MODE_PWM	0x80
 #define ONE_PHASE_COEFF		1000000
@@ -405,8 +422,12 @@
 
 	load_total = get_total_load(from);
 
-	if (pvreg->manage_phases == false)
-		return 0;
+	if (pvreg->manage_phases == false) {
+		if (enable_phase_management(pvreg))
+			pvreg->manage_phases = true;
+		else
+			return 0;
+	}
 
 	/* First check if the coeff is low for PFM mode */
 	if (load_total <= pvreg->pfm_threshold && n_online == 1) {
@@ -478,6 +499,7 @@
 	int coeff_total;
 	int rc;
 
+	kvreg->online_at_probe &= ~WAIT_FOR_LOAD;
 	coeff_total = get_coeff_total(kvreg);
 
 	rc = pmic_gang_set_phases(kvreg, coeff_total);
@@ -797,6 +819,7 @@
 				kvreg->name, requested_uV, orig_krait_uV, rc);
 	}
 
+	kvreg->online_at_probe &= ~WAIT_FOR_VOLTAGE;
 	coeff_total = get_coeff_total(kvreg);
 	/* adjust the phases since coeff2 would have changed */
 	rc = pmic_gang_set_phases(kvreg, coeff_total);
@@ -932,8 +955,10 @@
 DEFINE_SIMPLE_ATTRIBUTE(retention_fops,
 			get_retention_dbg_uV, set_retention_dbg_uV, "%llu\n");
 
+#define CPU_PWR_CTL_ONLINE_MASK 0x80
 static void kvreg_hw_init(struct krait_power_vreg *kvreg)
 {
+	int online;
 	/*
 	 * bhs_cnt value sets the ramp-up time from power collapse,
 	 * initialize the ramp up time
@@ -946,6 +971,10 @@
 	/* Enable MDD */
 	writel_relaxed(0x00000002, kvreg->mdd_base + MDD_MODE);
 	mb();
+	online = CPU_PWR_CTL_ONLINE_MASK
+			& readl_relaxed(kvreg->reg_base + CPU_PWR_CTL);
+	kvreg->online_at_probe
+		= online ? (WAIT_FOR_LOAD | WAIT_FOR_VOLTAGE) : 0x0;
 }
 
 static void glb_init(void __iomem *apcs_gcc_base)
@@ -1326,14 +1355,6 @@
 		base_ptr + APC_PWR_GATE_CTL);
 }
 
-static int __devinit begin_pmic_phase_management(void)
-{
-	if (the_gang != NULL)
-		the_gang->manage_phases = true;
-	return 0;
-}
-late_initcall(begin_pmic_phase_management);
-
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("KRAIT POWER regulator driver");
 MODULE_VERSION("1.0");