msm: clock: Support clk_prepare/unprepare()

Fill in the boiler plate prepare()/unprepare() code. Add a
prepare count and a prepare lock to protect the prepare/unprepare
paths. Also handle the parent/child relationship similarly to how
enable/disable is done.

In particular, WARN() whenever a driver calls clk_enable() before
calling clk_prepare() and whenever a driver calls clk_unprepare()
before calling clk_disable(). This should catch a few bugs even
though it's technically not SMP safe if an enable call is racing
with an unprepare call for example.

We also mark PLLs and XOs as already warned since those are
mostly internal clocks that driver authors aren't aware of. The
markings will be removed when the local clock driver is updated
to handle prepare/unprepare in another patch.

Change-Id: I41dd39d27a279f3477c6e1cef292ac5308d65243
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index 5b89fa9..7f0cafd 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -127,6 +127,41 @@
 	unvote_vdd_level(clk->vdd_class, level);
 }
 
+int clk_prepare(struct clk *clk)
+{
+	int ret = 0;
+	struct clk *parent;
+	if (!clk)
+		return 0;
+
+	mutex_lock(&clk->prepare_lock);
+	if (clk->prepare_count == 0) {
+		parent = clk_get_parent(clk);
+
+		ret = clk_prepare(parent);
+		if (ret)
+			goto out;
+		ret = clk_prepare(clk->depends);
+		if (ret)
+			goto err_prepare_depends;
+
+		if (clk->ops->prepare)
+			ret = clk->ops->prepare(clk);
+		if (ret)
+			goto err_prepare_clock;
+	}
+	clk->prepare_count++;
+out:
+	mutex_unlock(&clk->prepare_lock);
+	return ret;
+err_prepare_clock:
+	clk_unprepare(clk->depends);
+err_prepare_depends:
+	clk_unprepare(parent);
+	goto out;
+}
+EXPORT_SYMBOL(clk_prepare);
+
 /*
  * Standard clock functions defined in include/linux/clk.h
  */
@@ -140,6 +175,10 @@
 		return 0;
 
 	spin_lock_irqsave(&clk->lock, flags);
+	if (WARN(!clk->warned && !clk->prepare_count,
+				"%s: Don't call enable on unprepared clocks\n",
+				clk->dbg_name))
+		clk->warned = true;
 	if (clk->count == 0) {
 		parent = clk_get_parent(clk);
 
@@ -193,6 +232,11 @@
 		return;
 
 	spin_lock_irqsave(&clk->lock, flags);
+	if (WARN(!clk->warned && !clk->prepare_count,
+				"%s: Never called prepare or calling disable "
+				"after unprepare\n",
+				clk->dbg_name))
+		clk->warned = true;
 	if (WARN(clk->count == 0, "%s is unbalanced", clk->dbg_name))
 		goto out;
 	if (clk->count == 1) {
@@ -210,6 +254,37 @@
 }
 EXPORT_SYMBOL(clk_disable);
 
+void clk_unprepare(struct clk *clk)
+{
+	if (!clk)
+		return;
+
+	mutex_lock(&clk->prepare_lock);
+	if (!clk->prepare_count) {
+		if (WARN(!clk->warned, "%s is unbalanced (prepare)",
+				clk->dbg_name))
+			clk->warned = true;
+		goto out;
+	}
+	if (clk->prepare_count == 1) {
+		struct clk *parent = clk_get_parent(clk);
+
+		if (WARN(!clk->warned && clk->count,
+			"%s: Don't call unprepare when the clock is enabled\n",
+				clk->dbg_name))
+			clk->warned = true;
+
+		if (clk->ops->unprepare)
+			clk->ops->unprepare(clk);
+		clk_unprepare(clk->depends);
+		clk_unprepare(parent);
+	}
+	clk->prepare_count--;
+out:
+	mutex_unlock(&clk->prepare_lock);
+}
+EXPORT_SYMBOL(clk_unprepare);
+
 int clk_reset(struct clk *clk, enum clk_reset_action action)
 {
 	if (!clk->ops->reset)
@@ -335,7 +410,7 @@
 		if (clk->ops->handoff && !(clk->flags & CLKFLAG_HANDOFF_RATE)) {
 			if (clk->ops->handoff(clk)) {
 				clk->flags |= CLKFLAG_HANDOFF_RATE;
-				clk_enable(clk);
+				clk_prepare_enable(clk);
 			}
 		}
 	}
@@ -372,11 +447,11 @@
 			}
 			spin_unlock_irqrestore(&clk->lock, flags);
 			/*
-			 * Calling clk_disable() outside the lock is safe since
+			 * Calling this outside the lock is safe since
 			 * it doesn't need to be atomic with the flag change.
 			 */
 			if (handoff)
-				clk_disable(clk);
+				clk_disable_unprepare(clk);
 		}
 	}
 	pr_info("clock_late_init() disabled %d unused clocks\n", count);