msm: clock: Add hardware gating support to branch clocks

Add support for hardware clock gating on branch clocks. Do this
in a few steps:

 o At clock registration time, check to see if the branch is not
   in hardware gated mode and fix up the branch data structure
   as appropriate

 o When a clk_reset() is asserted take the branch out of
   hardware control so the reset can propagate if the clock
   is enabled

 o When a clk_reset() is deasserted put the branch back into
   hardware control

Add three new ops to the clk_ops structure to support the above.

	void (*enable_hwcg)(struct clk *clk);
	void (*disable_hwcg)(struct clk *clk);
	int (*in_hwcg_mode)(struct clk *clk);

{enable,disable}_hwcg() should enable and disable hardware clock
gating if possible. in_hwcg_mode() should return either a
non-zero value or a zero indicating whether the clock is
currently in hardware gating mode or not in hardware gating mode
respectively.

Use in_hwcg_mode() to detect when to skip the halt checks for a
branch and when to disable/enable hardware gating mode while
measuring clocks. This is particularly important for measurement
because we don't want to put a clock into hardware gating mode
accidentally after we measure the clock if the clock wasn't in
hardware gating mode to begin with.

Also expose a debugfs node indicating whether or not this clock
supports hardware gating. This should aid in debugging problems
due to hardware gating.

Change-Id: Id9b2d83adcc6dabe2544f48ef0b4d752d9a5c5c1
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
diff --git a/arch/arm/mach-msm/clock-local.h b/arch/arm/mach-msm/clock-local.h
index 31f64ce..a561802d 100644
--- a/arch/arm/mach-msm/clock-local.h
+++ b/arch/arm/mach-msm/clock-local.h
@@ -90,6 +90,8 @@
  * struct branch - branch on/off
  * @ctl_reg: clock control register
  * @en_mask: ORed with @ctl_reg to enable the clock
+ * @hwcg_reg: hardware clock gating register
+ * @hwcg_mask: ORed with @hwcg_reg to enable hardware clock gating
  * @halt_reg: halt register
  * @halt_check: type of halt check to perform
  * @halt_bit: ANDed with @halt_reg to test for clock halted
@@ -100,6 +102,9 @@
 	void __iomem *const ctl_reg;
 	const u32 en_mask;
 
+	void __iomem *hwcg_reg;
+	u32 hwcg_mask;
+
 	void __iomem *const halt_reg;
 	const u16 halt_check;
 	const u16 halt_bit;
@@ -108,9 +113,10 @@
 	const u32 reset_mask;
 };
 
-int branch_reset(struct branch *clk, enum clk_reset_action action);
+int branch_reset(struct branch *b, enum clk_reset_action action);
 void __branch_clk_enable_reg(const struct branch *clk, const char *name);
 u32 __branch_clk_disable_reg(const struct branch *clk, const char *name);
+int branch_clk_handoff(struct clk *c);
 
 /*
  * Generic clock-definition struct and macros
@@ -151,6 +157,9 @@
 struct clk *rcg_clk_get_parent(struct clk *c);
 int rcg_clk_handoff(struct clk *c);
 int rcg_clk_reset(struct clk *clk, enum clk_reset_action action);
+void rcg_clk_enable_hwcg(struct clk *clk);
+void rcg_clk_disable_hwcg(struct clk *clk);
+int rcg_clk_in_hwcg_mode(struct clk *c);
 
 /**
  * struct cdiv_clk - integer divider clock with external source selection
@@ -287,6 +296,9 @@
 int branch_clk_set_parent(struct clk *clk, struct clk *parent);
 int branch_clk_is_enabled(struct clk *clk);
 int branch_clk_reset(struct clk *c, enum clk_reset_action action);
+void branch_clk_enable_hwcg(struct clk *clk);
+void branch_clk_disable_hwcg(struct clk *clk);
+int branch_clk_in_hwcg_mode(struct clk *c);
 
 /**
  * struct measure_clk - for rate measurement debug use