diff mbox

[PATCHV2,2/2] OMAP3630: Clock: Fixing HSDivider Limitation

Message ID E0D41E29EB0DAC4E9F3FF173962E9E94026B2DBC17@dbde02.ent.ti.com (mailing list archive)
State Changes Requested, archived
Delegated to: Paul Walmsley
Headers show

Commit Message

G.N, Vijayakumar Jan. 18, 2010, 12:36 p.m. UTC
None
diff mbox

Patch

diff --git a/arch/arm/mach-omap2/clock34xx.c b/arch/arm/mach-omap2/clock34xx.c
index 0d30e53..e5213f8 100644
--- a/arch/arm/mach-omap2/clock34xx.c
+++ b/arch/arm/mach-omap2/clock34xx.c
@@ -146,6 +146,42 @@  const struct clkops clkops_omap3430es2_hsotgusb_wait = {
 	.find_companion = omap2_clk_dflt_find_companion,
 };
 
+/** omap3_pwrdn_clk_enable_with_hsdiv_restore - enable clocks suffering
+ *         from HSDivider problem.
+ * @clk: DPLL output struct clk
+ *
+ * 3630 only: dpll3_m3_ck, dpll4_m2_ck, dpll4_m3_ck, dpll4_m4_ck, dpll4_m5_ck
+ * & dpll4_m6_ck dividers get lost after their respective PWRDN bits are set.
+ * Any write to the corresponding CM_CLKSEL register will refresh the
+ * dividers.  Only x2 clocks are affected, so it is safe to trust the parent
+ * clock information to refresh the CM_CLKSEL registers.
+ */
+int omap3_pwrdn_clk_enable_with_hsdiv_restore(struct clk *clk)
+{
+	u32 v;
+	int ret;
+
+	/* enable the clock */
+	ret = omap2_dflt_clk_enable(clk);
+
+	/* Restore the dividers */
+	if (!ret) {
+		v = __raw_readl(clk->parent->clksel_reg);
+		v += (1 << clk->parent->clksel_shift);
+		__raw_writel(v, clk->parent->clksel_reg);
+		v -= (1 << clk->parent->clksel_shift);
+		__raw_writel(v, clk->parent->clksel_reg);
+	}
+	return ret;
+}
+
+const struct clkops clkops_omap3_pwrdn_with_hsdiv_wait_restore = {
+	.enable		= omap3_pwrdn_clk_enable_with_hsdiv_restore,
+	.disable	= omap2_dflt_clk_disable,
+	.find_companion	= omap2_clk_dflt_find_companion,
+	.find_idlest	= omap2_clk_dflt_find_idlest,
+};
+
 const struct clkops clkops_noncore_dpll_ops = {
 	.enable		= omap3_noncore_dpll_enable,
 	.disable	= omap3_noncore_dpll_disable,
diff --git a/arch/arm/mach-omap2/clock34xx.h b/arch/arm/mach-omap2/clock34xx.h
index 9a2c07e..6f7d271 100644
--- a/arch/arm/mach-omap2/clock34xx.h
+++ b/arch/arm/mach-omap2/clock34xx.h
@@ -20,5 +20,6 @@  extern const struct clkops clkops_omap3430es2_ssi_wait;
 extern const struct clkops clkops_omap3430es2_hsotgusb_wait;
 extern const struct clkops clkops_omap3430es2_dss_usbhost_wait;
 extern const struct clkops clkops_noncore_dpll_ops;
+extern const struct clkops clkops_omap3_pwrdn_with_hsdiv_wait_restore;
 
 #endif
diff --git a/arch/arm/mach-omap2/clock34xx_data.c b/arch/arm/mach-omap2/clock34xx_data.c
index 955d4ef..39a1b3c 100755
--- a/arch/arm/mach-omap2/clock34xx_data.c
+++ b/arch/arm/mach-omap2/clock34xx_data.c
@@ -3447,6 +3447,21 @@  int __init omap2_clk_init(void)
 		dpll4_m4_ck = dpll4_m4_ck_3630;
 		dpll4_m5_ck = dpll4_m5_ck_3630;
 		dpll4_m6_ck = dpll4_m6_ck_3630;
+
+		/* For 3630: override clkops_omap2_dflt_wait for the
+		 * clocks affected from HSDivider PWRDN reset limitation */
+		dpll3_m3x2_ck.ops =
+			&clkops_omap3_pwrdn_with_hsdiv_wait_restore;
+		dpll4_m2x2_ck.ops =
+			&clkops_omap3_pwrdn_with_hsdiv_wait_restore;
+		dpll4_m3x2_ck.ops =
+			&clkops_omap3_pwrdn_with_hsdiv_wait_restore;
+		dpll4_m4x2_ck.ops =
+			&clkops_omap3_pwrdn_with_hsdiv_wait_restore;
+		dpll4_m5x2_ck.ops =
+			&clkops_omap3_pwrdn_with_hsdiv_wait_restore;
+		dpll4_m6x2_ck.ops =
+			&clkops_omap3_pwrdn_with_hsdiv_wait_restore;
 	} else {
 		dpll4_dd = dpll4_dd_34xx;
 		dpll4_m2_ck = dpll4_m2_ck_34xx;