msm: clock: Move voltage scaling to prepare/unprepare

Move the voltage calls to a sleepable context so we can avoid
spinning for hundreds of microseconds with interrupts disabled
waiting for a regulator to increase. This change also paves the
way to making the clock driver into a real regulator consumer
that uses the proper regulator APIs instead of the MSM specific
rpm_vreg API.

Doing this also requires us to make clk_set_rate() a sleeping
call so that concurrent clk_prepare() and clk_set_rate() calls
are synchronized. Making clk_set_rate() sleepable also
necessitates moving the clk_set_rate() call in clock-voter.c to a
sleepable context. Do that by having clock-voter aggregate and
update the rate in prepare/unprepare instead of enable/disable
(note that enable/disable of voter clocks implicitly calls
enable/disable on the parent via generic clock code).

Now that clk_set_rate() is sleeping, call clk_prepare() and
clk_unprepare() in the clock-local code when a rate change
requires reparenting the clock. This cleans up a problem we have
where sources may be left unprepared by a clock rate switch
(hence the default true warned flag for PLLs and crystals).

Change-Id: I493a00261055001a68fa884daa52e3d281ec6a2d
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 373cf47..2ec4e38 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -2883,6 +2883,7 @@
 };
 
 struct pix_rdi_clk {
+	bool prepared;
 	bool enabled;
 	unsigned long cur_rate;
 
@@ -2908,6 +2909,7 @@
 	unsigned long flags;
 	struct pix_rdi_clk *rdi = to_pix_rdi_clk(c);
 	struct clk **mux_map = pix_rdi_mux_map;
+	unsigned long old_rate = rdi->cur_rate;
 
 	/*
 	 * These clocks select three inputs via two muxes. One mux selects
@@ -2918,7 +2920,7 @@
 	 * needs to be on at what time.
 	 */
 	for (i = 0; mux_map[i]; i++) {
-		ret = clk_enable(mux_map[i]);
+		ret = clk_prepare_enable(mux_map[i]);
 		if (ret)
 			goto err;
 	}
@@ -2927,11 +2929,21 @@
 		goto err;
 	}
 	/* Keep the new source on when switching inputs of an enabled clock */
-	if (rdi->enabled) {
-		clk_disable(mux_map[rdi->cur_rate]);
-		clk_enable(mux_map[rate]);
+	if (rdi->prepared) {
+		ret = clk_prepare(mux_map[rate]);
+		if (ret)
+			goto err;
 	}
-	spin_lock_irqsave(&local_clock_reg_lock, flags);
+	spin_lock_irqsave(&c->lock, flags);
+	if (rdi->enabled) {
+		ret = clk_enable(mux_map[rate]);
+		if (ret) {
+			spin_unlock_irqrestore(&c->lock, flags);
+			clk_unprepare(mux_map[rate]);
+			goto err;
+		}
+	}
+	spin_lock(&local_clock_reg_lock);
 	reg = readl_relaxed(rdi->s2_reg);
 	reg &= ~rdi->s2_mask;
 	reg |= rate == 2 ? rdi->s2_mask : 0;
@@ -2953,10 +2965,16 @@
 	mb();
 	udelay(1);
 	rdi->cur_rate = rate;
-	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+	spin_unlock(&local_clock_reg_lock);
+
+	if (rdi->enabled)
+		clk_disable(mux_map[old_rate]);
+	spin_unlock_irqrestore(&c->lock, flags);
+	if (rdi->prepared)
+		clk_unprepare(mux_map[old_rate]);
 err:
 	for (i--; i >= 0; i--)
-		clk_disable(mux_map[i]);
+		clk_disable_unprepare(mux_map[i]);
 
 	return 0;
 }
@@ -2966,6 +2984,13 @@
 	return to_pix_rdi_clk(c)->cur_rate;
 }
 
+static int pix_rdi_clk_prepare(struct clk *c)
+{
+	struct pix_rdi_clk *rdi = to_pix_rdi_clk(c);
+	rdi->prepared = true;
+	return 0;
+}
+
 static int pix_rdi_clk_enable(struct clk *c)
 {
 	unsigned long flags;
@@ -2990,6 +3015,12 @@
 	rdi->enabled = false;
 }
 
+static void pix_rdi_clk_unprepare(struct clk *c)
+{
+	struct pix_rdi_clk *rdi = to_pix_rdi_clk(c);
+	rdi->prepared = false;
+}
+
 static int pix_rdi_clk_reset(struct clk *c, enum clk_reset_action action)
 {
 	return branch_reset(&to_pix_rdi_clk(c)->b, action);
@@ -3026,8 +3057,10 @@
 }
 
 static struct clk_ops clk_ops_pix_rdi_8960 = {
+	.prepare = pix_rdi_clk_prepare,
 	.enable = pix_rdi_clk_enable,
 	.disable = pix_rdi_clk_disable,
+	.unprepare = pix_rdi_clk_unprepare,
 	.handoff = pix_rdi_clk_handoff,
 	.set_rate = pix_rdi_clk_set_rate,
 	.get_rate = pix_rdi_clk_get_rate,
diff --git a/arch/arm/mach-msm/clock-local.c b/arch/arm/mach-msm/clock-local.c
index 2df1cd1..b952f2f 100644
--- a/arch/arm/mach-msm/clock-local.c
+++ b/arch/arm/mach-msm/clock-local.c
@@ -320,10 +320,6 @@
 	u32 reg_val;
 	void __iomem *const reg = rcg->b.ctl_reg;
 
-	WARN(rcg->current_freq == &rcg_dummy_freq,
-		"Attempting to enable %s before setting its rate. "
-		"Set the rate first!\n", rcg->c.dbg_name);
-
 	/*
 	 * Program the NS register, if applicable. NS registers are not
 	 * set in the set_rate path because power can be saved by deferring
@@ -419,6 +415,18 @@
 	}
 }
 
+static int rcg_clk_prepare(struct clk *c)
+{
+	struct rcg_clk *rcg = to_rcg_clk(c);
+
+	WARN(rcg->current_freq == &rcg_dummy_freq,
+		"Attempting to prepare %s before setting its rate. "
+		"Set the rate first!\n", rcg->c.dbg_name);
+	rcg->prepared = true;
+
+	return 0;
+}
+
 /* Enable a rate-settable clock. */
 static int rcg_clk_enable(struct clk *c)
 {
@@ -445,6 +453,12 @@
 	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
 }
 
+static void rcg_clk_unprepare(struct clk *c)
+{
+	struct rcg_clk *rcg = to_rcg_clk(c);
+	rcg->prepared = false;
+}
+
 /*
  * Frequency-related functions
  */
@@ -456,6 +470,7 @@
 	struct clk_freq_tbl *nf, *cf;
 	struct clk *chld;
 	int rc = 0;
+	unsigned long flags;
 
 	for (nf = rcg->freq_tbl; nf->freq_hz != FREQ_END
 			&& nf->freq_hz != rate; nf++)
@@ -466,11 +481,22 @@
 
 	cf = rcg->current_freq;
 
-	if (rcg->enabled) {
-		/* Enable source clock dependency for the new freq. */
-		rc = clk_enable(nf->src_clk);
+	/* Enable source clock dependency for the new frequency */
+	if (rcg->prepared) {
+		rc = clk_prepare(nf->src_clk);
 		if (rc)
 			return rc;
+
+	}
+
+	spin_lock_irqsave(&c->lock, flags);
+	if (rcg->enabled) {
+		rc = clk_enable(nf->src_clk);
+		if (rc) {
+			spin_unlock_irqrestore(&c->lock, flags);
+			clk_unprepare(nf->src_clk);
+			return rc;
+		}
 	}
 
 	spin_lock(&local_clock_reg_lock);
@@ -519,6 +545,10 @@
 	/* Release source requirements of the old freq. */
 	if (rcg->enabled)
 		clk_disable(cf->src_clk);
+	spin_unlock_irqrestore(&c->lock, flags);
+
+	if (rcg->prepared)
+		clk_unprepare(cf->src_clk);
 
 	return rc;
 }
@@ -819,8 +849,10 @@
 }
 
 struct clk_ops clk_ops_rcg = {
+	.prepare = rcg_clk_prepare,
 	.enable = rcg_clk_enable,
 	.disable = rcg_clk_disable,
+	.unprepare = rcg_clk_unprepare,
 	.enable_hwcg = rcg_clk_enable_hwcg,
 	.disable_hwcg = rcg_clk_disable_hwcg,
 	.in_hwcg_mode = rcg_clk_in_hwcg_mode,
diff --git a/arch/arm/mach-msm/clock-local.h b/arch/arm/mach-msm/clock-local.h
index 034e09c..81085ef 100644
--- a/arch/arm/mach-msm/clock-local.h
+++ b/arch/arm/mach-msm/clock-local.h
@@ -164,6 +164,7 @@
  * Generic clock-definition struct and macros
  */
 struct rcg_clk {
+	bool		prepared;
 	bool		enabled;
 	void		*const ns_reg;
 	void		*const md_reg;
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index 42b36f6..3f19b2a 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -148,12 +148,12 @@
 	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
 }
 
-static int rcg_clk_enable(struct clk *c)
+static int rcg_clk_prepare(struct clk *c)
 {
 	struct rcg_clk *rcg = to_rcg_clk(c);
 
 	WARN(rcg->current_freq == &rcg_dummy_freq,
-		"Attempting to enable %s before setting its rate. "
+		"Attempting to prepare %s before setting its rate. "
 		"Set the rate first!\n", rcg->c.dbg_name);
 
 	return 0;
@@ -163,7 +163,8 @@
 {
 	struct clk_freq_tbl *cf, *nf;
 	struct rcg_clk *rcg = to_rcg_clk(c);
-	int rc = 0;
+	int rc;
+	unsigned long flags;
 
 	for (nf = rcg->freq_tbl; nf->freq_hz != FREQ_END
 			&& nf->freq_hz != rate; nf++)
@@ -174,12 +175,21 @@
 
 	cf = rcg->current_freq;
 
-	if (rcg->c.count) {
-		/* TODO: Modify to use the prepare API */
-		/* Enable source clock dependency for the new freq. */
-		rc = clk_enable(nf->src_clk);
+	/* Enable source clock dependency for the new freq. */
+	if (c->prepare_count) {
+		rc = clk_prepare(nf->src_clk);
 		if (rc)
-			goto out;
+			return rc;
+	}
+
+	spin_lock_irqsave(&c->lock, flags);
+	if (c->count) {
+		rc = clk_enable(nf->src_clk);
+		if (rc) {
+			spin_unlock_irqrestore(&c->lock, flags);
+			clk_unprepare(nf->src_clk);
+			return rc;
+		}
 	}
 
 	BUG_ON(!rcg->set_rate);
@@ -188,12 +198,16 @@
 	rcg->set_rate(rcg, nf);
 
 	/* Release source requirements of the old freq. */
-	if (rcg->c.count)
+	if (c->count)
 		clk_disable(cf->src_clk);
+	spin_unlock_irqrestore(&c->lock, flags);
+
+	if (c->prepare_count)
+		clk_unprepare(cf->src_clk);
 
 	rcg->current_freq = nf;
-out:
-	return rc;
+
+	return 0;
 }
 
 /* Return a supported rate that's at least the specified rate. */
@@ -585,7 +599,7 @@
 struct clk_ops clk_ops_empty;
 
 struct clk_ops clk_ops_rcg = {
-	.enable = rcg_clk_enable,
+	.enable = rcg_clk_prepare,
 	.set_rate = rcg_clk_set_rate,
 	.list_rate = rcg_clk_list_rate,
 	.round_rate = rcg_clk_round_rate,
@@ -594,7 +608,7 @@
 };
 
 struct clk_ops clk_ops_rcg_mnd = {
-	.enable = rcg_clk_enable,
+	.enable = rcg_clk_prepare,
 	.set_rate = rcg_clk_set_rate,
 	.list_rate = rcg_clk_list_rate,
 	.round_rate = rcg_clk_round_rate,
diff --git a/arch/arm/mach-msm/clock-voter.c b/arch/arm/mach-msm/clock-voter.c
index 4cd9b1c..3e1cbb9 100644
--- a/arch/arm/mach-msm/clock-voter.c
+++ b/arch/arm/mach-msm/clock-voter.c
@@ -12,13 +12,13 @@
  */
 
 #include <linux/err.h>
-#include <linux/spinlock.h>
+#include <linux/mutex.h>
 #include <linux/clk.h>
 
 #include "clock.h"
 #include "clock-voter.h"
 
-static DEFINE_SPINLOCK(voter_clk_lock);
+static DEFINE_MUTEX(voter_clk_lock);
 
 /* Aggregate the rate of clocks that are currently on. */
 static unsigned long voter_clk_aggregate_rate(const struct clk *parent)
@@ -37,12 +37,11 @@
 static int voter_clk_set_rate(struct clk *clk, unsigned long rate)
 {
 	int ret = 0;
-	unsigned long flags;
 	struct clk *clkp;
 	struct clk_voter *clkh, *v = to_clk_voter(clk);
 	unsigned long cur_rate, new_rate, other_rate = 0;
 
-	spin_lock_irqsave(&voter_clk_lock, flags);
+	mutex_lock(&voter_clk_lock);
 
 	if (v->enabled) {
 		struct clk *parent = v->parent;
@@ -68,20 +67,19 @@
 	}
 	clk->rate = rate;
 unlock:
-	spin_unlock_irqrestore(&voter_clk_lock, flags);
+	mutex_unlock(&voter_clk_lock);
 
 	return ret;
 }
 
-static int voter_clk_enable(struct clk *clk)
+static int voter_clk_prepare(struct clk *clk)
 {
 	int ret = 0;
-	unsigned long flags;
 	unsigned long cur_rate;
 	struct clk *parent;
 	struct clk_voter *v = to_clk_voter(clk);
 
-	spin_lock_irqsave(&voter_clk_lock, flags);
+	mutex_lock(&voter_clk_lock);
 	parent = v->parent;
 
 	/*
@@ -96,18 +94,18 @@
 	}
 	v->enabled = true;
 out:
-	spin_unlock_irqrestore(&voter_clk_lock, flags);
+	mutex_unlock(&voter_clk_lock);
 
 	return ret;
 }
 
-static void voter_clk_disable(struct clk *clk)
+static void voter_clk_unprepare(struct clk *clk)
 {
-	unsigned long flags, cur_rate, new_rate;
+	unsigned long cur_rate, new_rate;
 	struct clk *parent;
 	struct clk_voter *v = to_clk_voter(clk);
 
-	spin_lock_irqsave(&voter_clk_lock, flags);
+	mutex_lock(&voter_clk_lock);
 	parent = v->parent;
 
 	/*
@@ -121,7 +119,7 @@
 	if (new_rate < cur_rate)
 		clk_set_rate(parent, new_rate);
 
-	spin_unlock_irqrestore(&voter_clk_lock, flags);
+	mutex_unlock(&voter_clk_lock);
 }
 
 static int voter_clk_is_enabled(struct clk *clk)
@@ -157,8 +155,8 @@
 }
 
 struct clk_ops clk_ops_voter = {
-	.enable = voter_clk_enable,
-	.disable = voter_clk_disable,
+	.prepare = voter_clk_prepare,
+	.unprepare = voter_clk_unprepare,
 	.set_rate = voter_clk_set_rate,
 	.is_enabled = voter_clk_is_enabled,
 	.round_rate = voter_clk_round_rate,
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index f605c1f..a0367b0 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -156,6 +156,9 @@
 		if (ret)
 			goto err_prepare_depends;
 
+		ret = vote_rate_vdd(clk, clk->rate);
+		if (ret)
+			goto err_vote_vdd;
 		if (clk->ops->prepare)
 			ret = clk->ops->prepare(clk);
 		if (ret)
@@ -166,6 +169,8 @@
 	mutex_unlock(&clk->prepare_lock);
 	return ret;
 err_prepare_clock:
+	unvote_rate_vdd(clk, clk->rate);
+err_vote_vdd:
 	clk_unprepare(clk->depends);
 err_prepare_depends:
 	clk_unprepare(parent);
@@ -202,9 +207,6 @@
 		if (ret)
 			goto err_enable_depends;
 
-		ret = vote_rate_vdd(clk, clk->rate);
-		if (ret)
-			goto err_vote_vdd;
 		trace_clock_enable(clk->dbg_name, 1, smp_processor_id());
 		if (clk->ops->enable)
 			ret = clk->ops->enable(clk);
@@ -217,8 +219,6 @@
 	return 0;
 
 err_enable_clock:
-	unvote_rate_vdd(clk, clk->rate);
-err_vote_vdd:
 	clk_disable(clk->depends);
 err_enable_depends:
 	clk_disable(parent);
@@ -249,7 +249,6 @@
 		trace_clock_disable(clk->dbg_name, 0, smp_processor_id());
 		if (clk->ops->disable)
 			clk->ops->disable(clk);
-		unvote_rate_vdd(clk, clk->rate);
 		clk_disable(clk->depends);
 		clk_disable(parent);
 	}
@@ -281,6 +280,7 @@
 
 		if (clk->ops->unprepare)
 			clk->ops->unprepare(clk);
+		unvote_rate_vdd(clk, clk->rate);
 		clk_unprepare(clk->depends);
 		clk_unprepare(parent);
 	}
@@ -316,7 +316,7 @@
 
 int clk_set_rate(struct clk *clk, unsigned long rate)
 {
-	unsigned long start_rate, flags;
+	unsigned long start_rate;
 	int rc = 0;
 
 	if (IS_ERR_OR_NULL(clk))
@@ -325,14 +325,14 @@
 	if (!clk->ops->set_rate)
 		return -ENOSYS;
 
-	spin_lock_irqsave(&clk->lock, flags);
+	mutex_lock(&clk->prepare_lock);
 
 	/* Return early if the rate isn't going to change */
 	if (clk->rate == rate)
 		goto out;
 
-	trace_clock_set_rate(clk->dbg_name, rate, smp_processor_id());
-	if (clk->count) {
+	trace_clock_set_rate(clk->dbg_name, rate, raw_smp_processor_id());
+	if (clk->prepare_count) {
 		start_rate = clk->rate;
 		/* Enforce vdd requirements for target frequency. */
 		rc = vote_rate_vdd(clk, rate);
@@ -350,14 +350,13 @@
 	if (!rc)
 		clk->rate = rate;
 out:
-	spin_unlock_irqrestore(&clk->lock, flags);
+	mutex_unlock(&clk->prepare_lock);
 	return rc;
 
 err_set_rate:
 	unvote_rate_vdd(clk, rate);
 err_vote_vdd:
-	spin_unlock_irqrestore(&clk->lock, flags);
-	return rc;
+	goto out;
 }
 EXPORT_SYMBOL(clk_set_rate);