Merge "msm_xo: Work around RPM treating CXO_CLK and D0 as the same" into msm-3.0
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 119f89c..9ab630d 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -4865,6 +4865,7 @@
 	CLK_LOOKUP("xo",		cxo_clk.c,	"pil_qdsp6v4.2"),
 	CLK_LOOKUP("xo",		cxo_clk.c,	"pil_gss"),
 	CLK_LOOKUP("xo",		cxo_clk.c,	"BAM_RMNT"),
+	CLK_LOOKUP("xo",		cxo_clk.c,	"msm_xo"),
 	CLK_LOOKUP("pll2",		pll2_clk.c,	NULL),
 	CLK_LOOKUP("pll8",		pll8_clk.c,	NULL),
 	CLK_LOOKUP("pll4",		pll4_clk.c,	NULL),
@@ -5147,6 +5148,7 @@
 	CLK_LOOKUP("xo",		cxo_clk.c,	"pil_qdsp6v4.1"),
 	CLK_LOOKUP("xo",		cxo_clk.c,	"pil_qdsp6v4.2"),
 	CLK_LOOKUP("xo",		cxo_clk.c,	"BAM_RMNT"),
+	CLK_LOOKUP("xo",		cxo_clk.c,	"msm_xo"),
 	CLK_LOOKUP("pll2",		pll2_clk.c,	NULL),
 	CLK_LOOKUP("pll8",		pll8_clk.c,	NULL),
 	CLK_LOOKUP("pll4",		pll4_clk.c,	NULL),
diff --git a/arch/arm/mach-msm/clock-9615.c b/arch/arm/mach-msm/clock-9615.c
index 3e059b6..e1dc2ae 100644
--- a/arch/arm/mach-msm/clock-9615.c
+++ b/arch/arm/mach-msm/clock-9615.c
@@ -1602,6 +1602,7 @@
 	CLK_LOOKUP("xo",	cxo_a_clk.c,	""),
 	CLK_LOOKUP("xo",	cxo_clk.c,	"msm_otg"),
 	CLK_LOOKUP("xo",	cxo_clk.c,	"BAM_RMNT"),
+	CLK_LOOKUP("xo",	cxo_clk.c,	"msm_xo"),
 	CLK_LOOKUP("pll0",	pll0_clk.c,	NULL),
 	CLK_LOOKUP("pll8",	pll8_clk.c,	NULL),
 	CLK_LOOKUP("pll14",	pll14_clk.c,	NULL),
diff --git a/arch/arm/mach-msm/msm_xo.c b/arch/arm/mach-msm/msm_xo.c
index 936fd6b..86776d3 100644
--- a/arch/arm/mach-msm/msm_xo.c
+++ b/arch/arm/mach-msm/msm_xo.c
@@ -21,6 +21,7 @@
 #include <linux/seq_file.h>
 #include <linux/uaccess.h>
 #include <linux/string.h>
+#include <linux/clk.h>
 
 #include <mach/msm_xo.h>
 #include <mach/rpm.h>
@@ -232,6 +233,9 @@
 {
 	int ret;
 	struct msm_xo *xo = xo_voter->xo;
+	int is_d0 = xo == &msm_xo_sources[MSM_XO_TCXO_D0];
+	int needs_workaround = cpu_is_msm8960() || cpu_is_apq8064() ||
+			       cpu_is_msm8930() || cpu_is_msm9615();
 
 	if (xo_voter->mode == mode)
 		return 0;
@@ -244,6 +248,20 @@
 		xo->votes[mode]--;
 		goto out;
 	}
+	/* TODO: Remove once RPM separates the concept of D0 and CXO */
+	if (is_d0 && needs_workaround) {
+		static struct clk *xo_clk;
+
+		if (!xo_clk) {
+			xo_clk = clk_get_sys("msm_xo", "xo");
+			BUG_ON(IS_ERR(xo_clk));
+		}
+		/* Ignore transitions from pin to on or vice versa */
+		if (mode && xo_voter->mode == MSM_XO_MODE_OFF)
+			clk_enable(xo_clk);
+		else if (!mode)
+			clk_disable(xo_clk);
+	}
 	xo_voter->mode = mode;
 out:
 	return ret;