msm: acpuclock-7201: Convert to clock APIs for PLL control

Change-Id: I3270f3169e02cadf7e66e51edaa732555b1ff760
Signed-off-by: Pankaj Kumar <pakuma@codeaurora.org>
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 8347a25..f7cc4e3 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -23,7 +23,7 @@
 obj-y += acpuclock.o
 obj-$(CONFIG_ARCH_MSM7X01A) += acpuclock-7201.o
 obj-$(CONFIG_ARCH_MSM7X25) += acpuclock-7201.o
-obj-$(CONFIG_ARCH_MSM7X27) += acpuclock-7201.o
+obj-$(CONFIG_ARCH_MSM7X27) += acpuclock-7201.o clock-pll.o
 obj-$(CONFIG_ARCH_MSM_SCORPION) += pmu.o
 obj-$(CONFIG_ARCH_MSM_KRAIT) += msm-krait-l2-accessors.o pmu.o
 obj-$(CONFIG_ARCH_MSM7X27A) += pmu.o
diff --git a/arch/arm/mach-msm/acpuclock-7201.c b/arch/arm/mach-msm/acpuclock-7201.c
index 5a21407..c4409ff 100644
--- a/arch/arm/mach-msm/acpuclock-7201.c
+++ b/arch/arm/mach-msm/acpuclock-7201.c
@@ -27,7 +27,6 @@
 #include <linux/mutex.h>
 #include <linux/io.h>
 #include <linux/sort.h>
-#include <linux/remote_spinlock.h>
 #include <mach/board.h>
 #include <mach/msm_iomap.h>
 #include <asm/mach-types.h>
@@ -39,17 +38,16 @@
 #define A11S_CLK_CNTL_ADDR (MSM_CSR_BASE + 0x100)
 #define A11S_CLK_SEL_ADDR (MSM_CSR_BASE + 0x104)
 #define A11S_VDD_SVS_PLEVEL_ADDR (MSM_CSR_BASE + 0x124)
-#define PLLn_MODE(n)	(MSM_CLK_CTL_BASE + 0x300 + 28 * (n))
-#define PLLn_L_VAL(n)	(MSM_CLK_CTL_BASE + 0x304 + 28 * (n))
 
-#define PLL4_MODE	(MSM_CLK_CTL_BASE + 0x374)
-#define PLL4_L_VAL	(MSM_CLK_CTL_BASE + 0x378)
 
 #define POWER_COLLAPSE_KHZ 19200
 
 /* Max CPU frequency allowed by hardware while in standby waiting for an irq. */
 #define MAX_WAIT_FOR_IRQ_KHZ 128000
 
+/**
+ * enum - For acpuclock PLL IDs
+ */
 enum {
 	ACPU_PLL_TCXO	= -1,
 	ACPU_PLL_0	= 0,
@@ -60,15 +58,16 @@
 	ACPU_PLL_END,
 };
 
-static const struct pll {
-	void __iomem *mod_reg;
-	const uint32_t l_val_mask;
-} soc_pll[ACPU_PLL_END] = {
-	[ACPU_PLL_0] = {PLLn_MODE(ACPU_PLL_0), 0x3f},
-	[ACPU_PLL_1] = {PLLn_MODE(ACPU_PLL_1), 0x3f},
-	[ACPU_PLL_2] = {PLLn_MODE(ACPU_PLL_2), 0x3f},
-	[ACPU_PLL_3] = {PLLn_MODE(ACPU_PLL_3), 0x3f},
-	[ACPU_PLL_4] = {PLL4_MODE, 0x3ff},
+struct acpu_clk_src {
+	struct clk *clk;
+	const char *name;
+};
+
+static struct acpu_clk_src pll_clk[ACPU_PLL_END] = {
+	[ACPU_PLL_0] = { .name = "pll0_clk" },
+	[ACPU_PLL_1] = { .name = "pll1_clk" },
+	[ACPU_PLL_2] = { .name = "pll2_clk" },
+	[ACPU_PLL_4] = { .name = "pll4_clk" },
 };
 
 struct clock_state {
@@ -78,24 +77,6 @@
 	struct clk			*ebi1_clk;
 };
 
-#define PLL_BASE	7
-
-struct shared_pll_control {
-	uint32_t	version;
-	struct {
-		/* Denotes if the PLL is ON. Technically, this can be read
-		 * directly from the PLL registers, but this feild is here,
-		 * so let's use it.
-		 */
-		uint32_t	on;
-		/* One bit for each processor core. The application processor
-		 * is allocated bit position 1. All other bits should be
-		 * considered as votes from other processors.
-		 */
-		uint32_t	votes;
-	} pll[PLL_BASE + ACPU_PLL_END];
-};
-
 struct clkctl_acpu_speed {
 	unsigned int	use_for_scaling;
 	unsigned int	a11clk_khz;
@@ -112,8 +93,6 @@
 	struct clkctl_acpu_speed *up[ACPU_PLL_END];
 };
 
-static remote_spinlock_t pll_lock;
-static struct shared_pll_control *pll_control;
 static struct clock_state drv_state = { 0 };
 static struct clkctl_acpu_speed *acpu_freq_tbl;
 
@@ -329,26 +308,16 @@
 	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
 };
 
-#define PLL_0_MHZ	0
-#define PLL_196_MHZ	10
-#define PLL_245_MHZ	12
-#define PLL_589_MHZ	30
-#define PLL_737_MHZ	38
-#define PLL_800_MHZ	41
-#define PLL_960_MHZ	50
-#define PLL_1008_MHZ	52
-#define PLL_1200_MHZ	62
-
 #define PLL_CONFIG(m0, m1, m2, m4) { \
-	PLL_##m0##_MHZ, PLL_##m1##_MHZ, PLL_##m2##_MHZ, PLL_##m4##_MHZ, \
+	m0, m1, m2, m4, \
 	pll0_##m0##_pll1_##m1##_pll2_##m2##_pll4_##m4 \
 }
 
 struct pll_freq_tbl_map {
-	unsigned int	pll0_l;
-	unsigned int	pll1_l;
-	unsigned int	pll2_l;
-	unsigned int	pll4_l;
+	unsigned int	pll0_rate;
+	unsigned int	pll1_rate;
+	unsigned int	pll2_rate;
+	unsigned int	pll4_rate;
 	struct clkctl_acpu_speed *tbl;
 };
 
@@ -405,59 +374,6 @@
 }
 #endif
 
-static void pll_enable(void __iomem *addr, unsigned on)
-{
-	if (on) {
-		writel_relaxed(2, addr);
-		mb();
-		udelay(5);
-		writel_relaxed(6, addr);
-		mb();
-		udelay(50);
-		writel_relaxed(7, addr);
-	} else {
-		writel_relaxed(0, addr);
-	}
-}
-
-static int pc_pll_request(unsigned id, unsigned on)
-{
-	int res = 0;
-	on = !!on;
-
-	if (on)
-		pr_debug("Enabling PLL %d\n", id);
-	else
-		pr_debug("Disabling PLL %d\n", id);
-
-	if (id >= ACPU_PLL_END)
-		return -EINVAL;
-
-	remote_spin_lock(&pll_lock);
-	if (on) {
-		pll_control->pll[PLL_BASE + id].votes |= 2;
-		if (!pll_control->pll[PLL_BASE + id].on) {
-			pll_enable(soc_pll[id].mod_reg, 1);
-			pll_control->pll[PLL_BASE + id].on = 1;
-		}
-	} else {
-		pll_control->pll[PLL_BASE + id].votes &= ~2;
-		if (pll_control->pll[PLL_BASE + id].on
-		    && !pll_control->pll[PLL_BASE + id].votes) {
-			pll_enable(soc_pll[id].mod_reg, 0);
-			pll_control->pll[PLL_BASE + id].on = 0;
-		}
-	}
-	remote_spin_unlock(&pll_lock);
-
-	if (on)
-		pr_debug("PLL enabled\n");
-	else
-		pr_debug("PLL disabled\n");
-
-	return res;
-}
-
 static int acpuclk_set_vdd_level(int vdd)
 {
 	uint32_t current_vdd;
@@ -576,7 +492,7 @@
 
 	if (reason == SETRATE_CPUFREQ) {
 		if (strt_s->pll != tgt_s->pll && tgt_s->pll != ACPU_PLL_TCXO) {
-			rc = pc_pll_request(tgt_s->pll, 1);
+			rc = clk_prepare_enable(pll_clk[tgt_s->pll].clk);
 			if (rc < 0) {
 				pr_err("PLL%d enable failed (%d)\n",
 					tgt_s->pll, rc);
@@ -651,7 +567,7 @@
 
 		if (cur_s->pll != ACPU_PLL_TCXO
 		    && !(plls_enabled & (1 << cur_s->pll))) {
-			rc = pc_pll_request(cur_s->pll, 1);
+			rc = clk_prepare_enable(pll_clk[cur_s->pll].clk);
 			if (rc < 0) {
 				pr_err("PLL%d enable failed (%d)\n",
 					cur_s->pll, rc);
@@ -684,12 +600,8 @@
 	if (tgt_s->pll != ACPU_PLL_TCXO)
 		plls_enabled &= ~(1 << tgt_s->pll);
 	for (pll = ACPU_PLL_0; pll < ACPU_PLL_END; pll++)
-		if (plls_enabled & (1 << pll)) {
-			res = pc_pll_request(pll, 0);
-			if (res < 0)
-				pr_warning("PLL%d disable failed (%d)\n",
-						pll, res);
-		}
+		if (plls_enabled & (1 << pll))
+			clk_disable_unprepare(pll_clk[pll].clk);
 
 	/* Nothing else to do for power collapse. */
 	if (reason == SETRATE_PC)
@@ -742,9 +654,10 @@
 	}
 
 	drv_state.current_speed = speed;
-	if (speed->pll != ACPU_PLL_TCXO)
-		if (pc_pll_request(speed->pll, 1))
+	if (speed->pll != ACPU_PLL_TCXO) {
+		if (clk_prepare_enable(pll_clk[speed->pll].clk))
 			pr_warning("Failed to vote for boot PLL\n");
+	}
 
 	/* Fix div2 to 2 for 7x27/5a(aa) targets */
 	if (!cpu_is_msm7x27()) {
@@ -777,64 +690,52 @@
 /*----------------------------------------------------------------------------
  * Clock driver initialization
  *---------------------------------------------------------------------------*/
-
-static void __init acpu_freq_tbl_fixup(void)
+#define MHZ 1000000
+static void __init select_freq_plan(void)
 {
-	unsigned long pll0_l, pll1_l, pll2_l, pll4_l;
-	struct pll_freq_tbl_map *lst;
+	unsigned long pll_mhz[ACPU_PLL_END];
+	struct pll_freq_tbl_map *t;
+	int i;
 
-	/* Wait for the PLLs to be initialized and then read their frequency.
-	 */
-	do {
-		pll0_l = readl_relaxed(PLLn_L_VAL(0)) &
-				soc_pll[ACPU_PLL_0].l_val_mask;
-		cpu_relax();
-		udelay(50);
-	} while (pll0_l == 0);
-	do {
-		pll1_l = readl_relaxed(PLLn_L_VAL(1)) &
-				soc_pll[ACPU_PLL_1].l_val_mask;
-		cpu_relax();
-		udelay(50);
-	} while (pll1_l == 0);
-	do {
-		pll2_l = readl_relaxed(PLLn_L_VAL(2)) &
-				soc_pll[ACPU_PLL_2].l_val_mask;
-		cpu_relax();
-		udelay(50);
-	} while (pll2_l == 0);
-
-	pr_info("L val: PLL0: %d, PLL1: %d, PLL2: %d\n",
-			(int)pll0_l, (int)pll1_l, (int)pll2_l);
-
-	if (!cpu_is_msm7x27() && !cpu_is_msm7x25a()) {
-		do {
-			pll4_l = readl_relaxed(PLL4_L_VAL) &
-				soc_pll[ACPU_PLL_4].l_val_mask;
-			cpu_relax();
-			udelay(50);
-		} while (pll4_l == 0);
-		pr_info("L val: PLL4: %d\n", (int)pll4_l);
-	} else {
-		pll4_l = 0;
+	/* Get PLL clocks */
+	for (i = 0; i < ACPU_PLL_END; i++) {
+		if (pll_clk[i].name) {
+			pll_clk[i].clk = clk_get_sys("acpu", pll_clk[i].name);
+			if (IS_ERR(pll_clk[i].clk)) {
+				pll_mhz[i] = 0;
+				continue;
+			}
+			/* Get PLL's Rate */
+			pll_mhz[i] = clk_get_rate(pll_clk[i].clk)/MHZ;
+		}
 	}
 
-	/* Fix the tables for 7x25a variant to not conflict with 7x27 ones */
+	/*
+	 * For the pll configuration used in acpuclock table e.g.
+	 * pll0_960_pll1_245_pll2_1200" is same for 7627 and
+	 * 7625a (as pll0,pll1,pll2) having same rates, but frequency
+	 * table is different for both targets.
+	 *
+	 * Hence below for loop will not be able to select correct
+	 * table based on PLL rates as rates are same. Hence we need
+	 * to add this cpu check for selecting the correct acpuclock table.
+	 */
 	if (cpu_is_msm7x25a()) {
-		if (pll1_l == PLL_245_MHZ) {
+		if (pll_mhz[ACPU_PLL_1] == 245) {
 			acpu_freq_tbl =
 				pll0_960_pll1_245_pll2_1200_25a;
-		} else if (pll1_l == PLL_737_MHZ) {
+		} else if (pll_mhz[ACPU_PLL_1] == 737) {
 			acpu_freq_tbl =
 				pll0_960_pll1_737_pll2_1200_25a;
 		}
 	} else {
 		/* Select the right table to use. */
-		for (lst = acpu_freq_tbl_list; lst->tbl != 0; lst++) {
-			if (lst->pll0_l == pll0_l && lst->pll1_l == pll1_l
-					&& lst->pll2_l == pll2_l
-					&& lst->pll4_l == pll4_l) {
-				acpu_freq_tbl = lst->tbl;
+		for (t = acpu_freq_tbl_list; t->tbl != 0; t++) {
+			if (t->pll0_rate == pll_mhz[ACPU_PLL_0]
+				&& t->pll1_rate == pll_mhz[ACPU_PLL_1]
+				&& t->pll2_rate == pll_mhz[ACPU_PLL_2]
+				&& t->pll4_rate == pll_mhz[ACPU_PLL_4]) {
+				acpu_freq_tbl = t->tbl;
 				break;
 			}
 		}
@@ -945,33 +846,6 @@
 	}
 }
 
-static void shared_pll_control_init(void)
-{
-#define PLL_REMOTE_SPINLOCK_ID "S:7"
-	unsigned smem_size;
-
-	remote_spin_lock_init(&pll_lock, PLL_REMOTE_SPINLOCK_ID);
-	pll_control = smem_get_entry(SMEM_CLKREGIM_SOURCES, &smem_size);
-
-	if (!pll_control) {
-		pr_err("Can't find shared PLL control data structure!\n");
-		BUG();
-	/* There might be more PLLs than what the application processor knows
-	 * about. But the index used for each PLL is guaranteed to remain the
-	 * same. */
-	} else if (smem_size < sizeof(struct shared_pll_control)) {
-			pr_err("Shared PLL control data"
-					"structure too small!\n");
-			BUG();
-	} else if (pll_control->version != 0xCCEE0001) {
-			pr_err("Shared PLL control version mismatch!\n");
-			BUG();
-	} else {
-		pr_info("Shared PLL control available.\n");
-		return;
-	}
-
-}
 
 static struct acpuclk_data acpuclk_7627_data = {
 	.set_rate = acpuclk_7627_set_rate,
@@ -988,9 +862,8 @@
 	BUG_ON(IS_ERR(drv_state.ebi1_clk));
 
 	mutex_init(&drv_state.lock);
-	shared_pll_control_init();
 	drv_state.max_speed_delta_khz = soc_data->max_speed_delta_khz;
-	acpu_freq_tbl_fixup();
+	select_freq_plan();
 	acpuclk_7627_data.wait_for_irq_khz = find_wait_for_irq_khz();
 	precompute_stepping();
 	acpuclk_hw_init();
diff --git a/arch/arm/mach-msm/clock-pcom-lookup.c b/arch/arm/mach-msm/clock-pcom-lookup.c
index 200cbfe..c20b7e4 100644
--- a/arch/arm/mach-msm/clock-pcom-lookup.c
+++ b/arch/arm/mach-msm/clock-pcom-lookup.c
@@ -11,9 +11,16 @@
  */
 
 #include "clock.h"
+#include "clock-pll.h"
 #include "clock-pcom.h"
 #include "clock-voter.h"
 
+#include <mach/msm_iomap.h>
+#include <mach/socinfo.h>
+
+#define PLLn_MODE(n)	(MSM_CLK_CTL_BASE + 0x300 + 28 * (n))
+#define PLL4_MODE	(MSM_CLK_CTL_BASE + 0x374)
+
 static DEFINE_CLK_PCOM(adm_clk,		ADM_CLK,	CLKFLAG_SKIP_AUTO_OFF);
 static DEFINE_CLK_PCOM(adsp_clk,	ADSP_CLK,	CLKFLAG_SKIP_AUTO_OFF);
 static DEFINE_CLK_PCOM(ahb_m_clk,	AHB_M_CLK,	CLKFLAG_SKIP_AUTO_OFF);
@@ -28,6 +35,46 @@
 static DEFINE_CLK_PCOM(csi1_p_clk,	CSI1_P_CLK,	CLKFLAG_SKIP_AUTO_OFF);
 static DEFINE_CLK_PCOM(csi1_vfe_clk,	CSI1_VFE_CLK,	CLKFLAG_SKIP_AUTO_OFF);
 
+static struct pll_shared_clk pll0_clk = {
+	.id = PLL_0,
+	.mode_reg = PLLn_MODE(0),
+	.c = {
+		.ops = &clk_pll_ops,
+		.dbg_name = "pll0_clk",
+		CLK_INIT(pll0_clk.c),
+	},
+};
+
+static struct pll_shared_clk pll1_clk = {
+	.id = PLL_1,
+	.mode_reg = PLLn_MODE(1),
+	.c = {
+		.ops = &clk_pll_ops,
+		.dbg_name = "pll1_clk",
+		CLK_INIT(pll1_clk.c),
+	},
+};
+
+static struct pll_shared_clk pll2_clk = {
+	.id = PLL_2,
+	.mode_reg = PLLn_MODE(2),
+	.c = {
+		.ops = &clk_pll_ops,
+		.dbg_name = "pll2_clk",
+		CLK_INIT(pll2_clk.c),
+	},
+};
+
+static struct pll_shared_clk pll4_clk = {
+	.id = PLL_4,
+	.mode_reg = PLL4_MODE,
+	.c = {
+		.ops = &clk_pll_ops,
+		.dbg_name = "pll4_clk",
+		CLK_INIT(pll4_clk.c),
+	},
+};
+
 static struct pcom_clk dsi_byte_clk = {
 	.id = P_DSI_BYTE_CLK,
 	.c = {
@@ -251,14 +298,20 @@
 	CLK_LOOKUP("core_clk",		ebi_usb_clk.c,	"msm_otg"),
 	CLK_LOOKUP("ebi1_vfe_clk",	ebi_vfe_clk.c,	NULL),
 	CLK_LOOKUP("mem_clk",		ebi_adm_clk.c,	"msm_dmov"),
+
+	CLK_LOOKUP("pll0_clk",		pll0_clk.c,	"acpu"),
+	CLK_LOOKUP("pll1_clk",		pll1_clk.c,	"acpu"),
+	CLK_LOOKUP("pll2_clk",		pll2_clk.c,	"acpu"),
 };
 
 struct clock_init_data msm7x27_clock_init_data __initdata = {
 	.table = msm_clocks_7x27,
 	.size = ARRAY_SIZE(msm_clocks_7x27),
+	.init = msm_shared_pll_control_init,
 };
 
-static struct clk_lookup msm_clocks_7x27a[] = {
+/* Clock table for common clocks between 7627a and 7625a */
+static struct clk_lookup msm_cmn_clk_7625a_7627a[] __initdata = {
 	CLK_LOOKUP("core_clk",		adm_clk.c,	"msm_dmov"),
 	CLK_LOOKUP("adsp_clk",		adsp_clk.c,	NULL),
 	CLK_LOOKUP("ahb_m_clk",		ahb_m_clk.c,	NULL),
@@ -340,11 +393,41 @@
 	CLK_LOOKUP("ebi1_mddi_clk",	ebi_mddi_clk.c,	NULL),
 	CLK_LOOKUP("ebi1_vfe_clk",	ebi_vfe_clk.c,	NULL),
 	CLK_LOOKUP("mem_clk",		ebi_adm_clk.c,	"msm_dmov"),
+
+	CLK_LOOKUP("pll0_clk",		pll0_clk.c,	"acpu"),
+	CLK_LOOKUP("pll1_clk",		pll1_clk.c,	"acpu"),
+	CLK_LOOKUP("pll2_clk",		pll2_clk.c,	"acpu"),
+
 };
 
+/* PLL 4 clock is available for 7627a target. */
+static struct clk_lookup msm_clk_7627a[] __initdata = {
+	CLK_LOOKUP("pll4_clk",		pll4_clk.c,	"acpu"),
+};
+
+static struct clk_lookup msm_clk_7627a_7625a[ARRAY_SIZE(msm_cmn_clk_7625a_7627a)
+					+ ARRAY_SIZE(msm_clk_7627a)];
+
+static void __init msm7627a_clock_init(void)
+{
+	int size = ARRAY_SIZE(msm_cmn_clk_7625a_7627a);
+
+	/* Intialize shared PLL control structure */
+	msm_shared_pll_control_init();
+
+	memcpy(&msm_clk_7627a_7625a, &msm_cmn_clk_7625a_7627a,
+					sizeof(msm_cmn_clk_7625a_7627a));
+	if (!cpu_is_msm7x25a()) {
+		memcpy(&msm_clk_7627a_7625a[size],
+				&msm_clk_7627a, sizeof(msm_clk_7627a));
+		size += ARRAY_SIZE(msm_clk_7627a);
+	}
+	msm7x27a_clock_init_data.size = size;
+}
+
 struct clock_init_data msm7x27a_clock_init_data __initdata = {
-	.table = msm_clocks_7x27a,
-	.size = ARRAY_SIZE(msm_clocks_7x27a),
+	.table = msm_clk_7627a_7625a,
+	.init = msm7627a_clock_init,
 };
 
 static struct clk_lookup msm_clocks_8x50[] = {
diff --git a/arch/arm/mach-msm/clock-pll.c b/arch/arm/mach-msm/clock-pll.c
new file mode 100644
index 0000000..f6b2b45
--- /dev/null
+++ b/arch/arm/mach-msm/clock-pll.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/remote_spinlock.h>
+
+#include <mach/socinfo.h>
+#include <mach/msm_iomap.h>
+
+#include "clock.h"
+#include "clock-pll.h"
+#include "smd_private.h"
+
+struct pll_rate {
+	unsigned int lvalue;
+	unsigned long rate;
+};
+
+static struct pll_rate pll_l_rate[] = {
+	{10, 196000000},
+	{12, 245760000},
+	{30, 589820000},
+	{38, 737280000},
+	{41, 800000000},
+	{50, 960000000},
+	{52, 1008000000},
+	{62, 1200000000},
+	{0, 0},
+};
+
+#define PLL_BASE	7
+
+struct shared_pll_control {
+	uint32_t	version;
+	struct {
+		/*
+		 * Denotes if the PLL is ON. Technically, this can be read
+		 * directly from the PLL registers, but this feild is here,
+		 * so let's use it.
+		 */
+		uint32_t	on;
+		/*
+		 * One bit for each processor core. The application processor
+		 * is allocated bit position 1. All other bits should be
+		 * considered as votes from other processors.
+		 */
+		uint32_t	votes;
+	} pll[PLL_BASE + PLL_END];
+};
+
+static remote_spinlock_t pll_lock;
+static struct shared_pll_control *pll_control;
+
+void __init msm_shared_pll_control_init(void)
+{
+#define PLL_REMOTE_SPINLOCK_ID "S:7"
+	unsigned smem_size;
+
+	remote_spin_lock_init(&pll_lock, PLL_REMOTE_SPINLOCK_ID);
+
+	pll_control = smem_get_entry(SMEM_CLKREGIM_SOURCES, &smem_size);
+	if (!pll_control) {
+		pr_err("Can't find shared PLL control data structure!\n");
+		BUG();
+	/*
+	 * There might be more PLLs than what the application processor knows
+	 * about. But the index used for each PLL is guaranteed to remain the
+	 * same.
+	 */
+	} else if (smem_size < sizeof(struct shared_pll_control)) {
+			pr_err("Shared PLL control data"
+					 "structure too small!\n");
+			BUG();
+	} else if (pll_control->version != 0xCCEE0001) {
+			pr_err("Shared PLL control version mismatch!\n");
+			BUG();
+	} else {
+		pr_info("Shared PLL control available.\n");
+		return;
+	}
+
+}
+
+static void pll_enable(void __iomem *addr, unsigned on)
+{
+	if (on) {
+		writel_relaxed(2, addr);
+		mb();
+		udelay(5);
+		writel_relaxed(6, addr);
+		mb();
+		udelay(50);
+		writel_relaxed(7, addr);
+	} else {
+		writel_relaxed(0, addr);
+	}
+}
+
+static int pll_clk_enable(struct clk *clk)
+{
+	struct pll_shared_clk *pll = to_pll_shared_clk(clk);
+	unsigned int pll_id = pll->id;
+
+	remote_spin_lock(&pll_lock);
+
+	pll_control->pll[PLL_BASE + pll_id].votes |= BIT(1);
+	if (!pll_control->pll[PLL_BASE + pll_id].on) {
+		pll_enable(pll->mode_reg, 1);
+		pll_control->pll[PLL_BASE + pll_id].on = 1;
+	}
+
+	remote_spin_unlock(&pll_lock);
+	return 0;
+}
+
+static void pll_clk_disable(struct clk *clk)
+{
+	struct pll_shared_clk *pll = to_pll_shared_clk(clk);
+	unsigned int pll_id = pll->id;
+
+	remote_spin_lock(&pll_lock);
+
+	pll_control->pll[PLL_BASE + pll_id].votes &= ~BIT(1);
+	if (pll_control->pll[PLL_BASE + pll_id].on
+	    && !pll_control->pll[PLL_BASE + pll_id].votes) {
+		pll_enable(pll->mode_reg, 0);
+		pll_control->pll[PLL_BASE + pll_id].on = 0;
+	}
+
+	remote_spin_unlock(&pll_lock);
+}
+
+static int pll_clk_is_enabled(struct clk *clk)
+{
+	struct pll_shared_clk *pll = to_pll_shared_clk(clk);
+
+	return readl_relaxed(pll->mode_reg) & BIT(0);
+}
+
+static bool pll_clk_is_local(struct clk *clk)
+{
+	return true;
+}
+
+static int pll_clk_handoff(struct clk *clk)
+{
+	struct pll_shared_clk *pll = to_pll_shared_clk(clk);
+	unsigned int pll_lval;
+	struct pll_rate *l;
+
+	/*
+	 * Wait for the PLLs to be initialized and then read their frequency.
+	 */
+	do {
+		pll_lval = readl_relaxed(pll->mode_reg + 4) & 0x3ff;
+		cpu_relax();
+		udelay(50);
+	} while (pll_lval == 0);
+
+	/* Convert PLL L values to PLL Output rate */
+	for (l = pll_l_rate; l->rate != 0; l++) {
+		if (l->lvalue == pll_lval) {
+			clk->rate = l->rate;
+			break;
+		}
+	}
+
+	if (!clk->rate) {
+		pr_crit("Unknown PLL's L value!\n");
+		BUG();
+	}
+
+	return 0;
+}
+
+struct clk_ops clk_pll_ops = {
+	.enable = pll_clk_enable,
+	.disable = pll_clk_disable,
+	.handoff = pll_clk_handoff,
+	.is_local = pll_clk_is_local,
+	.is_enabled = pll_clk_is_enabled,
+};
diff --git a/arch/arm/mach-msm/clock-pll.h b/arch/arm/mach-msm/clock-pll.h
new file mode 100644
index 0000000..ae0ca17
--- /dev/null
+++ b/arch/arm/mach-msm/clock-pll.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+/**
+ * enum - For PLL IDs
+ */
+enum {
+	PLL_TCXO	= -1,
+	PLL_0	= 0,
+	PLL_1,
+	PLL_2,
+	PLL_3,
+	PLL_4,
+	PLL_END,
+};
+
+/**
+ * struct pll_shared_clk -  PLL shared with other processors without
+ * any HW voting
+ * @id: PLL ID
+ * @mode_reg: enable register
+ * @parent: clock source
+ * @c: clk
+ */
+struct pll_shared_clk {
+	unsigned int id;
+	void __iomem *const mode_reg;
+	struct clk c;
+};
+
+extern struct clk_ops clk_pll_ops;
+
+static inline struct pll_shared_clk *to_pll_shared_clk(struct clk *clk)
+{
+	return container_of(clk, struct pll_shared_clk, c);
+}
+
+/**
+ * msm_shared_pll_control_init() - Initialize shared pll control structure
+ */
+void msm_shared_pll_control_init(void);