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,