msm: clock-8x60: Allow hand-offs of already-running RCG clocks at boot
Inherit the rate of running rate-settable clocks at boot if the
same rate is supported by the Linux kernel. These clocks will
still be disabled by the auto-off code in late-init if no driver
explicitly enables them before that.
This feature allows Linux drivers to keep a clock enabled all the
way through boot. For glitch-free clocks, drivers can set the
rate of the clock to any supported value at boot and enable it
with no interruption of the clock signal. Non-glitch-free clocks
will still experience some interruption, but this can be avoided
by calling clk_set_rate() with the same rate that was set by the
bootloader (which can be returned by calling clk_get_rate()).
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 c145240..a29e9cd 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -49,6 +49,15 @@
clk_disable(parent);
goto out;
}
+ } else if (clk->flags & CLKFLAG_HANDOFF_RATE) {
+ /*
+ * The clock was already enabled by handoff code so there is no
+ * need to enable it again here. Clearing the handoff flag will
+ * prevent the lateinit handoff code from disabling the clock if
+ * a client driver still has it enabled.
+ */
+ clk->flags &= ~CLKFLAG_HANDOFF_RATE;
+ goto out;
}
clk->count++;
out:
@@ -180,6 +189,8 @@
struct clk *clk = clock_tbl[n].clk;
struct clk *parent = clk_get_parent(clk);
clk_set_parent(clk, parent);
+ if (clk->ops->handoff)
+ clk->ops->handoff(clk);
}
clkdev_add_table(clock_tbl, num_clocks);
@@ -199,6 +210,7 @@
clock_debug_init(clk_init_data);
for (n = 0; n < clk_init_data->size; n++) {
struct clk *clk = clk_init_data->table[n].clk;
+ bool handoff = false;
clock_debug_add(clk);
if (!(clk->flags & CLKFLAG_SKIP_AUTO_OFF)) {
@@ -207,7 +219,17 @@
count++;
clk->ops->auto_off(clk);
}
+ if (clk->flags & CLKFLAG_HANDOFF_RATE) {
+ clk->flags &= ~CLKFLAG_HANDOFF_RATE;
+ handoff = true;
+ }
spin_unlock_irqrestore(&clk->lock, flags);
+ /*
+ * Calling clk_disable() outside the lock is safe since
+ * it doesn't need to be atomic with the flag change.
+ */
+ if (handoff)
+ clk_disable(clk);
}
}
pr_info("clock_late_init() disabled %d unused clocks\n", count);