msm: clock: Improve clock handoff code.
The current clock handoff code hands off the child clock before handing off
the parent clock. That is technically incorrect since the state and rate of
a clock can't be determined without knowing the state and rate of the
source/parent clock. But this works alright for now since the handoff code
forcefully enables the necessary parent and also assumes that if a clock
has multiple parents, the rates of all those parents are fixed. As we
implement more clocks, this assumption no longer holds true.
The current handoff code also causes the prepare and enable ops to be
called for an already enabled clock. The hardware read/writes caused by
this might not be harmful in the case of most clock hardware designs, but
is not always the case. Eg: PLLs, I2C clocks, etc.
To address these issues, rewrite the clock handoff code so that the parent
clock is identified first, it's handed off and then the child clock is
handed off. Also, when an already enabled clock is handed off, just
directly update the software state of the clock and don't call the ops to
update the hardware. To make sure the parent clock's reference counts are
updated correctly, call clk_prepare_enable() on the parent clock.
This change also has the nice effect of avoiding any "clock stuck off/on"
warnings during boot that are caused by the boot code configuring the
clocks incorrectly (parent off, child on). This is because we don't
actually call the prepare/enable ops and also make sure the parent clocks
is on before calling the handoff code for the child clock.
Change-Id: I385a2afaf62a4138d53048f675822e079be2fcca
Signed-off-by: Saravana Kannan <skannan@codeaurora.org>
diff --git a/arch/arm/mach-msm/clock-voter.c b/arch/arm/mach-msm/clock-voter.c
index 7421ba6..c3145ef 100644
--- a/arch/arm/mach-msm/clock-voter.c
+++ b/arch/arm/mach-msm/clock-voter.c
@@ -1,5 +1,4 @@
-/*
- * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -139,11 +138,17 @@
static enum handoff voter_clk_handoff(struct clk *clk)
{
- /* Apply default rate vote */
- if (clk->rate)
- return HANDOFF_ENABLED_CLK;
+ if (!clk->rate)
+ return HANDOFF_DISABLED_CLK;
- return HANDOFF_DISABLED_CLK;
+ /*
+ * Send the default rate to the parent if necessary and update the
+ * software state of the voter clock.
+ */
+ if (voter_clk_prepare(clk) < 0)
+ return HANDOFF_DISABLED_CLK;
+
+ return HANDOFF_ENABLED_CLK;
}
struct clk_ops clk_ops_voter = {