msm: clock: Make sure clock parents are set before handoff

The loop that calls clk_set_parent() on each clock in the table is the
same one that performs clock handoffs and calls clk_prepare_enable()
on them. For complex clock hierarchies, it's possible that a clock's
grandparent would not yet be set by the time clk_prepare_enable() is
called.

Fix this by breaking the loop into two. The first loop iterates over
all the clocks and sets up their parents. The second performs the
handoff operations which may depend on the parents being set.

With this, there is still no guarantee that a clock's parent is
handed off before the clock itself, but we're one step closer to
a robust solution.

Change-Id: I4dece682e6d9a4c60746f8639f98789c2e23b20f
Signed-off-by: Matt Wagantall <mattw@codeaurora.org>
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index dcded38..09bf036 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -399,6 +399,7 @@
 	unsigned n;
 	struct clk_lookup *clock_tbl;
 	size_t num_clocks;
+	struct clk *clk;
 
 	clk_init_data = data;
 	if (clk_init_data->pre_init)
@@ -408,15 +409,23 @@
 	num_clocks = data->size;
 
 	for (n = 0; n < num_clocks; n++) {
-		struct clk *clk = clock_tbl[n].clk;
-		struct clk *parent = clk_get_parent(clk);
+		struct clk *parent;
+		clk = clock_tbl[n].clk;
+		parent = clk_get_parent(clk);
 		if (parent && list_empty(&clk->siblings))
 			list_add(&clk->siblings, &parent->children);
-		if (clk->ops->handoff && !(clk->flags & CLKFLAG_HANDOFF_RATE)) {
-			if (clk->ops->handoff(clk) == HANDOFF_ENABLED_CLK) {
-				clk->flags |= CLKFLAG_HANDOFF_RATE;
-				clk_prepare_enable(clk);
-			}
+	}
+
+	/*
+	 * Detect and preserve initial clock state until clock_late_init() or
+	 * a driver explicitly changes it, whichever is first.
+	 */
+	for (n = 0; n < num_clocks; n++) {
+		clk = clock_tbl[n].clk;
+		if (clk->ops->handoff && !(clk->flags & CLKFLAG_HANDOFF_RATE) &&
+		    (clk->ops->handoff(clk) == HANDOFF_ENABLED_CLK)) {
+			clk->flags |= CLKFLAG_HANDOFF_RATE;
+			clk_prepare_enable(clk);
 		}
 	}